Compare commits

..
2 Commits
644 changed files with 8168 additions and 46576 deletions
+4 -9
View File
@@ -36,8 +36,8 @@
@import "CPCibLoading.j" @import "CPCibLoading.j"
@import "CPCibOutletConnector.j" @import "CPCibOutletConnector.j"
@import "CPClipView.j" @import "CPClipView.j"
@import "CPCollectionView.j"
@import "CPCollectionViewItem.j" @import "CPCollectionViewItem.j"
@import "CPCollectionView.j"
@import "CPColor.j" @import "CPColor.j"
@import "CPColorPanel.j" @import "CPColorPanel.j"
@import "CPColorWell.j" @import "CPColorWell.j"
@@ -53,10 +53,8 @@
@import "CPFont.j" @import "CPFont.j"
@import "CPFontManager.j" @import "CPFontManager.j"
@import "CPGeometry.j" @import "CPGeometry.j"
@import "CPGraphics.j"
@import "CPImage.j" @import "CPImage.j"
@import "CPImageView.j" @import "CPImageView.j"
@import "CPKeyBinding.j"
@import "CPMenu.j" @import "CPMenu.j"
@import "CPMenuItem.j" @import "CPMenuItem.j"
@import "CPOpenPanel.j" @import "CPOpenPanel.j"
@@ -67,22 +65,20 @@
@import "CPProgressIndicator.j" @import "CPProgressIndicator.j"
@import "CPRadio.j" @import "CPRadio.j"
@import "CPResponder.j" @import "CPResponder.j"
@import "CPScroller.j"
@import "CPScrollView.j"
@import "CPSearchField.j" @import "CPSearchField.j"
@import "CPScrollView.j"
@import "CPScroller.j"
@import "CPSecureTextField.j" @import "CPSecureTextField.j"
@import "CPSegmentedControl.j" @import "CPSegmentedControl.j"
@import "CPShadow.j" @import "CPShadow.j"
@import "CPSlider.j" @import "CPSlider.j"
@import "CPSplitView.j" @import "CPSplitView.j"
@import "CPTabView.j"
@import "CPTableColumn.j" @import "CPTableColumn.j"
@import "CPTableView.j" @import "CPTableView.j"
@import "CPTabView.j"
@import "CPText.j"
@import "CPTextField.j" @import "CPTextField.j"
@import "CPToolbar.j" @import "CPToolbar.j"
@import "CPToolbarItem.j" @import "CPToolbarItem.j"
@import "CPTokenField.j"
@import "CPTreeNode.j" @import "CPTreeNode.j"
@import "CPView.j" @import "CPView.j"
@import "CPViewAnimation.j" @import "CPViewAnimation.j"
@@ -90,4 +86,3 @@
@import "CPWebView.j" @import "CPWebView.j"
@import "CPWindow.j" @import "CPWindow.j"
@import "CPWindowController.j" @import "CPWindowController.j"
@import "CPArrayController.j"
+11 -46
View File
@@ -26,16 +26,11 @@
@import <Foundation/CPIndexSet.j> @import <Foundation/CPIndexSet.j>
@import <Foundation/CPString.j> @import <Foundation/CPString.j>
@import "CPView.j" @import <AppKit/CPView.j>
@import "CPButton.j"
#import "CoreGraphics/CGGeometry.h"
/*!
@ingroup appkit
@class CPAccordionViewItem
<p>A CPAccordionViewItem represents a single section of a CPAccordionView.</p>
*/
@implementation CPAccordionViewItem : CPObject @implementation CPAccordionViewItem : CPObject
{ {
CPString _identifier @accessors(property=identifier); CPString _identifier @accessors(property=identifier);
@@ -48,10 +43,6 @@
return [self initWithIdentifier:@""]; return [self initWithIdentifier:@""];
} }
/*!
Initializes a new CPAccordionViewItem with the specified identifier. This identifier may
then be used in subsequent methods to provide abstract introspection of the CPAccordionView.
*/
- (id)initWithIdentifier:(CPString)anIdentifier - (id)initWithIdentifier:(CPString)anIdentifier
{ {
self = [super init]; self = [super init];
@@ -64,25 +55,6 @@
@end @end
/*!
@ingroup appkit
@class CPAccordionView
<p>CPAccordionView provides a container for CPAccordionViewItem objects and manages layout state
for all sublayout items.</p>
<strong>Example</strong><br />
<pre>
var myAccordionView = [[CPAccordionView alloc] initWithFrame:CGRectMakeZero()];
var firstItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"firstSection"]];
[firstItem setView:[[CPView alloc] initWithFrame:CGRectMakeZero()]];
var secondItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"secondSection"]];
[secondItem setView:[[CPView alloc] initWithFrame:CGRectMakeZero()]];
[myAccordionView addItem:firstItem];
[myAccordionView addItem:secondItem];
[myAccordionView setAutoresizingMask: CPViewWidthSizable | CPViewHeightSizable];
</pre>
*/
@implementation CPAccordionView : CPView @implementation CPAccordionView : CPView
{ {
CPInteger _dirtyItemIndex; CPInteger _dirtyItemIndex;
@@ -92,10 +64,7 @@ var secondItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"secondSection
CPMutableArray _itemViews; CPMutableArray _itemViews;
CPIndexSet _expandedItemIndexes; CPIndexSet _expandedItemIndexes;
} }
/*!
Initializes the receiver for usage with the specified bounding rectangle
@return the initialized view
*/
- (id)initWithFrame:(CGRect)aFrame - (id)initWithFrame:(CGRect)aFrame
{ {
self = [super initWithFrame:aFrame]; self = [super initWithFrame:aFrame];
@@ -126,11 +95,7 @@ var secondItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"secondSection
{ {
return _items; return _items;
} }
/*!
Append a CPAccordionViewItem to the receiver. Note that the CPAccordionViewItem must contain
a valid CPView derived component or a TypeError will be generated when the contents of the
ViewItem are disclosed.
*/
- (void)addItem:(CPAccordionViewItem)anItem - (void)addItem:(CPAccordionViewItem)anItem
{ {
[self insertItem:anItem atIndex:_items.length]; [self insertItem:anItem atIndex:_items.length];
@@ -213,7 +178,7 @@ var secondItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"secondSection
if ([itemView isCollapsed]) if ([itemView isCollapsed])
[self expandItemAtIndex:anIndex]; [self expandItemAtIndex:anIndex];
else else
[self collapseItemAtIndex:anIndex]; [self collapseItemAtIndex:anIndex];
} }
@@ -237,12 +202,12 @@ var secondItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"secondSection
var itemView = _itemViews[anIndex]; var itemView = _itemViews[anIndex];
if (!itemView) if (!itemView)
return; return;
if (!isEnabled) if (!isEnabled)
[self collapseItemAtIndex:anIndex]; [self collapseItemAtIndex:anIndex];
else else
[self expandItemAtIndex:anIndex]; [self expandItemAtIndex:anIndex];
[itemView setEnabled:isEnabled]; [itemView setEnabled:isEnabled];
} }
@@ -270,7 +235,7 @@ var secondItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"secondSection
{ {
if (_items.length <= 0) if (_items.length <= 0)
return [self setFrameSize:_CGSizeMake(_CGRectGetWidth([self frame]), 0.0)]; return [self setFrameSize:_CGSizeMake(_CGRectGetWidth([self frame]), 0.0)];
if (_dirtyItemIndex === CPNotFound) if (_dirtyItemIndex === CPNotFound)
return; return;
@@ -391,7 +356,7 @@ var secondItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"secondSection
[_contentView setFrameSize:_CGSizeMake(aWidth, contentHeight)]; [_contentView setFrameSize:_CGSizeMake(aWidth, contentHeight)];
[self setFrame:_CGRectMake(0.0, aY, aWidth, contentHeight + headerHeight)]; [self setFrame:_CGRectMake(0.0, aY, aWidth, contentHeight + headerHeight)];
} }
} }
- (void)resizeSubviewsWithOldSize:(CGSize)aSize - (void)resizeSubviewsWithOldSize:(CGSize)aSize
@@ -408,7 +373,7 @@ var secondItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"secondSection
/* /*
else if (aKeyPath === "itemHeaderPrototype") else if (aKeyPath === "itemHeaderPrototype")
{ {
} }
*/ */
} }
+102 -256
View File
@@ -26,34 +26,39 @@
@import <Foundation/CPObject.j> @import <Foundation/CPObject.j>
@import <Foundation/CPString.j> @import <Foundation/CPString.j>
@import "CPApplication.j" @import <AppKit/CPApplication.j>
@import "CPButton.j" @import <AppKit/CPButton.j>
@import "CPColor.j" @import <AppKit/CPColor.j>
@import "CPFont.j" @import <AppKit/CPFont.j>
@import "CPImage.j" @import <AppKit/CPImage.j>
@import "CPImageView.j" @import <AppKit/CPImageView.j>
@import "CPPanel.j" @import <AppKit/CPPanel.j>
@import "CPTextField.j" @import <AppKit/CPTextField.j>
/* /*
@global @global
@group CPAlertStyle @group CPAlertStyle
*/ */
CPWarningAlertStyle = 0; CPWarningAlertStyle = 0;
/* /*
@global @global
@group CPAlertStyle @group CPAlertStyle
*/ */
CPInformationalAlertStyle = 1; CPInformationalAlertStyle = 1;
/* /*
@global @global
@group CPAlertStyle @group CPAlertStyle
*/ */
CPCriticalAlertStyle = 2; CPCriticalAlertStyle = 2;
var CPAlertWarningImage,
CPAlertInformationImage,
CPAlertErrorImage;
/*! /*!
@ingroup appkit @ingroup appkit
CPAlert is an alert panel that can be displayed modally to present the CPAlert is an alert panel that can be displayed modally to present the
user with a message and one or more options. user with a message and one or more options.
@@ -69,51 +74,41 @@ CPCriticalAlertStyle = 2;
@delegate -(void)alertDidEnd:(CPAlert)theAlert returnCode:(int)returnCode; @delegate -(void)alertDidEnd:(CPAlert)theAlert returnCode:(int)returnCode;
Called when the user dismisses the alert by clicking one of the buttons. Called when the user dismisses the alert by clicking one of the buttons.
@param theAlert the alert panel that the user dismissed @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 representing the first button added to the alert which appears on the
right, 1 representing the next button to the left and so on) right, 1 representing the next button to the left and so on)
*/ */
@implementation CPAlert : CPView @implementation CPAlert : CPObject
{ {
CPPanel _alertPanel; CPPanel _alertPanel;
CPTextField _messageLabel; CPTextField _messageLabel;
CPTextField _informativeLabel;
CPImageView _alertImageView; CPImageView _alertImageView;
CPAlertStyle _alertStyle; CPAlertStyle _alertStyle;
CPString _windowTitle; CPString _windowTitle;
int _windowStyle; int _windowStyle;
int _buttonCount;
CPArray _buttons; CPArray _buttons;
id _delegate; id _delegate;
SEL _didEndSelector;
id _modalDelegate;
} }
+ (CPString)defaultThemeClass + (void)initialize
{ {
return @"alert"; if (self != CPAlert)
} return;
+ (id)themeAttributes var bundle = [CPBundle bundleForClass:[self class]];
{
return [CPDictionary dictionaryWithObjects:[CGSizeMake(400.0, 110.0), CGInsetMake(15, 15, 15, 50), 6, 10, CPAlertWarningImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPAlert/dialog-warning.png"]
CPJustifiedTextAlignment, [CPColor blackColor], [CPFont boldSystemFontOfSize:13.0], [CPNull null], CGSizeMakeZero(), size:CGSizeMake(32.0, 32.0)];
CPJustifiedTextAlignment, [CPColor blackColor], [CPFont systemFontOfSize:12.0], [CPNull null], CGSizeMakeZero(),
CGPointMake(15, 12), CPAlertInformationImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPAlert/dialog-information.png"]
[CPNull null], size:CGSizeMake(32.0, 32.0)];
[CPNull null],
[CPNull null] CPAlertErrorImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPAlert/dialog-error.png"]
] size:CGSizeMake(32.0, 32.0)];
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"
]];
} }
/*! /*!
@@ -123,56 +118,57 @@ CPCriticalAlertStyle = 2;
{ {
if (self = [super init]) if (self = [super init])
{ {
_buttonCount = 0;
_buttons = [CPArray array]; _buttons = [CPArray array];
_alertStyle = CPWarningAlertStyle; _alertStyle = CPWarningAlertStyle;
_alertPanel = nil;
_windowStyle = nil;
_didEndSelector = nil;
_messageLabel = [CPTextField labelWithTitle:@"Alert"]; [self setWindowStyle:nil];
_alertImageView = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
_informativeLabel = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
} }
return self; return self;
} }
/*! /*!
Sets the window appearance. If CPHUDBackgroundWindowMask is set, the default HUD theme Sets the window appearance.
will be activated.
@param styleMask - Either CPHUDBackgroundWindowMask or nil for standard. @param styleMask - Either CPHUDBackgroundWindowMask or nil for standard.
*/ */
- (void)setWindowStyle:(int)styleMask - (void)setWindowStyle:(int)styleMask
{ {
_windowStyle = 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];
[self setTheme:(_windowStyle & CPHUDBackgroundWindowMask) ? [CPTheme defaultHudTheme] : [CPTheme defaultTheme]]; [_messageLabel setTextColor:(styleMask & CPHUDBackgroundWindowMask) ? [CPColor whiteColor] : [CPColor blackColor]];
// We'll need to recreate the panel to get the new window style. var count = [_buttons count];
_alertPanel = nil; for(var i=0; i < count; i++)
}
- (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)
{ {
while (count--) var button = _buttons[i];
[contentView addSubview:_buttons[count]];
} [button setFrameSize:CGSizeMake([button frame].size.width, (styleMask == CPHUDBackgroundWindowMask) ? 20.0 : 24.0)];
else
[self addButtonWithTitle:@"OK"]; [button setTheme:(_windowStyle === CPHUDBackgroundWindowMask) ? [CPTheme themeNamed:"Aristo-HUD"] : [CPTheme defaultTheme]];
[contentView addSubview:_messageLabel]; [[_alertPanel contentView] addSubview:button];
[contentView addSubview:_alertImageView]; }
[contentView addSubview:_informativeLabel];
if (!_messageLabel)
{
var bounds = [[_alertPanel contentView] bounds];
_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];
} }
/*! /*!
@@ -235,7 +231,7 @@ CPCriticalAlertStyle = 2;
} }
/*! /*!
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. @param messageText - Message text for the alert.
*/ */
- (void)setMessageText:(CPString)messageText - (void)setMessageText:(CPString)messageText
@@ -243,157 +239,41 @@ CPCriticalAlertStyle = 2;
[_messageLabel setStringValue:messageText]; [_messageLabel setStringValue:messageText];
} }
/*! /*!
Returns the receiver's message text body. Return's the receiver's message text body.
*/ */
- (CPString)messageText - (CPString)messageText
{ {
return [_messageLabel stringValue]; 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. 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. Buttons will be added starting from the right hand side of the \c CPAlert panel.
The first button will have the index 0, the second button 1 and so on. The first button will have the index 0, the second button 1 and so on.
The first button will automatically be given a key equivalent of Return,
and any button titled "Cancel" will be given a key equivalent of Escape.
You really shouldn't need more than 3 buttons. You really shouldn't need more than 3 buttons.
*/ */
- (void)addButtonWithTitle:(CPString)title - (void)addButtonWithTitle:(CPString)title
{ {
var bounds = [[_alertPanel contentView] bounds], var bounds = [[_alertPanel contentView] bounds],
button = [[CPButton alloc] initWithFrame:CGRectMakeZero()], button = [[CPButton alloc] initWithFrame:CGRectMake(CGRectGetWidth(bounds) - ((_buttonCount + 1) * 90.0), CGRectGetHeight(bounds) - 34.0, 80.0, (_windowStyle == CPHUDBackgroundWindowMask) ? 20.0 : 24.0)];
_buttonCount = [_buttons count];
[button setTitle:title]; [button setTitle:title];
[button setTarget:self]; [button setTarget:self];
[button setTag:_buttonCount]; [button setTag:_buttonCount];
[button setAction:@selector(_dismissAlert:)]; [button setAction:@selector(_notifyDelegate:)];
[button setTheme:(_windowStyle === CPHUDBackgroundWindowMask) ? [CPTheme themeNamed:"Aristo-HUD"] : [CPTheme defaultTheme]];
[button setAutoresizingMask:CPViewMinXMargin | CPViewMinYMargin];
[[_alertPanel contentView] addSubview:button]; [[_alertPanel contentView] addSubview:button];
if (_buttonCount == 0) if (_buttonCount == 0)
[button setKeyEquivalent:CPCarriageReturnCharacter]; [_alertPanel setDefaultButton:button];
else if ([title lowercaseString] === "cancel")
[button setKeyEquivalent:CPEscapeFunctionKey];
else
[button setKeyEquivalent:nil];
[_buttons insertObject:button atIndex:0]; _buttonCount++;
} [_buttons addObject:button];
- (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;
}
} }
/*! /*!
@@ -403,68 +283,34 @@ CPCriticalAlertStyle = 2;
*/ */
- (void)runModal - (void)runModal
{ {
[self layoutPanel]; 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];
[CPApp runModalForWindow:_alertPanel]; [CPApp runModalForWindow:_alertPanel];
} }
/*!
Runs the receiver modally as an alert sheet attached to a specified window.
@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 */ /* @ignore */
- (void)_dismissAlert:(CPButton)button - (void)_notifyDelegate:(id)button
{ {
if ([_alertPanel isSheet]) [CPApp abortModal];
[CPApp endSheet:_alertPanel returnCode:[button tag]]; [_alertPanel close];
else
{
[CPApp abortModal];
[_alertPanel close];
[self _alertDidEnd:nil returnCode:[button tag] contextInfo:nil]; if (_delegate && [_delegate respondsToSelector:@selector(alertDidEnd:returnCode:)])
} [_delegate alertDidEnd:self returnCode:[button tag]];
} }
@end @end
+27 -27
View File
@@ -48,14 +48,14 @@ CPAnimationLinear = 3;
ACTUAL_FRAME_RATE = 0; ACTUAL_FRAME_RATE = 0;
/*! /*!
@ingroup appkit @ingroup appkit
@class CPAnimation @class CPAnimation
Manages an animation. Contains timing and progress information. Manages an animation. Contains timing and progress information.
@par Delegate Methods @par Delegate Methods
@delegate -(BOOL)animationShouldStart:(CPAnimation)animation; @delegate -(BOOL)animationShouldStart:(CPAnimation)animation;
Called at the beginning of \c -startAnimation. Called at the beginning of \c -startAnimation.
@param animation the animation that will start @param animation the animation that will start
@@ -81,13 +81,13 @@ ACTUAL_FRAME_RATE = 0;
{ {
CPTimeInterval _lastTime; CPTimeInterval _lastTime;
CPTimeInterval _duration; CPTimeInterval _duration;
CPAnimationCurve _animationCurve; CPAnimationCurve _animationCurve;
CAMediaTimingFunction _timingFunction; CAMediaTimingFunction _timingFunction;
float _frameRate; float _frameRate;
float _progress; float _progress;
id _delegate; id _delegate;
CPTimer _timer; CPTimer _timer;
} }
@@ -101,7 +101,7 @@ ACTUAL_FRAME_RATE = 0;
- (id)initWithDuration:(float)aDuration animationCurve:(CPAnimationCurve)anAnimationCurve - (id)initWithDuration:(float)aDuration animationCurve:(CPAnimationCurve)anAnimationCurve
{ {
self = [super init]; self = [super init];
if (self) if (self)
{ {
_progress = 0.0; _progress = 0.0;
@@ -110,14 +110,14 @@ ACTUAL_FRAME_RATE = 0;
[self setAnimationCurve:anAnimationCurve]; [self setAnimationCurve:anAnimationCurve];
} }
return self; return self;
} }
/*! /*!
Sets the animation's pace. Sets the animation's pace.
@param anAnimationCurve the animation's pace @param anAnimationCurve the animation's pace
@throws CPInvalidArgumentException if an invalid animation curve is specified @throws CPInvalidArgumentException if an invalid animation curve is specified
*/ */
- (void)setAnimationCurve:(CPAnimationCurve)anAnimationCurve - (void)setAnimationCurve:(CPAnimationCurve)anAnimationCurve
{ {
@@ -125,13 +125,13 @@ ACTUAL_FRAME_RATE = 0;
{ {
case CPAnimationEaseInOut: timingFunctionName = kCAMediaTimingFunctionEaseInEaseOut; case CPAnimationEaseInOut: timingFunctionName = kCAMediaTimingFunctionEaseInEaseOut;
break; break;
case CPAnimationEaseIn: timingFunctionName = kCAMediaTimingFunctionEaseIn; case CPAnimationEaseIn: timingFunctionName = kCAMediaTimingFunctionEaseIn;
break; break;
case CPAnimationEaseOut: timingFunctionName = kCAMediaTimingFunctionEaseOut; case CPAnimationEaseOut: timingFunctionName = kCAMediaTimingFunctionEaseOut;
break; break;
case CPAnimationLinear: timingFunctionName = kCAMediaTimingFunctionLinear; case CPAnimationLinear: timingFunctionName = kCAMediaTimingFunctionLinear;
break; break;
@@ -139,7 +139,7 @@ ACTUAL_FRAME_RATE = 0;
reason:"Invalid value provided for animation curve"]; reason:"Invalid value provided for animation curve"];
break; break;
} }
_animationCurve = anAnimationCurve; _animationCurve = anAnimationCurve;
_timingFunction = [CAMediaTimingFunction functionWithName:timingFunctionName]; _timingFunction = [CAMediaTimingFunction functionWithName:timingFunctionName];
} }
@@ -161,7 +161,7 @@ ACTUAL_FRAME_RATE = 0;
{ {
if (aDuration < 0) if (aDuration < 0)
[CPException raise:CPInvalidArgumentException reason:"aDuration can't be negative"]; [CPException raise:CPInvalidArgumentException reason:"aDuration can't be negative"];
_duration = aDuration; _duration = aDuration;
} }
@@ -182,7 +182,7 @@ ACTUAL_FRAME_RATE = 0;
{ {
if (frameRate < 0) if (frameRate < 0)
[CPException raise:CPInvalidArgumentException reason:"frameRate can't be negative"]; [CPException raise:CPInvalidArgumentException reason:"frameRate can't be negative"];
_frameRate = frameRate; _frameRate = frameRate;
} }
@@ -221,13 +221,13 @@ ACTUAL_FRAME_RATE = 0;
// If we're already animating, or our delegate stops us, animate. // If we're already animating, or our delegate stops us, animate.
if (_timer || _delegate && [_delegate respondsToSelector:@selector(animationShouldStart:)] && ![_delegate animationShouldStart:self]) if (_timer || _delegate && [_delegate respondsToSelector:@selector(animationShouldStart:)] && ![_delegate animationShouldStart:self])
return; return;
if (_progress === 1.0) if (_progress === 1.0)
_progress = 0.0; _progress = 0.0;
ACTUAL_FRAME_RATE = 0; ACTUAL_FRAME_RATE = 0;
_lastTime = new Date(); _lastTime = new Date();
_timer = [CPTimer scheduledTimerWithTimeInterval:0.0 target:self selector:@selector(animationTimerDidFire:) userInfo:nil repeats:YES]; _timer = [CPTimer scheduledTimerWithTimeInterval:0.0 target:self selector:@selector(animationTimerDidFire:) userInfo:nil repeats:YES];
} }
@@ -242,14 +242,14 @@ ACTUAL_FRAME_RATE = 0;
_lastTime = currentTime; _lastTime = currentTime;
++ACTUAL_FRAME_RATE; ++ACTUAL_FRAME_RATE;
[self setCurrentProgress:progress]; [self setCurrentProgress:progress];
if (progress === 1.0) if (progress === 1.0)
{ {
[_timer invalidate]; [_timer invalidate];
_timer = nil; _timer = nil;
if ([_delegate respondsToSelector:@selector(animationDidEnd:)]) if ([_delegate respondsToSelector:@selector(animationDidEnd:)])
[_delegate animationDidEnd:self]; [_delegate animationDidEnd:self];
} }
@@ -262,10 +262,10 @@ ACTUAL_FRAME_RATE = 0;
{ {
if (!_timer) if (!_timer)
return; return;
[_timer invalidate]; [_timer invalidate];
_timer = nil; _timer = nil;
if ([_delegate respondsToSelector:@selector(animationDidStop:)]) if ([_delegate respondsToSelector:@selector(animationDidStop:)])
[_delegate animationDidStop:self]; [_delegate animationDidStop:self];
} }
@@ -302,16 +302,16 @@ ACTUAL_FRAME_RATE = 0;
- (float)currentValue - (float)currentValue
{ {
var t = [self currentProgress]; var t = [self currentProgress];
if ([_delegate respondsToSelector:@selector(animation:valueForProgress:)]) if ([_delegate respondsToSelector:@selector(animation:valueForProgress:)])
return [_delegate animation:self valueForProgress:t]; return [_delegate animation:self valueForProgress:t];
var c1 = [], var c1 = [],
c2 = []; c2 = [];
[_timingFunction getControlPointAtIndex:1 values:c1]; [_timingFunction getControlPointAtIndex:1 values:c1];
[_timingFunction getControlPointAtIndex:2 values:c2]; [_timingFunction getControlPointAtIndex:2 values:c2];
return CubicBezierAtTime(t,c1[0],c1[1],c2[0],c2[1],_duration); return CubicBezierAtTime(t,c1[0],c1[1],c2[0],c2[1],_duration);
} }
@@ -332,7 +332,7 @@ var CubicBezierAtTime = function CubicBezierAtTime(t,p1x,p1y,p2x,p2y,duration)
function solve(x,epsilon) {return sampleCurveY(solveCurveX(x,epsilon));}; function solve(x,epsilon) {return sampleCurveY(solveCurveX(x,epsilon));};
// Given an x value, find a parametric value it came from. // Given an x value, find a parametric value it came from.
function solveCurveX(x,epsilon) {var t0,t1,t2,x2,d2,i; function solveCurveX(x,epsilon) {var t0,t1,t2,x2,d2,i;
function fabs(n) {if(n>=0) {return n;}else {return 0-n;}}; function fabs(n) {if(n>=0) {return n;}else {return 0-n;}};
// First try a few iterations of Newton's method -- normally very fast. // First try a few iterations of Newton's method -- normally very fast.
for(t2=x, i=0; i<8; i++) {x2=sampleCurveX(t2)-x; if(fabs(x2)<epsilon) {return t2;} d2=sampleCurveDerivativeX(t2); if(fabs(d2)<1e-6) {break;} t2=t2-x2/d2;} for(t2=x, i=0; i<8; i++) {x2=sampleCurveX(t2)-x; if(fabs(x2)<epsilon) {return t2;} d2=sampleCurveDerivativeX(t2); if(fabs(d2)<1e-6) {break;} t2=t2-x2/d2;}
// Fall back to the bisection method for reliability. // Fall back to the bisection method for reliability.
+146 -171
View File
@@ -31,6 +31,7 @@
@import "CPCibLoading.j" @import "CPCibLoading.j"
@import "CPPlatform.j" @import "CPPlatform.j"
#include "Platform/Platform.h"
var CPMainCibFile = @"CPMainCibFile", var CPMainCibFile = @"CPMainCibFile",
CPMainCibFileHumanFriendly = @"Main cib file base name"; CPMainCibFileHumanFriendly = @"Main cib file base name";
@@ -53,7 +54,7 @@ CPRunStoppedResponse = -1000;
CPRunAbortedResponse = -1001; CPRunAbortedResponse = -1001;
CPRunContinuesResponse = -1002; CPRunContinuesResponse = -1002;
/*! /*!
@ingroup appkit @ingroup appkit
@class CPApplication @class CPApplication
@@ -61,7 +62,7 @@ CPRunContinuesResponse = -1002;
Every GUI application has exactly one instance of CPApplication (or of a custom subclass of Every GUI application has exactly one instance of CPApplication (or of a custom subclass of
CPApplication). Your program's main() function can create that instance by calling the CPApplication). Your program's main() function can create that instance by calling the
\c CPApplicationMain function. A simple example looks like this: \c CPApplicationMain function. A simple example looks like this:
<pre> <pre>
function main(args, namedArgs) function main(args, namedArgs)
{ {
@@ -81,25 +82,25 @@ CPRunContinuesResponse = -1002;
@implementation CPApplication : CPResponder @implementation CPApplication : CPResponder
{ {
CPArray _eventListeners; CPArray _eventListeners;
CPEvent _currentEvent; CPEvent _currentEvent;
CPArray _windows; CPArray _windows;
CPWindow _keyWindow; CPWindow _keyWindow;
CPWindow _mainWindow; CPWindow _mainWindow;
CPWindow _previousKeyWindow; CPWindow _previousKeyWindow;
CPWindow _previousMainWindow; CPWindow _previousMainWindow;
CPMenu _mainMenu; CPMenu _mainMenu;
CPDocumentController _documentController; CPDocumentController _documentController;
CPModalSession _currentSession; CPModalSession _currentSession;
// //
id _delegate; id _delegate;
BOOL _finishedLaunching; BOOL _finishedLaunching;
BOOL _isActive; BOOL _isActive;
CPDictionary _namedArgs; CPDictionary _namedArgs;
CPArray _args; CPArray _args;
CPString _fullArgsString; CPString _fullArgsString;
@@ -107,8 +108,6 @@ CPRunContinuesResponse = -1002;
CPImage _applicationIconImage; CPImage _applicationIconImage;
CPPanel _aboutPanel; CPPanel _aboutPanel;
CPThemeBlend _themeBlend @accessors(property=themeBlend);
} }
/*! /*!
@@ -120,7 +119,7 @@ CPRunContinuesResponse = -1002;
{ {
if (!CPApp) if (!CPApp)
CPApp = [[CPApplication alloc] init]; CPApp = [[CPApplication alloc] init];
return CPApp; return CPApp;
} }
@@ -132,18 +131,73 @@ CPRunContinuesResponse = -1002;
- (id)init - (id)init
{ {
self = [super init]; self = [super init];
CPApp = self;
if (self) if (self)
{ {
_eventListeners = []; _eventListeners = [];
_windows = []; _windows = [];
[_windows addObject:nil]; [_windows addObject:nil];
}
// FIXME: This should be read from the cib.
_mainMenu = [[CPMenu alloc] initWithTitle:@"MainMenu"];
// FIXME: We should implement autoenabling.
[_mainMenu setAutoenablesItems:NO];
var bundle = [CPBundle bundleForClass:[CPApplication class]],
newMenuItem = [[CPMenuItem alloc] initWithTitle:@"New" action:@selector(newDocument:) keyEquivalent:@"n"];
[newMenuItem setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/New.png"] size:CGSizeMake(16.0, 16.0)]];
[newMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/NewHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
[_mainMenu addItem:newMenuItem];
var openMenuItem = [[CPMenuItem alloc] initWithTitle:@"Open" action:@selector(openDocument:) keyEquivalent:@"o"];
[openMenuItem setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/Open.png"] size:CGSizeMake(16.0, 16.0)]];
[openMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/OpenHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
[_mainMenu addItem:openMenuItem];
var saveMenu = [[CPMenu alloc] initWithTitle:@"Save"],
saveMenuItem = [[CPMenuItem alloc] initWithTitle:@"Save" action:@selector(saveDocument:) keyEquivalent:nil];
[saveMenuItem setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/Save.png"] size:CGSizeMake(16.0, 16.0)]];
[saveMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/SaveHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
[saveMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Save" action:@selector(saveDocument:) keyEquivalent:@"s"]];
[saveMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Save As" action:@selector(saveDocumentAs:) keyEquivalent:nil]];
[saveMenuItem setSubmenu:saveMenu];
[_mainMenu addItem:saveMenuItem];
var editMenuItem = [[CPMenuItem alloc] initWithTitle:@"Edit" action:nil keyEquivalent:nil],
editMenu = [[CPMenu alloc] initWithTitle:@"Edit"],
undoMenuItem = [[CPMenuItem alloc] initWithTitle:@"Undo" action:@selector(undo:) keyEquivalent:CPUndoKeyEquivalent],
redoMenuItem = [[CPMenuItem alloc] initWithTitle:@"Redo" action:@selector(redo:) keyEquivalent:CPRedoKeyEquivalent];
[undoMenuItem setKeyEquivalentModifierMask:CPUndoKeyEquivalentModifierMask];
[redoMenuItem setKeyEquivalentModifierMask:CPRedoKeyEquivalentModifierMask];
[editMenu addItem:undoMenuItem];
[editMenu addItem:redoMenuItem];
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Cut" action:@selector(cut:) keyEquivalent:@"x"]],
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Copy" action:@selector(copy:) keyEquivalent:@"c"]],
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Paste" action:@selector(paste:) keyEquivalent:@"v"]];
[editMenuItem setSubmenu:editMenu];
[editMenuItem setHidden:YES];
[_mainMenu addItem:editMenuItem];
[_mainMenu addItem:[CPMenuItem separatorItem]];
}
return self; return self;
} }
@@ -224,28 +278,28 @@ CPRunContinuesResponse = -1002;
// We also want to set the default cursor on the body, so that buttons and things don't have an iBeam // We also want to set the default cursor on the body, so that buttons and things don't have an iBeam
[[CPCursor arrowCursor] set]; [[CPCursor arrowCursor] set];
var bundle = [CPBundle mainBundle], var bundle = [CPBundle mainBundle],
types = [bundle objectForInfoDictionaryKey:@"CPBundleDocumentTypes"]; types = [bundle objectForInfoDictionaryKey:@"CPBundleDocumentTypes"];
if ([types count] > 0) if ([types count] > 0)
_documentController = [CPDocumentController sharedDocumentController]; _documentController = [CPDocumentController sharedDocumentController];
var delegateClassName = [bundle objectForInfoDictionaryKey:@"CPApplicationDelegateClass"]; var delegateClassName = [bundle objectForInfoDictionaryKey:@"CPApplicationDelegateClass"];
if (delegateClassName) if (delegateClassName)
{ {
var delegateClass = objj_getClass(delegateClassName); var delegateClass = objj_getClass(delegateClassName);
if (delegateClass) if (delegateClass)
if ([_documentController class] == delegateClass) if ([_documentController class] == delegateClass)
[self setDelegate:_documentController]; [self setDelegate:_documentController];
else else
[self setDelegate:[[delegateClass alloc] init]]; [self setDelegate:[[delegateClass alloc] init]];
} }
var defaultCenter = [CPNotificationCenter defaultCenter]; var defaultCenter = [CPNotificationCenter defaultCenter];
[defaultCenter [defaultCenter
postNotificationName:CPApplicationWillFinishLaunchingNotification postNotificationName:CPApplicationWillFinishLaunchingNotification
object:self]; object:self];
@@ -326,9 +380,7 @@ CPRunContinuesResponse = -1002;
applicationVersion = [options objectForKey:@"ApplicationVersion"] || [mainInfo objectForKey:@"CPBundleShortVersionString"], applicationVersion = [options objectForKey:@"ApplicationVersion"] || [mainInfo objectForKey:@"CPBundleShortVersionString"],
copyright = [options objectForKey:@"Copyright"] || [mainInfo objectForKey:@"CPHumanReadableCopyright"]; copyright = [options objectForKey:@"Copyright"] || [mainInfo objectForKey:@"CPHumanReadableCopyright"];
var aboutPanelPath = [[CPBundle bundleForClass:[CPWindowController class]] pathForResource:@"AboutPanel.cib"], var aboutPanelController = [[CPWindowController alloc] initWithWindowCibName:@"AboutPanel"],
aboutPanelController = [CPWindowController alloc],
aboutPanelController = [aboutPanelController initWithWindowCibPath:aboutPanelPath owner:aboutPanelController],
aboutPanel = [aboutPanelController window], aboutPanel = [aboutPanelController window],
contentView = [aboutPanel contentView], contentView = [aboutPanel contentView],
imageView = [contentView viewWithTag:1], imageView = [contentView viewWithTag:1],
@@ -336,14 +388,14 @@ CPRunContinuesResponse = -1002;
versionLabel = [contentView viewWithTag:3], versionLabel = [contentView viewWithTag:3],
copyrightLabel = [contentView viewWithTag:4], copyrightLabel = [contentView viewWithTag:4],
standardPath = [[CPBundle bundleForClass:[self class]] pathForResource:@"standardApplicationIcon.png"]; standardPath = [[CPBundle bundleForClass:[self class]] pathForResource:@"standardApplicationIcon.png"];
// FIXME move this into the CIB eventually // FIXME move this into the CIB eventually
[applicationLabel setFont:[CPFont boldSystemFontOfSize:14.0]]; [applicationLabel setFont:[CPFont boldSystemFontOfSize:14.0]];
[applicationLabel setAlignment:CPCenterTextAlignment]; [applicationLabel setAlignment:CPCenterTextAlignment];
[versionLabel setAlignment:CPCenterTextAlignment]; [versionLabel setAlignment:CPCenterTextAlignment];
[copyrightLabel setAlignment:CPCenterTextAlignment]; [copyrightLabel setAlignment:CPCenterTextAlignment];
[imageView setImage:applicationIcon || [[CPImage alloc] initWithContentsOfFile:standardPath [imageView setImage:applicationIcon || [[CPImage alloc] initWithContentsOfFile:standardPath
size:CGSizeMake(256, 256)]]; size:CGSizeMake(256, 256)]];
[applicationLabel setStringValue:applicationTitle || ""]; [applicationLabel setStringValue:applicationTitle || ""];
@@ -447,10 +499,10 @@ CPRunContinuesResponse = -1002;
return; return;
// raise exception; // raise exception;
} }
_currentSession._state = aCode; _currentSession._state = aCode;
_currentSession = _currentSession._previous; _currentSession = _currentSession._previous;
// if (aCode == CPRunAbortedResponse) // if (aCode == CPRunAbortedResponse)
[self _removeRunModalLoop]; [self _removeRunModalLoop];
} }
@@ -459,12 +511,12 @@ CPRunContinuesResponse = -1002;
- (void)_removeRunModalLoop - (void)_removeRunModalLoop
{ {
var count = _eventListeners.length; var count = _eventListeners.length;
while (count--) while (count--)
if (_eventListeners[count]._callback === _CPRunModalLoop) if (_eventListeners[count]._callback === _CPRunModalLoop)
{ {
_eventListeners.splice(count, 1); _eventListeners.splice(count, 1);
return; return;
} }
} }
@@ -502,13 +554,12 @@ CPRunContinuesResponse = -1002;
{ {
aModalSession._previous = _currentSession; aModalSession._previous = _currentSession;
_currentSession = aModalSession; _currentSession = aModalSession;
var theWindow = aModalSession._window; var theWindow = aModalSession._window;
[theWindow center]; [theWindow center];
[theWindow makeKeyWindow]; [theWindow makeKeyAndOrderFront:self];
[theWindow orderFront:self];
// [theWindow._bridge _obscureWindowsBelowModalWindow]; // [theWindow._bridge _obscureWindowsBelowModalWindow];
[CPApp setCallback:_CPRunModalLoop forNextEventMatchingMask:CPAnyEventMask untilDate:nil inMode:0 dequeue:NO]; [CPApp setCallback:_CPRunModalLoop forNextEventMatchingMask:CPAnyEventMask untilDate:nil inMode:0 dequeue:NO];
@@ -522,7 +573,7 @@ CPRunContinuesResponse = -1002;
{ {
if (!_currentSession) if (!_currentSession)
return nil; return nil;
return _currentSession._window; return _currentSession._window;
} }
@@ -567,7 +618,7 @@ CPRunContinuesResponse = -1002;
{ {
if (_eventListeners[_eventListeners.length - 1]._mask & (1 << [anEvent type])) if (_eventListeners[_eventListeners.length - 1]._mask & (1 << [anEvent type]))
_eventListeners.pop()._callback(anEvent); _eventListeners.pop()._callback(anEvent);
return; return;
} }
@@ -619,11 +670,7 @@ CPRunContinuesResponse = -1002;
*/ */
- (CPArray)orderedWindows - (CPArray)orderedWindows
{ {
#if PLATFORM(DOM)
return CPWindowObjectList(); return CPWindowObjectList();
#else
return [];
#endif
} }
- (void)hide:(id)aSender - (void)hide:(id)aSender
@@ -682,11 +729,11 @@ CPRunContinuesResponse = -1002;
if ([super tryToPerform:anAction with:anObject]) if ([super tryToPerform:anAction with:anObject])
return YES; return YES;
if ([_delegate respondsToSelector:anAction]) if([_delegate respondsToSelector:anAction])
{ {
[_delegate performSelector:anAction withObject:anObject]; [_delegate performSelector:anAction withObject:anObject];
return YES; return YES;
} }
@@ -706,9 +753,9 @@ CPRunContinuesResponse = -1002;
if (!target) if (!target)
return NO; return NO;
[target performSelector:anAction withObject:aSender]; [target performSelector:anAction withObject:aSender];
return YES; return YES;
} }
@@ -727,10 +774,10 @@ CPRunContinuesResponse = -1002;
{ {
if (!anAction) if (!anAction)
return nil; return nil;
if (aTarget) if (aTarget)
return aTarget; return aTarget;
return [self targetForAction:anAction]; return [self targetForAction:anAction];
} }
@@ -755,28 +802,28 @@ CPRunContinuesResponse = -1002;
{ {
var responder = [aWindow firstResponder], var responder = [aWindow firstResponder],
checkWindow = YES; checkWindow = YES;
while (responder) while (responder)
{ {
if ([responder respondsToSelector:anAction]) if ([responder respondsToSelector:anAction])
return responder; return responder;
if (responder == aWindow) if (responder == aWindow)
checkWindow = NO; checkWindow = NO;
responder = [responder nextResponder]; responder = [responder nextResponder];
} }
if (checkWindow && [aWindow respondsToSelector:anAction]) if (checkWindow && [aWindow respondsToSelector:anAction])
return aWindow; return aWindow;
var delegate = [aWindow delegate]; var delegate = [aWindow delegate];
if ([delegate respondsToSelector:anAction]) if ([delegate respondsToSelector:anAction])
return delegate; return delegate;
var windowController = [aWindow windowController]; var windowController = [aWindow windowController];
if ([windowController respondsToSelector:anAction]) if ([windowController respondsToSelector:anAction])
return windowController; return windowController;
@@ -805,26 +852,26 @@ CPRunContinuesResponse = -1002;
{ {
if (!anAction) if (!anAction)
return nil; return nil;
var target = [self _targetForWindow:[self keyWindow] action:anAction]; var target = [self _targetForWindow:[self keyWindow] action:anAction];
if (target) if (target)
return target; return target;
target = [self _targetForWindow:[self mainWindow] action:anAction]; target = [self _targetForWindow:[self mainWindow] action:anAction];
if (target) if (target)
return target; return target;
if ([self respondsToSelector:anAction]) if ([self respondsToSelector:anAction])
return self; return self;
if ([_delegate respondsToSelector:anAction]) if ([_delegate respondsToSelector:anAction])
return _delegate; return _delegate;
if ([_documentController respondsToSelector:anAction]) if ([_documentController respondsToSelector:anAction])
return _documentController; return _documentController;
return nil; return nil;
} }
@@ -854,31 +901,30 @@ CPRunContinuesResponse = -1002;
@param aContextInfo @param aContextInfo
*/ */
- (void)beginSheet:(CPWindow)aSheet modalForWindow:(CPWindow)aWindow modalDelegate:(id)aModalDelegate didEndSelector:(SEL)aDidEndSelector contextInfo:(id)aContextInfo - (void)beginSheet:(CPWindow)aSheet modalForWindow:(CPWindow)aWindow modalDelegate:(id)aModalDelegate didEndSelector:(SEL)aDidEndSelector contextInfo:(id)aContextInfo
{ {
var styleMask = [aSheet styleMask]; var styleMask = [aSheet styleMask];
if (!(styleMask & CPDocModalWindowMask)) if (!(styleMask & CPDocModalWindowMask))
{ {
[CPException raise:CPInternalInconsistencyException reason:@"Currently only CPDocModalWindowMask style mask is supported for attached sheets"]; [CPException raise:CPInternalInconsistencyException reason:@"Currently only CPDocModalWindowMask style mask is supported for attached sheets"];
return; return;
} }
[aWindow orderFront:self]; [aWindow orderFront:self];
[aSheet setPlatformWindow:[aWindow platformWindow]];
[aWindow _attachSheet:aSheet modalDelegate:aModalDelegate didEndSelector:aDidEndSelector contextInfo:aContextInfo]; [aWindow _attachSheet:aSheet modalDelegate:aModalDelegate didEndSelector:aDidEndSelector contextInfo:aContextInfo];
} }
- (void)endSheet:(CPWindow)sheet returnCode:(int)returnCode - (void)endSheet:(CPWindow)sheet returnCode:(int)returnCode
{ {
var count = [_windows count]; var count = [_windows count];
while (--count >= 0) while (--count >= 0)
{ {
var aWindow = [_windows objectAtIndex:count], var aWindow = [_windows objectAtIndex:count];
context = aWindow._sheetContext; var context = aWindow._sheetContext;
if (context != nil && context["sheet"] === sheet) if (context != nil && context["sheet"] === sheet)
{ {
context["returnCode"] = returnCode; context["returnCode"] = returnCode;
[aWindow _detachSheetWindow]; [aWindow _detachSheetWindow];
return; return;
} }
@@ -892,40 +938,40 @@ CPRunContinuesResponse = -1002;
- (CPArray)arguments - (CPArray)arguments
{ {
if (_fullArgsString !== window.location.hash) if(_fullArgsString !== window.location.hash)
[self _reloadArguments]; [self _reloadArguments];
return _args; return _args;
} }
- (void)setArguments:(CPArray)args - (void)setArguments:(CPArray)args
{ {
if (!args || args.length == 0) if(!args || args.length == 0)
{ {
_args = []; _args = [];
window.location.hash = @"#"; window.location.hash = @"#";
return; return;
} }
if ([args class] != CPArray) if([args class] != CPArray)
args = [CPArray arrayWithObject:args]; args = [CPArray arrayWithObject:args];
_args = args; _args = args;
var toEncode = [_args copy]; var toEncode = [_args copy];
for (var i = 0, count = toEncode.length; i < count; i++) for(var i=0, count = toEncode.length; i<count; i++)
toEncode[i] = encodeURIComponent(toEncode[i]); toEncode[i] = encodeURIComponent(toEncode[i]);
var hash = [toEncode componentsJoinedByString:@"/"]; var hash = [toEncode componentsJoinedByString:@"/"];
window.location.hash = @"#" + hash; window.location.hash = @"#" + hash;
} }
- (void)_reloadArguments - (void)_reloadArguments
{ {
_fullArgsString = window.location.hash; _fullArgsString = window.location.hash;
if (_fullArgsString.length) if (_fullArgsString.length)
{ {
var args = _fullArgsString.substring(1).split("/"); var args = _fullArgsString.substring(1).split("/");
@@ -960,18 +1006,18 @@ CPRunContinuesResponse = -1002;
- (void)_willBecomeActive - (void)_willBecomeActive
{ {
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationWillBecomeActiveNotification [[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationWillBecomeActiveNotification
object:self object:self
userInfo:nil]; userInfo:nil];
} }
- (void)_didBecomeActive - (void)_didBecomeActive
{ {
if (![self keyWindow] && _previousKeyWindow && if (![self keyWindow] && _previousKeyWindow &&
[[self windows] indexOfObjectIdenticalTo:_previousKeyWindow] !== CPNotFound) [[self windows] indexOfObjectIdenticalTo:_previousKeyWindow] !== CPNotFound)
[_previousKeyWindow makeKeyWindow]; [_previousKeyWindow makeKeyWindow];
if (![self mainWindow] && _previousMainWindow && if (![self mainWindow] && _previousMainWindow &&
[[self windows] indexOfObjectIdenticalTo:_previousMainWindow] !== CPNotFound) [[self windows] indexOfObjectIdenticalTo:_previousMainWindow] !== CPNotFound)
[_previousMainWindow makeMainWindow]; [_previousMainWindow makeMainWindow];
@@ -985,15 +1031,15 @@ CPRunContinuesResponse = -1002;
_previousKeyWindow = nil; _previousKeyWindow = nil;
_previousMainWindow = nil; _previousMainWindow = nil;
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationDidBecomeActiveNotification [[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationDidBecomeActiveNotification
object:self object:self
userInfo:nil]; userInfo:nil];
} }
- (void)_willResignActive - (void)_willResignActive
{ {
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationWillResignActiveNotification [[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationWillResignActiveNotification
object:self object:self
userInfo:nil]; userInfo:nil];
} }
@@ -1014,13 +1060,14 @@ CPRunContinuesResponse = -1002;
[_previousMainWindow resignMainWindow]; [_previousMainWindow resignMainWindow];
} }
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationDidResignActiveNotification [[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationDidResignActiveNotification
object:self object:self
userInfo:nil]; userInfo:nil];
} }
+ (CPString)defaultThemeName + (CPString)defaultThemeName
{ {
// FIXME: don't hardcode
return ([[CPBundle mainBundle] objectForInfoDictionaryKey:"CPDefaultTheme"] || @"Aristo"); return ([[CPBundle mainBundle] objectForInfoDictionaryKey:"CPDefaultTheme"] || @"Aristo");
} }
@@ -1036,14 +1083,13 @@ var _CPEventListenerMake = function(anEventMask, aCallback)
return { _mask:anEventMask, _callback:aCallback }; return { _mask:anEventMask, _callback:aCallback };
} }
// Make this a global for use in CPPlatformWindow+DOM.j. var _CPRunModalLoop = function(anEvent)
_CPRunModalLoop = function(anEvent)
{ {
[CPApp setCallback:_CPRunModalLoop forNextEventMatchingMask:CPAnyEventMask untilDate:nil inMode:0 dequeue:NO]; [CPApp setCallback:_CPRunModalLoop forNextEventMatchingMask:CPAnyEventMask untilDate:nil inMode:0 dequeue:NO];
var theWindow = [anEvent window], var theWindow = [anEvent window],
modalSession = CPApp._currentSession; modalSession = CPApp._currentSession;
if (theWindow == modalSession._window || [theWindow worksWhenModal]) if (theWindow == modalSession._window || [theWindow worksWhenModal])
[theWindow sendEvent:anEvent]; [theWindow sendEvent:anEvent];
} }
@@ -1115,15 +1161,8 @@ var _CPAppBootstrapperActions = nil;
+ (BOOL)loadDefaultTheme + (BOOL)loadDefaultTheme
{ {
var defaultThemeName = [CPApplication defaultThemeName], var blend = [[CPThemeBlend alloc] initWithContentsOfURL:[[CPBundle bundleForClass:[CPApplication class]] pathForResource:[CPApplication defaultThemeName] + ".blend"]];
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]; [blend loadWithDelegate:self];
return YES; return YES;
@@ -1131,7 +1170,6 @@ var _CPAppBootstrapperActions = nil;
+ (void)blendDidFinishLoading:(CPThemeBlend)aThemeBlend + (void)blendDidFinishLoading:(CPThemeBlend)aThemeBlend
{ {
[[CPApplication sharedApplication] setThemeBlend:aThemeBlend];
[CPTheme setDefaultTheme:[CPTheme themeNamed:[CPApplication defaultThemeName]]]; [CPTheme setDefaultTheme:[CPTheme themeNamed:[CPApplication defaultThemeName]]];
[self performActions]; [self performActions];
@@ -1150,73 +1188,10 @@ var _CPAppBootstrapperActions = nil;
return YES; return YES;
} }
else
[self loadCiblessBrowserMainMenu];
return NO; return NO;
} }
+ (void)loadCiblessBrowserMainMenu
{
var mainMenu = [[CPMenu alloc] initWithTitle:@"MainMenu"];
// FIXME: We should implement autoenabling.
[mainMenu setAutoenablesItems:NO];
var bundle = [CPBundle bundleForClass:[CPApplication class]],
newMenuItem = [[CPMenuItem alloc] initWithTitle:@"New" action:@selector(newDocument:) keyEquivalent:@"n"];
[newMenuItem setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/New.png"] size:CGSizeMake(16.0, 16.0)]];
[newMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/NewHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
[mainMenu addItem:newMenuItem];
var openMenuItem = [[CPMenuItem alloc] initWithTitle:@"Open" action:@selector(openDocument:) keyEquivalent:@"o"];
[openMenuItem setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/Open.png"] size:CGSizeMake(16.0, 16.0)]];
[openMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/OpenHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
[mainMenu addItem:openMenuItem];
var saveMenu = [[CPMenu alloc] initWithTitle:@"Save"],
saveMenuItem = [[CPMenuItem alloc] initWithTitle:@"Save" action:@selector(saveDocument:) keyEquivalent:nil];
[saveMenuItem setImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/Save.png"] size:CGSizeMake(16.0, 16.0)]];
[saveMenuItem setAlternateImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPApplication/SaveHighlighted.png"] size:CGSizeMake(16.0, 16.0)]];
[saveMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Save" action:@selector(saveDocument:) keyEquivalent:@"s"]];
[saveMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Save As" action:@selector(saveDocumentAs:) keyEquivalent:nil]];
[saveMenuItem setSubmenu:saveMenu];
[mainMenu addItem:saveMenuItem];
var editMenuItem = [[CPMenuItem alloc] initWithTitle:@"Edit" action:nil keyEquivalent:nil],
editMenu = [[CPMenu alloc] initWithTitle:@"Edit"],
undoMenuItem = [[CPMenuItem alloc] initWithTitle:@"Undo" action:@selector(undo:) keyEquivalent:CPUndoKeyEquivalent],
redoMenuItem = [[CPMenuItem alloc] initWithTitle:@"Redo" action:@selector(redo:) keyEquivalent:CPRedoKeyEquivalent];
[undoMenuItem setKeyEquivalentModifierMask:CPUndoKeyEquivalentModifierMask];
[redoMenuItem setKeyEquivalentModifierMask:CPRedoKeyEquivalentModifierMask];
[editMenu addItem:undoMenuItem];
[editMenu addItem:redoMenuItem];
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Cut" action:@selector(cut:) keyEquivalent:@"x"]],
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Copy" action:@selector(copy:) keyEquivalent:@"c"]],
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Paste" action:@selector(paste:) keyEquivalent:@"v"]];
[editMenuItem setSubmenu:editMenu];
[editMenuItem setHidden:YES];
[mainMenu addItem:editMenuItem];
[mainMenu addItem:[CPMenuItem separatorItem]];
[CPApp setMainMenu:mainMenu];
}
+ (void)cibDidFinishLoading:(CPCib)aCib + (void)cibDidFinishLoading:(CPCib)aCib
{ {
[self performActions]; [self performActions];
@@ -1229,7 +1204,7 @@ var _CPAppBootstrapperActions = nil;
+ (void)reset + (void)reset
{ {
_CPAppBootstrapperActions = nil; _CPAppBootstrapperActions = nil;
} }
@end @end
-675
View File
@@ -1,675 +0,0 @@
/*
* CPArrayController.j
* AppKit
*
* Adapted from Cocotron, by Johannes Fortmann
*
* Created by Ross Boucher.
* Copyright 2009, 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/CPIndexSet.j>
@import "CPObjectController.j"
@import "CPKeyValueBinding.j"
@implementation CPArrayController : CPObjectController
{
BOOL _avoidsEmptySelection;
BOOL _clearsFilterPredicateOnInsertion;
BOOL _filterRestrictsInsertion;
BOOL _preservesSelection;
BOOL _selectsInsertedObjects;
BOOL _alwaysUsesMultipleValuesMarker;
id _selectionIndexes;
id _sortDescriptors;
id _filterPredicate;
id _arrangedObjects;
}
+ (void)initialize
{
if (self !== [CPArrayController class])
return;
[self exposeBinding:@"contentArray"];
[self exposeBinding:@"contentSet"];
}
+ (CPSet)keyPathsForValuesAffectingContentArray
{
return [CPSet setWithObjects:"content"];
}
+ (CPSet)keyPathsForValuesAffectingArrangedObjects
{
return [CPSet setWithObjects:"content", "filterPredicate", "sortDescriptors"];
}
+ (CPSet)keyPathsForValuesAffectingSelection
{
return [CPSet setWithObjects:"selectionIndexes"];
}
+ (CPSet)keyPathsForValuesAffectingSelectionIndex
{
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
{
// Don't need to depend on arrangedObjects here because selectionIndexes already does.
return [CPSet setWithObjects:"selectionIndexes"];
}
+ (CPSet)keyPathsForValuesAffectingCanRemove
{
return [CPSet setWithObjects:"selectionIndexes"];
}
+ (CPSet)keyPathsForValuesAffectingCanSelectNext
{
return [CPSet setWithObjects:"selectionIndexes"];
}
+ (CPSet)keyPathsForValuesAffectingCanSelectPrevious
{
return [CPSet setWithObjects:"selectionIndexes"];
}
- (id)init
{
self = [super init];
if (self)
{
_selectionIndexes = [CPIndexSet indexSet];
}
return self;
}
- (void)prepareContent
{
[self _setContentArray:[[self newObject]]];
}
- (BOOL)preservesSelection
{
return _preservesSelection;
}
- (void)setPreservesSelection:(BOOL)value
{
_preservesSelection = value;
}
- (BOOL)selectsInsertedObjects
{
return _selectsInsertedObjects;
}
- (void)setSelectsInsertedObjects:(BOOL)value
{
_selectsInsertedObjects = value;
}
- (BOOL)avoidsEmptySelection
{
return _avoidsEmptySelection;
}
- (void)setAvoidsEmptySelection:(BOOL)value
{
_avoidsEmptySelection = value;
}
- (void)setContent:(id)value
{
if (value === nil)
value = [];
if (![value isKindOfClass:[CPArray class]])
value = [value];
var oldSelectedObjects = nil,
oldSelectionIndexes = nil;
if ([self preservesSelection])
oldSelectedObjects = [self selectedObjects];
else
oldSelectionIndexes = [self selectionIndexes];
/*
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]; // Causes a _rearrangeObjects.
else
[self _rearrangeObjects];
if ([self preservesSelection])
[self __setSelectedObjects:oldSelectedObjects];
else
[self __setSelectionIndexes:oldSelectionIndexes];
if (_clearsFilterPredicateOnInsertion)
[self didChangeValueForKey:@"filterPredicate"];
}
- (void)_setContentArray:(id)anArray
{
[self setContent:anArray];
}
- (void)_setContentSet:(id)aSet
{
[self setContent:aSet];
}
- (id)contentArray
{
return [self content];
}
- (id)contentSet
{
return [self content];
}
- (CPArray)arrangeObjects:(CPArray)objects
{
var filterPredicate = [self filterPredicate],
sortDescriptors = [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 [objects copy];
}
- (void)rearrangeObjects
{
[self willChangeValueForKey:@"arrangedObjects"];
[self _rearrangeObjects];
[self didChangeValueForKey:@"arrangedObjects"];
}
/*
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;
_arrangedObjects = [[_CPObservableArray alloc] initWithArray:value];
}
- (id)arrangedObjects
{
return _arrangedObjects;
}
- (CPArray)sortDescriptors
{
return _sortDescriptors;
}
- (void)setSortDescriptors:(CPArray)value
{
if (_sortDescriptors === value)
return;
_sortDescriptors = [value copy];
// Use the non-notification version since arrangedObjects already depends
// on sortDescriptors.
[self _rearrangeObjects];
}
- (CPPredicate)filterPredicate
{
return _filterPredicate;
}
- (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;
// Use the non-notification version since arrangedObjects already depends
// on filterPredicate.
[self _rearrangeObjects];
}
- (BOOL)alwaysUsesMultipleValuesMarker
{
return _alwaysUsesMultipleValuesMarker;
}
//Selection
- (unsigned)selectionIndex
{
return [_selectionIndexes firstIndex];
}
- (BOOL)setSelectionIndex:(unsigned)index
{
return [self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
}
- (CPIndexSet)selectionIndexes
{
return _selectionIndexes;
}
- (BOOL)setSelectionIndexes:(CPIndexSet)indexes
{
[self _selectionWillChange]
[self __setSelectionIndexes:indexes];
[self _selectionDidChange];
}
/*
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])
{
if (_avoidsEmptySelection && [[self arrangedObjects] count])
indexes = [CPIndexSet indexSetWithIndex:0];
}
else
{
var objectsCount = [[self arrangedObjects] count];
// Remove out of bounds indexes.
[indexes removeIndexesInRange:CPMakeRange(objectsCount, [indexes lastIndex] + 1)];
// When avoiding empty selection and the deleted selection was at the bottom, select the last item.
if (![indexes count] && _avoidsEmptySelection && objectsCount)
indexes = [CPIndexSet indexSetWithIndex:objectsCount - 1];
}
if ([_selectionIndexes isEqualToIndexSet:indexes])
return NO;
_selectionIndexes = [indexes copy];
// Push back the new selection to the model for selectionIndexes if we have one.
// There won't be an infinite loop because of the equality check above.
[[CPKeyValueBinding getBinding:@"selectionIndexes" forObject:self] reverseSetValueFor:@"selectionIndexes"];
return YES;
}
- (CPArray)selectedObjects
{
var objects = [[self arrangedObjects] objectsAtIndexes:[self selectionIndexes]];
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],
arrangedObjects = [self arrangedObjects];
for (var i = 0; i < count; i++)
{
var index = [arrangedObjects indexOfObject:[objects objectAtIndex:i]];
if (index !== CPNotFound)
[set addIndex:index];
}
[self __setSelectionIndexes:set];
return YES;
}
//Moving selection
- (BOOL)canSelectPrevious
{
return [[self selectionIndexes] firstIndex] > 0
}
- (void)selectPrevious:(id)sender
{
var index = [[self selectionIndexes] firstIndex] - 1;
if (index >= 0)
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
}
- (BOOL)canSelectNext
{
return [[self selectionIndexes] firstIndex] < [[self arrangedObjects] count] - 1;
}
- (void)selectNext:(id)sender
{
var index = [[self selectionIndexes] firstIndex] + 1;
if (index < [[self arrangedObjects] count])
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
}
//Add/Remove
- (void)addObject:(id)object
{
if (![self canAdd])
return;
if (_clearsFilterPredicateOnInsertion)
[self willChangeValueForKey:@"filterPredicate"];
[self willChangeValueForKey:@"content"];
[_contentObject addObject:object];
if (_clearsFilterPredicateOnInsertion)
[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];
else
[_selectionIndexes shiftIndexesStartingAtIndex:pos by:1];
}
else
[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
{
if (![self canRemove])
return;
[self willChangeValueForKey:@"content"];
[_contentObject removeObject:object];
if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:object])
{
// 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:@"content"];
}
- (void)add:(id)sender
{
if (![self canAdd])
return;
[self insert:sender];
}
- (void)insert:(id)sender
{
if (![self canInsert])
return;
var newObject = [self automaticallyPreparesContent] ? [self newObject] : [self _defaultNewObject];
[self addObject:newObject];
}
- (void)remove:(id)sender
{
[self removeObjects:[[self arrangedObjects] objectsAtIndexes:[self selectionIndexes]]];
}
- (void)removeObjectsAtArrangedObjectIndexes:(CPIndexSet)indexes
{
[self _removeObjects:[[self arrangedObjects] objectsAtIndexes:indexes]];
}
- (void)addObjects:(CPArray)objects
{
if (![self canAdd])
return;
var contentArray = [self contentArray],
count = [objects count];
for (var i = 0; i < count; i++)
[contentArray addObject:[objects objectAtIndex:i]];
[self setContent:contentArray];
}
- (void)removeObjects:(CPArray)objects
{
if (![self canRemove])
return;
[self _removeObjects:objects];
}
- (void)_removeObjects:(CPArray)objects
{
[self willChangeValueForKey:@"content"];
[_contentObject removeObjectsInArray:objects];
var arrangedObjects = [self arrangedObjects],
position = [arrangedObjects indexOfObject:[objects objectAtIndex:0]];
[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
{
return [self isEditable];
}
@end
@implementation CPArrayController (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:coder];
if (self)
{
_avoidsEmptySelection = [coder decodeBoolForKey:@"CPArrayControllerAvoidsEmptySelection"];
_clearsFilterPredicateOnInsertion = [coder decodeBoolForKey:@"CPClearsFilterPredicateOnInsertion"];
_filterRestrictsInsertion = [coder decodeBoolForKey:@"CPArrayControllerFilterRestrictsInsertion"];
_preservesSelection = [coder decodeBoolForKey:@"CPArrayControllerPreservesSelection"];
_selectsInsertedObjects = [coder decodeBoolForKey:@"CPArrayControllerSelectsInsertedObjects"];
_alwaysUsesMultipleValuesMarker = [coder decodeBoolForKey:@"CPArrayControllerAlwaysUsesMultipleValuesMarker"];
if ([self automaticallyPreparesContent])
[self prepareContent];
else
[self _setContentArray:[]];
}
return self;
}
- (void)awakeFromCib
{
[self _selectionWillChange];
[self _selectionDidChange];
}
@end
+10 -11
View File
@@ -4,7 +4,7 @@
* Created by Ross Boucher. * Created by Ross Boucher.
* Copyright 2009, 280 North, Inc. * Copyright 2009, 280 North, Inc.
* *
* Adapted from Kevin Wojniak, portions Copyright 2009 Kevin Wojniak. * Adapted from Kevin Wojniak, portions Copyright 2009 Kevin Wojniak.
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@@ -20,27 +20,26 @@
* License along with this library; if not, write to the Free Software * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
* Copyright 2009 280 North, Inc. * Copyright 2009 280 North, Inc.
*/ */
@import <AppKit/CPGraphicsContext.j>
@import <Foundation/CPObject.j> @import <Foundation/CPObject.j>
@import "CPGraphicsContext.j"
// Class defaults // Class defaults
var DefaultLineWidth = 1.0; var DefaultLineWidth = 1.0;
/*! /*!
@ingroup appkit @ingroup appkit
@class CPBezierPath @class CPBezierPath
A CPBezierPath allows you to create paths for drawing to the screen using a simpler API than CoreGraphics. A CPBezierPath allows you to create paths for drawing to the screen using a simpler API than CoreGraphics.
Paths can form any shape, including regular polgyons like squares and triangles; circles, arcs; or complex Paths can form any shape, including regular polgyons like squares and triangles; circles, arcs; or complex
line segments. line segments.
A path can be stroked and filled using the relevant method. The currently active fill and stroke color will A path can be stroked and filled using the relevant method. The currently active fill and stroke color will
be used, which can be set by calling setFill: and setStroke: on any CPColor object (or set: for both). be used, which can be set by calling setFill: and setStroke: on any CPColor object (or set: for both).
*/ */
@@ -65,9 +64,9 @@ var DefaultLineWidth = 1.0;
+ (CPBezierPath)bezierPathWithOvalInRect:(CGRect)rect + (CPBezierPath)bezierPathWithOvalInRect:(CGRect)rect
{ {
var path = [self bezierPath]; var path = [self bezierPath];
[path appendBezierPathWithOvalInRect:rect]; [path appendBezierPathWithOvalInRect:rect];
return path; return path;
} }
@@ -77,9 +76,9 @@ var DefaultLineWidth = 1.0;
+ (CPBezierPath)bezierPathWithRect:(CGRect)rect + (CPBezierPath)bezierPathWithRect:(CGRect)rect
{ {
var path = [self bezierPath]; var path = [self bezierPath];
[path appendBezierPathWithRect:rect]; [path appendBezierPathWithRect:rect];
return path; return path;
} }
+53 -177
View File
@@ -19,33 +19,25 @@
* License along with this library; if not, write to the Free Software * License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
@import "CPView.j" @import "CPView.j"
// CPBoxType
CPBoxPrimary = 0;
CPBoxSecondary = 1;
CPBoxSeperator = 2;
CPBoxOldStyle = 3;
CPBoxCustom = 4;
// CPBorderType // CPBorderType
CPNoBorder = 0; CPNoBorder = 0;
CPLineBorder = 1; CPLineBorder = 1;
CPBezelBorder = 2; CPBezelBorder = 2;
CPGrooveBorder = 3; CPGrooveBorder = 3;
@implementation CPBox : CPView @implementation CPBox : CPView
{ {
CPBoxType _boxType;
CPBorderType _borderType; CPBorderType _borderType;
CPColor _borderColor; CPColor _borderColor;
CPColor _fillColor; CPColor _fillColor;
float _cornerRadius; float _cornerRadius;
float _borderWidth; float _borderWidth;
CPSize _contentMargin; CPSize _contentMargin;
CPView _contentView; CPView _contentView;
} }
@@ -58,19 +50,18 @@ CPGrooveBorder = 3;
[box setFrameFromContentFrame:[aView frame]]; [box setFrameFromContentFrame:[aView frame]];
[enclosingView replaceSubview:aView with:box]; [enclosingView replaceSubview:aView with:box];
[box setContentView:aView]; [box setContentView:aView];
return box; return box;
} }
- (id)initWithFrame:(CPRect)frameRect - (id)initWithFrame:(CPRect)frameRect
{ {
self = [super initWithFrame:frameRect]; self = [super initWithFrame:frameRect];
if (self) if (self)
{ {
_borderType = CPBezelBorder;
_fillColor = [CPColor clearColor]; _fillColor = [CPColor clearColor];
_borderColor = [CPColor blackColor]; _borderColor = [CPColor blackColor];
@@ -78,9 +69,7 @@ CPGrooveBorder = 3;
_contentMargin = CGSizeMake(0.0, 0.0); _contentMargin = CGSizeMake(0.0, 0.0);
_contentView = [[CPView alloc] initWithFrame:[self bounds]]; _contentView = [[CPView alloc] initWithFrame:[self bounds]];
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
[self setAutoresizesSubviews:YES];
[self addSubview:_contentView]; [self addSubview:_contentView];
} }
@@ -99,26 +88,9 @@ CPGrooveBorder = 3;
return _borderType; return _borderType;
} }
- (void)setBorderType:(CPBorderType)aBorderType - (void)setBorderType:(CPBorderType)value
{ {
if (_borderType === aBorderType) _borderType = value;
return;
_borderType = aBorderType;
[self setNeedsDisplay:YES];
}
- (CPBoxType)boxType
{
return _boxType;
}
- (void)setBoxType:(CPBoxType)aBoxType
{
if (_boxType === aBoxType)
return;
_boxType = aBoxType;
[self setNeedsDisplay:YES]; [self setNeedsDisplay:YES];
} }
@@ -189,10 +161,9 @@ CPGrooveBorder = 3;
return; return;
[aView setFrame:CGRectInset([self bounds], _contentMargin.width + _borderWidth, _contentMargin.height + _borderWidth)]; [aView setFrame:CGRectInset([self bounds], _contentMargin.width + _borderWidth, _contentMargin.height + _borderWidth)];
[aView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
[self replaceSubview:_contentView with:aView]; [self replaceSubview:_contentView with:aView];
_contentView = aView; _contentView = aView;
} }
- (CPSize)contentViewMargins - (CPSize)contentViewMargins
@@ -202,9 +173,9 @@ CPGrooveBorder = 3;
- (void)setContentViewMargins:(CPSize)size - (void)setContentViewMargins:(CPSize)size
{ {
if (size.width < 0 || size.height < 0) if(size.width < 0 || size.height < 0)
[CPException raise:CPGenericException reason:@"Margins must be positive"]; [CPException raise:CPGenericException reason:@"Margins must be positive"];
_contentMargin = CGSizeMakeCopy(size); _contentMargin = CGSizeMakeCopy(size);
[self setNeedsDisplay:YES]; [self setNeedsDisplay:YES];
} }
@@ -218,151 +189,56 @@ CPGrooveBorder = 3;
- (void)sizeToFit - (void)sizeToFit
{ {
var contentFrame = [_contentView frame]; 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)]; contentFrame.size.height + _contentMargin.height * 2)];
[_contentView setFrameOrigin:CGPointMake(_contentMargin.width, _contentMargin.height)]; [_contentView setFrameOrigin:CGPointMake(_contentMargin.width, _contentMargin.height)];
} }
- (void)drawRect:(CPRect)rect - (void)drawRect:(CPRect)rect
{ {
if (_borderType === CPNoBorder) var bounds = [self bounds],
return; aContext = [[CPGraphicsContext currentContext] graphicsPort],
border2 = _borderWidth/2,
var bounds = [self bounds]; 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);
switch (_boxType) CGContextSetFillColor(aContext, [self fillColor]);
CGContextSetStrokeColor(aContext, [self borderColor]);
CGContextSetLineWidth(aContext, _borderWidth);
switch(_borderType)
{ {
case CPBoxSeperator: case CPLineBorder: CGContextFillRoundedRectangleInRect(aContext, fillRect, _cornerRadius, YES, YES, YES, YES);
// NSBox does not include a horitontal flag for the seperator type. We have to determine CGContextStrokeRoundedRectangleInRect(aContext, strokeRect, _cornerRadius, YES, YES, YES, YES);
// the type of seperator to draw by the width and height of the frame. break;
if (CGRectGetWidth(bounds) === 5.0)
return [self _drawVerticalSeperatorInRect:bounds];
else if (CGRectGetHeight(bounds) === 5.0)
return [self _drawHorizontalSeperatorInRect:bounds];
break; 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;
default: break;
} }
switch (_borderType)
{
case CPBezelBorder:
[self _drawBezelBorderInRect:bounds];
break;
default:
case CPLineBorder:
[self _drawLineBorderInRect:bounds];
break;
}
}
- (void)_drawHorizontalSeperatorInRect:(CGRect)aRect
{
var context = [[CPGraphicsContext currentContext] graphicsPort];
CGContextSetStrokeColor(context, [self borderColor]);
CGContextSetLineWidth(context, 1.0);
CGContextMoveToPoint(context, CGRectGetMinX(aRect), CGRectGetMinY(aRect));
CGContextAddLineToPoint(context, CGRectGetWidth(aRect), CGRectGetMinY(aRect));
CGContextStrokePath(context);
}
- (void)_drawVerticalSeperatorInRect:(CGRect)aRect
{
var context = [[CPGraphicsContext currentContext] graphicsPort];
CGContextSetStrokeColor(context, [self borderColor]);
CGContextSetLineWidth(context, 1.0);
CGContextMoveToPoint(context, CGRectGetMinX(aRect), CGRectGetMinY(aRect));
CGContextAddLineToPoint(context, CGRectGetMinX(aRect), CGRectGetHeight(aRect));
CGContextStrokePath(context);
}
- (void)_drawBezelBorderInRect:(CGRect)aRect
{
var context = [[CPGraphicsContext currentContext] graphicsPort],
sides = [CPMinYEdge, CPMaxXEdge, CPMaxYEdge, CPMinXEdge],
sideGray = 190.0 / 255.0,
grays = [142.0 / 255.0, sideGray, sideGray, sideGray],
borderWidth = _borderWidth;
while (borderWidth--)
aRect = CPDrawTiledRects(aRect, aRect, sides, grays);
CGContextSetFillColor(context, [self fillColor]);
CGContextFillRect(context, aRect);
}
- (void)_drawLineBorderInRect:(CGRect)aRect
{
var context = [[CPGraphicsContext currentContext] graphicsPort];
aRect = CGRectInset(aRect, _borderWidth / 2.0, _borderWidth / 2.0);
CGContextSetFillColor(context, [self fillColor]);
CGContextSetStrokeColor(context, [self borderColor]);
CGContextSetLineWidth(context, _borderWidth);
CGContextFillRoundedRectangleInRect(context, aRect, _cornerRadius, YES, YES, YES, YES);
CGContextStrokeRoundedRectangleInRect(context, aRect, _cornerRadius, YES, YES, YES, YES);
}
@end
var CPBoxTypeKey = @"CPBoxTypeKey",
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)
{
_boxType = [aCoder decodeIntForKey:CPBoxTypeKey];
_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:_boxType forKey:CPBoxTypeKey];
[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 @end
+45 -104
View File
@@ -20,17 +20,14 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
@import <Foundation/CPIndexSet.j>
@import "CPControl.j" @import "CPControl.j"
@import "CPImage.j" @import "CPImage.j"
@import "CPTableView.j" @import "CPTableView.j"
@import "CPTextField.j"
@import "CPScrollView.j" @import "CPScrollView.j"
/*! /*!
@ingroup appkit @ingroup appkit
@class CPBrowser @class CPBrowser
*/ */
@implementation CPBrowser : CPControl @implementation CPBrowser : CPControl
@@ -67,14 +64,14 @@
+ (CPImage)branchImage + (CPImage)branchImage
{ {
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPBrowser class]] return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[self class]]
pathForResource:"browser-leaf.png"] pathForResource:"browser-leaf.png"]
size:CGSizeMake(9,9)]; size:CGSizeMake(9,9)];
} }
+ (CPImage)highlightedBranchImage + (CPImage)highlightedBranchImage
{ {
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPBrowser class]] return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[self class]]
pathForResource:"browser-leaf-highlighted.png"] pathForResource:"browser-leaf-highlighted.png"]
size:CGSizeMake(9,9)]; size:CGSizeMake(9,9)];
} }
@@ -99,18 +96,18 @@
_prototypeView = [[CPTextField alloc] initWithFrame:CGRectMakeZero()]; _prototypeView = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
[_prototypeView setVerticalAlignment:CPCenterVerticalTextAlignment]; [_prototypeView setVerticalAlignment:CPCenterVerticalTextAlignment];
[_prototypeView setValue:[CPColor whiteColor] forThemeAttribute:"text-color" inState:CPThemeStateSelectedDataView]; [_prototypeView setValue:[CPColor whiteColor] forThemeAttribute:"text-color" inState:CPThemeStateSelected];
[_prototypeView setLineBreakMode:CPLineBreakByTruncatingTail]; [_prototypeView setLineBreakMode:CPLineBreakByTruncatingTail];
_horizontalScrollView = [[CPScrollView alloc] initWithFrame:[self bounds]]; _horizontalScrollView = [[CPScrollView alloc] initWithFrame:[self bounds]];
[_horizontalScrollView setHasVerticalScroller:NO]; [_horizontalScrollView setHasVerticalScroller:NO];
[_horizontalScrollView setAutohidesScrollers:YES]; [_horizontalScrollView setAutohidesScrollers:YES];
[_horizontalScrollView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]; [_horizontalScrollView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
_contentView = [[CPView alloc] initWithFrame:CGRectMake(0, 0, 0, CGRectGetHeight([self bounds]))]; _contentView = [[CPView alloc] initWithFrame:CGRectMake(0, 0, 0, CGRectGetHeight([self bounds]))];
[_contentView setAutoresizingMask:CPViewHeightSizable]; [_contentView setAutoresizingMask:CPViewHeightSizable];
[_horizontalScrollView setDocumentView:_contentView]; [_horizontalScrollView setDocumentView:_contentView];
[self addSubview:_horizontalScrollView]; [self addSubview:_horizontalScrollView];
@@ -132,7 +129,7 @@
} }
- (void)setDelegate:(id)anObject - (void)setDelegate:(id)anObject
{ {
_delegate = anObject; _delegate = anObject;
_delegateSupportsImages = [_delegate respondsToSelector:@selector(browser:imageValueForItem:)]; _delegateSupportsImages = [_delegate respondsToSelector:@selector(browser:imageValueForItem:)];
@@ -170,10 +167,12 @@
if (columnIndex >= _tableViews.length) if (columnIndex >= _tableViews.length)
return; return;
var oldValue = _tableViews.length - 1, var oldValue = _tableViews.length - 1;
indexPlusOne = columnIndex + 1; // unloads all later columns.
[[_tableViews.slice(indexPlusOne) valueForKey:"enclosingScrollView"] // unloads all later columns.
var indexPlusOne = columnIndex + 1;
[[_tableViews.slice(indexPlusOne) valueForKey:"enclosingScrollView"]
makeObjectsPerformSelector:@selector(removeFromSuperview)]; makeObjectsPerformSelector:@selector(removeFromSuperview)];
_tableViews = _tableViews.slice(0, indexPlusOne); _tableViews = _tableViews.slice(0, indexPlusOne);
@@ -197,10 +196,10 @@
selectionIndexes = [lastColumn selectedRowIndexes]; selectionIndexes = [lastColumn selectedRowIndexes];
if (lastIndex >= 0 && [selectionIndexes count] > 1) if (lastIndex >= 0 && [selectionIndexes count] > 1)
[CPException raise:CPInvalidArgumentException [CPException raise:CPInvalidArgumentException
reason:"Can't add column, column "+lastIndex+" has invalid selection."]; reason:"Can't add column, column "+lastIndex+" has invalid selection."];
var index = lastIndex + 1, var index = lastIndex+1,
item = index === 0 ? _rootItem : [_tableDelegates[lastIndex] childAtIndex:[selectionIndexes firstIndex]]; item = index === 0 ? _rootItem : [_tableDelegates[lastIndex] childAtIndex:[selectionIndexes firstIndex]];
if (index > 0 && item && [self isLeafItem:item]) if (index > 0 && item && [self isLeafItem:item])
@@ -214,6 +213,8 @@
[table setAllowsEmptySelection:_allowsEmptySelection]; [table setAllowsEmptySelection:_allowsEmptySelection];
[table registerForDraggedTypes:[self registeredDraggedTypes]]; [table registerForDraggedTypes:[self registeredDraggedTypes]];
[self setNextResponder:table];
[self _addTableColumnsToTableView:table forColumnIndex:index]; [self _addTableColumnsToTableView:table forColumnIndex:index];
var delegate = [[_CPBrowserTableDelegate alloc] init]; var delegate = [[_CPBrowserTableDelegate alloc] init];
@@ -232,7 +233,7 @@
[table setAction:@selector(_tableViewClicked:)]; [table setAction:@selector(_tableViewClicked:)];
[table setDoubleAction:@selector(_tableViewDoubleClicked:)]; [table setDoubleAction:@selector(_tableViewDoubleClicked:)];
[table setDraggingDestinationFeedbackStyle:CPTableViewDraggingDestinationFeedbackStyleRegular]; [table setDraggingDestinationFeedbackStyle:CPTableViewDraggingDestinationFeedbackStyleRegular];
var scrollView = [[_CPBrowserScrollView alloc] initWithFrame:CGRectMakeZero()]; var scrollView = [[_CPBrowserScrollView alloc] initWithFrame:CGRectMakeZero()];
[scrollView _setBrowser:self]; [scrollView _setBrowser:self];
[scrollView setDocumentView:table]; [scrollView setDocumentView:table];
@@ -273,10 +274,10 @@
[view setBranchImage:[[self class] branchImage]]; [view setBranchImage:[[self class] branchImage]];
[view setHighlightedBranchImage:[[self class] highlightedBranchImage]]; [view setHighlightedBranchImage:[[self class] highlightedBranchImage]];
[column setDataView:view]; [column setDataView:view];
[column setResizingMask:CPTableColumnNoResizing]; [column setResizingMask:CPTableColumnNoResizing];
[aTableView addTableColumn:column]; [aTableView addTableColumn:column];
} }
@@ -313,39 +314,6 @@
[_contentView setFrameSize:CGSizeMake(xOrigin, height)]; [_contentView setFrameSize:CGSizeMake(xOrigin, height)];
} }
- (unsigned)rowAtPoint:(CGPoint)aPoint
{
var column = [self columnAtPoint:aPoint];
if (column === -1)
return -1;
var tableView = _tableViews[column];
return [tableView rowAtPoint:[tableView convertPoint:aPoint fromView:self]];
}
- (unsigned)columnAtPoint:(CGPoint)aPoint
{
var adjustedPoint = [_contentView convertPoint:aPoint fromView:self];
for (var i = 0, count = _tableViews.length; i < count; i++)
{
var frame = [[_tableViews[i] enclosingScrollView] frame];
if (CGRectContainsPoint(frame, adjustedPoint))
return i;
}
return -1;
}
- (CGRect)rectOfRow:(unsigned)aRow inColumn:(unsigned)aColumn
{
var tableView = _tableViews[aColumn],
rect = [tableView rectOfRow:aRow];
rect.origin = [self convertPoint:rect.origin fromView:tableView];
return rect;
}
// ITEMS // ITEMS
- (id)itemAtRow:(int)row inColumn:(int)column - (id)itemAtRow:(int)row inColumn:(int)column
@@ -389,10 +357,6 @@
// CLICK EVENTS // CLICK EVENTS
- (void)trackMouse:(CPEvent)anEvent
{
}
- (void)_column:(unsigned)columnIndex clickedRow:(unsigned)rowIndex - (void)_column:(unsigned)columnIndex clickedRow:(unsigned)rowIndex
{ {
[self setLastColumn:columnIndex]; [self setLastColumn:columnIndex];
@@ -418,15 +382,6 @@
[self sendAction:_doubleAction to:_target]; [self sendAction:_doubleAction to:_target];
} }
- (void)keyDown:(CPEvent)anEvent
{
var column = [self selectedColumn];
if (column === -1)
return;
[_tableViews[column] keyDown:anEvent];
}
// SIZING // SIZING
- (float)columnContentWidthForColumnWidth:(float)aWidth - (float)columnContentWidthForColumnWidth:(float)aWidth
@@ -498,7 +453,7 @@
[_contentView scrollRectToVisible:[[[self tableViewInColumn:columnIndex] enclosingScrollView] frame]]; [_contentView scrollRectToVisible:[[[self tableViewInColumn:columnIndex] enclosingScrollView] frame]];
} }
- (void)scrollRowToVisible:(unsigned)rowIndex inColumn:(unsigned)columnIndex (void)scrollRowToVisible:(unsigned)rowIndex inColumn:(unsigned)columnIndex
{ {
[self scrollColumnToVisible:columnIndex]; [self scrollColumnToVisible:columnIndex];
[[self tableViewInColumn:columnIndex] scrollRowToVisible:rowIndex]; [[self tableViewInColumn:columnIndex] scrollRowToVisible:rowIndex];
@@ -571,9 +526,6 @@
- (CPIndexSet)selectedRowIndexesInColumn:(unsigned)column - (CPIndexSet)selectedRowIndexesInColumn:(unsigned)column
{ {
if (column < 0 || column > [self lastColumn] +1)
return [CPIndexSet indexSet];
return [[self tableViewInColumn:column] selectedRowIndexes]; return [[self tableViewInColumn:column] selectedRowIndexes];
} }
@@ -585,7 +537,7 @@
if ([_delegate respondsToSelector:@selector(browser:selectionIndexesForProposedSelection:inColumn:)]) if ([_delegate respondsToSelector:@selector(browser:selectionIndexesForProposedSelection:inColumn:)])
indexSet = [_delegate browser:self selectionIndexesForProposedSelection:indexSet inColumn:column]; indexSet = [_delegate browser:self selectionIndexesForProposedSelection:indexSet inColumn:column];
if ([_delegate respondsToSelector:@selector(browser:shouldSelectRowIndexes:inColumn:)] && if ([_delegate respondsToSelector:@selector(browser:shouldSelectRowIndexes:inColumn:)] &&
![_delegate browser:self shouldSelectRowIndexes:indexSet inColumn:column]) ![_delegate browser:self shouldSelectRowIndexes:indexSet inColumn:column])
return; return;
@@ -599,6 +551,8 @@
[[self tableViewInColumn:column] selectRowIndexes:indexSet byExtendingSelection:NO]; [[self tableViewInColumn:column] selectRowIndexes:indexSet byExtendingSelection:NO];
[self setNextResponder:[self tableViewInColumn:[self lastColumn]]];
[self scrollColumnToVisible:column]; [self scrollColumnToVisible:column];
if ([_delegate respondsToSelector:@selector(browserSelectionDidChange:)]) if ([_delegate respondsToSelector:@selector(browserSelectionDidChange:)])
@@ -650,8 +604,6 @@
@end @end
var _CPBrowserResizeControlBackgroundImage = nil;
@implementation _CPBrowserResizeControl : CPView @implementation _CPBrowserResizeControl : CPView
{ {
CGPoint _mouseDownX; CGPoint _mouseDownX;
@@ -660,26 +612,6 @@ var _CPBrowserResizeControlBackgroundImage = nil;
unsigned _width; unsigned _width;
} }
+ (CPImage)backgroundImage
{
if (!_CPBrowserResizeControlBackgroundImage)
{
var path = [[CPBundle bundleForClass:[self class]] pathForResource:"browser-resize-control.png"];
_CPBrowserResizeControlBackgroundImage = [[CPImage alloc] initWithContentsOfFile:path
size:CGSizeMake(15, 14)];
}
return _CPBrowserResizeControlBackgroundImage;
}
- (id)initWithFrame:(CGRect)aFrame
{
if (self = [super initWithFrame:aFrame])
[self setBackgroundColor:[CPColor colorWithPatternImage:[[self class] backgroundImage]]];
return self;
}
- (void)mouseDown:(CPEvent)anEvent - (void)mouseDown:(CPEvent)anEvent
{ {
_mouseDownX = [anEvent locationInWindow].x; _mouseDownX = [anEvent locationInWindow].x;
@@ -694,23 +626,34 @@ var _CPBrowserResizeControlBackgroundImage = nil;
[_browser setWidth:_width + deltaX ofColumn:_index]; [_browser setWidth:_width + deltaX ofColumn:_index];
} }
- (void)mouseUp:(CPEvent)anEvent
{
}
@end @end
var _CPBrowserResizeControlBackgroundImage = nil;
@implementation _CPBrowserScrollView : CPScrollView @implementation _CPBrowserScrollView : CPScrollView
{ {
_CPBrowserResizeControl _resizeControl; _CPBrowserResizeControl _resizeControl;
CPBrowser _browser @accessors; CPBrowser _browser @accessors;
} }
+ (CPImage)backgroundImage
{
if (!_CPBrowserResizeControlBackgroundImage)
{
var path = [[CPBundle bundleForClass:[self class]] pathForResource:"browser-resize-control.png"];
_CPBrowserResizeControlBackgroundImage = [[CPImage alloc] initWithContentsOfFile:path
size:CGSizeMake(15, 14)];
}
return _CPBrowserResizeControlBackgroundImage;
}
- (void)initWithFrame:(CGRect)aFrame - (void)initWithFrame:(CGRect)aFrame
{ {
if (self = [super initWithFrame:aFrame]) if (self = [super initWithFrame:aFrame])
{ {
_resizeControl = [[_CPBrowserResizeControl alloc] initWithFrame:CGRectMakeZero()]; _resizeControl = [[_CPBrowserResizeControl alloc] initWithFrame:CGRectMakeZero()];
[_resizeControl setBackgroundColor:[CPColor colorWithPatternImage:[[self class] backgroundImage]]];
[self addSubview:_resizeControl]; [self addSubview:_resizeControl];
} }
@@ -797,7 +740,7 @@ var _CPBrowserResizeControlBackgroundImage = nil;
} }
- (void)moveLeft:(id)sender - (void)moveLeft:(id)sender
{ {
var previousColumn = [_browser selectedColumn] - 1, var previousColumn = [_browser selectedColumn] - 1,
selectedRow = [_browser selectedRowInColumn:previousColumn]; selectedRow = [_browser selectedRowInColumn:previousColumn];
@@ -805,14 +748,12 @@ var _CPBrowserResizeControlBackgroundImage = nil;
} }
- (void)moveRight:(id)sender - (void)moveRight:(id)sender
{ {
[_browser selectRow:0 inColumn:[_browser selectedColumn] + 1]; [_browser selectRow:0 inColumn:[_browser selectedColumn] + 1];
} }
@end @end
@import <Foundation/CPObject.j>
@implementation _CPBrowserTableDelegate : CPObject @implementation _CPBrowserTableDelegate : CPObject
{ {
CPBrowser _browser @accessors; CPBrowser _browser @accessors;
@@ -863,7 +804,7 @@ var _CPBrowserResizeControlBackgroundImage = nil;
- (CPDragOperation)tableView:(CPTableView)aTableView validateDrop:(id)info proposedRow:(int)row proposedDropOperation:(CPTableViewDropOperation)operation - (CPDragOperation)tableView:(CPTableView)aTableView validateDrop:(id)info proposedRow:(int)row proposedDropOperation:(CPTableViewDropOperation)operation
{ {
if ([_delegate respondsToSelector:@selector(browser:validateDrop:proposedRow:column:dropOperation:)]) if ([_delegate respondsToSelector:@selector(browser:validateDrop:proposedRow:column:dropOperation:)])
return [_delegate browser:_browser validateDrop:info proposedRow:row column:_index dropOperation:operation]; [_delegate browser:_browser validateDrop:info proposedRow:row column:_index dropOperation:operation];
else else
return CPDragOperationNone; return CPDragOperationNone;
} }
@@ -924,9 +865,9 @@ var _CPBrowserResizeControlBackgroundImage = nil;
{ {
var imageView = [self layoutEphemeralSubviewNamed:@"image-view" var imageView = [self layoutEphemeralSubviewNamed:@"image-view"
positioned:CPWindowAbove positioned:CPWindowAbove
relativeToEphemeralSubviewNamed:nil], relativeToEphemeralSubviewNamed:nil];
isHighlighted = [self themeState] & CPThemeStateSelectedDataView;
var isHighlighted = [self themeState] & CPThemeStateSelected;
[imageView setImage: _isLeaf ? (isHighlighted ? _highlightedBranchImage : _branchImage) : nil]; [imageView setImage: _isLeaf ? (isHighlighted ? _highlightedBranchImage : _branchImage) : nil];
[imageView setImageScaling:CPScaleNone]; [imageView setImageScaling:CPScaleNone];
} }
+69 -174
View File
@@ -26,6 +26,8 @@
@import "CPControl.j" @import "CPControl.j"
@import "CPStringDrawing.j" @import "CPStringDrawing.j"
#include "CoreGraphics/CGGeometry.h"
/* @group CPBezelStyle */ /* @group CPBezelStyle */
@@ -72,10 +74,7 @@ CPChangeBackgroundCellMask = CPBackgroundButtonMask;
CPButtonStateMixed = CPThemeState("mixed"); CPButtonStateMixed = CPThemeState("mixed");
CPButtonDefaultHeight = 24.0; /*!
CPButtonImageOffset = 3.0;
/*!
@ingroup appkit @ingroup appkit
@class CPButton @class CPButton
@@ -86,9 +85,12 @@ CPButtonImageOffset = 3.0;
@implementation CPButton : CPControl @implementation CPButton : CPControl
{ {
BOOL _allowsMixedState; BOOL _allowsMixedState;
CPString _title; CPString _title;
CPString _alternateTitle; CPString _alternateTitle;
CPImage _image;
CPImage _alternateImage;
CPInteger _showsStateBy; CPInteger _showsStateBy;
CPInteger _highlightsBy; CPInteger _highlightsBy;
@@ -97,9 +99,6 @@ CPButtonImageOffset = 3.0;
// NS-style Display Properties // NS-style Display Properties
CPBezelStyle _bezelStyle; CPBezelStyle _bezelStyle;
CPControlSize _controlSize; CPControlSize _controlSize;
CPString _keyEquivalent;
unsigned _keyEquivalentModifierMask;
} }
+ (id)buttonWithTitle:(CPString)aTitle + (id)buttonWithTitle:(CPString)aTitle
@@ -118,21 +117,21 @@ CPButtonImageOffset = 3.0;
return button; return button;
} }
+ (CPString)defaultThemeClass + (CPString)themeClass
{ {
return @"button"; return @"button";
} }
+ (id)themeAttributes + (id)themeAttributes
{ {
return [CPDictionary dictionaryWithObjects:[[CPNull null], 0.0, _CGInsetMakeZero(), _CGInsetMakeZero(), [CPNull null]] return [CPDictionary dictionaryWithObjects:[_CGInsetMakeZero(), _CGInsetMakeZero(), [CPNull null]]
forKeys:[@"image", @"image-offset", @"bezel-inset", @"content-inset", @"bezel-color"]]; forKeys:[@"bezel-inset", @"content-inset", @"bezel-color"]];
} }
- (id)initWithFrame:(CGRect)aFrame - (id)initWithFrame:(CGRect)aFrame
{ {
self = [super initWithFrame:aFrame]; self = [super initWithFrame:aFrame];
if (self) if (self)
{ {
// Should we instead override the defaults? // Should we instead override the defaults?
@@ -140,16 +139,13 @@ CPButtonImageOffset = 3.0;
[self setValue:CPCenterVerticalTextAlignment forThemeAttribute:@"vertical-alignment"]; [self setValue:CPCenterVerticalTextAlignment forThemeAttribute:@"vertical-alignment"];
[self setValue:CPImageLeft forThemeAttribute:@"image-position"]; [self setValue:CPImageLeft forThemeAttribute:@"image-position"];
[self setValue:CPScaleNone forThemeAttribute:@"image-scaling"]; [self setValue:CPScaleNone forThemeAttribute:@"image-scaling"];
_controlSize = CPRegularControlSize; _controlSize = CPRegularControlSize;
_keyEquivalent = @"";
_keyEquivalentModifierMask = 0;
// [self setBezelStyle:CPRoundRectBezelStyle]; // [self setBezelStyle:CPRoundRectBezelStyle];
[self setBordered:YES]; [self setBordered:YES];
} }
return self; return self;
} }
@@ -252,9 +248,9 @@ CPButtonImageOffset = 3.0;
{ {
if (_title === aTitle) if (_title === aTitle)
return; return;
_title = aTitle; _title = aTitle;
[self setNeedsLayout]; [self setNeedsLayout];
[self setNeedsDisplay:YES]; [self setNeedsDisplay:YES];
} }
@@ -268,7 +264,7 @@ CPButtonImageOffset = 3.0;
{ {
if (_alternateTitle === aTitle) if (_alternateTitle === aTitle)
return; return;
_alternateTitle = aTitle; _alternateTitle = aTitle;
[self setNeedsLayout]; [self setNeedsLayout];
@@ -282,12 +278,18 @@ CPButtonImageOffset = 3.0;
- (void)setImage:(CPImage)anImage - (void)setImage:(CPImage)anImage
{ {
[self setValue:anImage forThemeAttribute:@"image"]; if (_image === anImage)
return;
_image = anImage;
[self setNeedsLayout];
[self setNeedsDisplay:YES];
} }
- (CPImage)image - (CPImage)image
{ {
return [self valueForThemeAttribute:@"image" inState:CPThemeStateNormal]; return _image;
} }
/*! /*!
@@ -296,7 +298,13 @@ CPButtonImageOffset = 3.0;
*/ */
- (void)setAlternateImage:(CPImage)anImage - (void)setAlternateImage:(CPImage)anImage
{ {
[self setValue:anImage forThemeAttribute:@"image" inState:CPThemeStateHighlighted]; if (_alternateImage === anImage)
return;
_alternateImage = anImage;
[self setNeedsLayout];
[self setNeedsDisplay:YES];
} }
/*! /*!
@@ -304,17 +312,7 @@ CPButtonImageOffset = 3.0;
*/ */
- (CPImage)alternateImage - (CPImage)alternateImage
{ {
return [self valueForThemeAttribute:@"image" inState:CPThemeStateHighlighted]; return _alternateImage;
}
- (void)setImageOffset:(float)theImageOffset
{
[self setValue:theImageOffset forThemeAttribute:@"image-offset"];
}
- (float)imageOffset
{
return [self valueForThemeAttribute:@"image-offset"];
} }
- (void)setShowsStateBy:(CPInteger)aMask - (void)setShowsStateBy:(CPInteger)aMask
@@ -375,13 +373,13 @@ CPButtonImageOffset = 3.0;
[self setShowsStateBy:CPContentsCellMask]; [self setShowsStateBy:CPContentsCellMask];
break; break;
case CPSwitchButton: [CPException raise:CPInvalidArgumentException case CPSwitchButton: [CPException raise:CPInvalidArgumentException
reason:"The CPSwitchButton type is not supported in Cappuccino, use the CPCheckBox class instead."]; reason:"The CPSwitchButton type is not supported in Cappuccino, use the CPCheckBox class instead."];
case CPRadioButton: [CPException raise:CPInvalidArgumentException case CPRadioButton: [CPException raise:CPInvalidArgumentException
reason:"The CPRadioButton type is not supported in Cappuccino, use the CPRadio class instead."]; reason:"The CPRadioButton type is not supported in Cappuccino, use the CPRadio class instead."];
default: [CPException raise:CPInvalidArgumentException default: [CPException raise:CPInvalidArgumentException
reason:"Unknown button type."]; reason:"Unknown button type."];
} }
@@ -397,7 +395,7 @@ CPButtonImageOffset = 3.0;
_imageDimsWhenDisabled = imageShouldDimWhenDisabled; _imageDimsWhenDisabled = imageShouldDimWhenDisabled;
if ([self hasThemeState:CPThemeStateDisabled]) if (_imageDimsWhenDisabled)
{ {
[self setNeedsDisplay:YES]; [self setNeedsDisplay:YES];
[self setNeedsLayout]; [self setNeedsLayout];
@@ -412,7 +410,7 @@ CPButtonImageOffset = 3.0;
- (BOOL)startTrackingAt:(CGPoint)aPoint - (BOOL)startTrackingAt:(CGPoint)aPoint
{ {
[self highlight:YES]; [self highlight:YES];
return [super startTrackingAt:aPoint]; return [super startTrackingAt:aPoint];
} }
@@ -433,12 +431,11 @@ CPButtonImageOffset = 3.0;
if (_CGInsetIsEmpty(contentInset)) if (_CGInsetIsEmpty(contentInset))
return bounds; return bounds;
bounds = _CGRectMakeCopy(bounds);
bounds.origin.x += contentInset.left; bounds.origin.x += contentInset.left;
bounds.origin.y += contentInset.top; bounds.origin.y += contentInset.top;
bounds.size.width -= contentInset.left + contentInset.right; bounds.size.width -= contentInset.left + contentInset.right;
bounds.size.height -= contentInset.top + contentInset.bottom; bounds.size.height -= contentInset.top + contentInset.bottom;
return bounds; return bounds;
} }
@@ -452,7 +449,6 @@ CPButtonImageOffset = 3.0;
if (_CGInsetIsEmpty(bezelInset)) if (_CGInsetIsEmpty(bezelInset))
return bounds; return bounds;
bounds = _CGRectMakeCopy(bounds);
bounds.origin.x += bezelInset.left; bounds.origin.x += bezelInset.left;
bounds.origin.y += bezelInset.top; bounds.origin.y += bezelInset.top;
bounds.size.width -= bezelInset.left + bezelInset.right; bounds.size.width -= bezelInset.left + bezelInset.right;
@@ -466,20 +462,8 @@ CPButtonImageOffset = 3.0;
*/ */
- (void)sizeToFit - (void)sizeToFit
{ {
[self layoutSubviews]; var size = [([self title] || " ") sizeWithFont:[self currentValueForThemeAttribute:@"font"]],
contentInset = [self currentValueForThemeAttribute:@"content-inset"],
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"], minSize = [self currentValueForThemeAttribute:@"min-size"],
maxSize = [self currentValueForThemeAttribute:@"max-size"]; maxSize = [self currentValueForThemeAttribute:@"max-size"];
@@ -499,10 +483,10 @@ CPButtonImageOffset = 3.0;
{ {
if (aName === "bezel-view") if (aName === "bezel-view")
return [self bezelRectForBounds:[self bounds]]; return [self bezelRectForBounds:[self bounds]];
else if (aName === "content-view") else if (aName === "content-view")
return [self contentRectForBounds:[self bounds]]; return [self contentRectForBounds:[self bounds]];
return [super rectForEphemeralSubviewNamed:aName]; return [super rectForEphemeralSubviewNamed:aName];
} }
@@ -513,7 +497,7 @@ CPButtonImageOffset = 3.0;
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()]; var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
[view setHitTests:NO]; [view setHitTests:NO];
return view; return view;
} }
else else
@@ -535,8 +519,7 @@ CPButtonImageOffset = 3.0;
if (contentView) if (contentView)
{ {
[contentView setText:([self hasThemeState:CPThemeStateHighlighted] && _alternateTitle) ? _alternateTitle : _title]; [contentView setText:([self hasThemeState:CPThemeStateHighlighted] && _alternateTitle) ? _alternateTitle : _title];
[contentView setImage:[self currentValueForThemeAttribute:@"image"]]; [contentView setImage:([self hasThemeState:CPThemeStateHighlighted] && _alternateImage) ? _alternateImage : _image];
[contentView setImageOffset:[self currentValueForThemeAttribute:@"image-offset"]];
[contentView setFont:[self currentValueForThemeAttribute:@"font"]]; [contentView setFont:[self currentValueForThemeAttribute:@"font"]];
[contentView setTextColor:[self currentValueForThemeAttribute:@"text-color"]]; [contentView setTextColor:[self currentValueForThemeAttribute:@"text-color"]];
@@ -547,10 +530,17 @@ CPButtonImageOffset = 3.0;
[contentView setTextShadowOffset:[self currentValueForThemeAttribute:@"text-shadow-offset"]]; [contentView setTextShadowOffset:[self currentValueForThemeAttribute:@"text-shadow-offset"]];
[contentView setImagePosition:[self currentValueForThemeAttribute:@"image-position"]]; [contentView setImagePosition:[self currentValueForThemeAttribute:@"image-position"]];
[contentView setImageScaling:[self currentValueForThemeAttribute:@"image-scaling"]]; [contentView setImageScaling:[self currentValueForThemeAttribute:@"image-scaling"]];
[contentView setDimsImage:[self hasThemeState:CPThemeStateDisabled] && _imageDimsWhenDisabled];
} }
} }
- (void)setDefaultButton:(BOOL)shouldBeDefaultButton
{
if (shouldBeDefaultButton)
[self setThemeState:CPThemeStateDefault];
else
[self unsetThemeState:CPThemeStateDefault];
}
- (void)setBordered:(BOOL)shouldBeBordered - (void)setBordered:(BOOL)shouldBeBordered
{ {
if (shouldBeBordered) if (shouldBeBordered)
@@ -564,79 +554,6 @@ CPButtonImageOffset = 3.0;
return [self hasThemeState:CPThemeStateBordered]; return [self hasThemeState:CPThemeStateBordered];
} }
/*!
Sets the keyboard shortcut for this button. For special keys see
CPEvent.j CP...FunctionKey and CPText.j CP...Character.
@param aString the keyboard shortcut as a string
*/
- (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];
}
/*!
Returns the keyboard shortcut for this button.
*/
- (CPString)keyEquivalent
{
return _keyEquivalent;
}
/*!
Returns the mask used with this button's key equivalent.
*/
- (void)setKeyEquivalentModifierMask:(unsigned)aMask
{
_keyEquivalentModifierMask = aMask;
}
/*!
Sets the mask to be used with this button's key equivalent.
*/
- (unsigned)keyEquivalentModifierMask
{
return _keyEquivalentModifierMask;
}
/*!
Checks the button's key equivalent against that in the event, and if they
match simulates a button click.
*/
- (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;
[self performClick:nil];
return YES;
}
@end @end
@implementation CPButton (NS) @implementation CPButton (NS)
@@ -652,16 +569,11 @@ CPButtonImageOffset = 3.0;
@end @end
var CPButtonImageKey = @"CPButtonImageKey", var CPButtonImageKey = @"CPButtonImageKey",
CPButtonAlternateImageKey = @"CPButtonAlternateImageKey", CPButtonAlternateImageKey = @"CPButtonAlternateImageKey",
CPButtonTitleKey = @"CPButtonTitleKey", CPButtonTitleKey = @"CPButtonTitleKey",
CPButtonAlternateTitleKey = @"CPButtonAlternateTitleKey", CPButtonAlternateTitleKey = @"CPButtonAlternateTitleKey",
CPButtonIsBorderedKey = @"CPButtonIsBorderedKey", CPButtonIsBorderedKey = @"CPButtonIsBorderedKey";
CPButtonAllowsMixedStateKey = @"CPButtonAllowsMixedStateKey",
CPButtonImageDimsWhenDisabledKey = @"CPButtonImageDimsWhenDisabledKey",
CPButtonImagePositionKey = @"CPButtonImagePositionKey",
CPButtonKeyEquivalentKey = @"CPButtonKeyEquivalentKey",
CPButtonKeyEquivalentMaskKey = @"CPButtonKeyEquivalentMaskKey";
@implementation CPButton (CPCoding) @implementation CPButton (CPCoding)
@@ -672,31 +584,21 @@ var CPButtonImageKey = @"CPButtonImageKey",
- (id)initWithCoder:(CPCoder)aCoder - (id)initWithCoder:(CPCoder)aCoder
{ {
self = [super initWithCoder:aCoder]; self = [super initWithCoder:aCoder];
if (self) if (self)
{ {
_controlSize = CPRegularControlSize; _controlSize = CPRegularControlSize;
_title = [aCoder decodeObjectForKey:CPButtonTitleKey]; [self setImage:[aCoder decodeObjectForKey:CPButtonImageKey]];
_alternateTitle = [aCoder decodeObjectForKey:CPButtonAlternateTitleKey]; [self setAlternateImage:[aCoder decodeObjectForKey:CPButtonAlternateImageKey]];
if ([aCoder containsValueForKey:CPButtonAllowsMixedStateKey]) [self setTitle:[aCoder decodeObjectForKey:CPButtonTitleKey]];
_allowsMixedState = [aCoder decodeBoolForKey:CPButtonAllowsMixedStateKey]; [self setAlternateTitle:[aCoder decodeObjectForKey:CPButtonAlternateTitleKey]];
[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 setNeedsLayout];
[self setNeedsDisplay:YES]; [self setNeedsDisplay:YES];
} }
return self; return self;
} }
@@ -708,18 +610,11 @@ var CPButtonImageKey = @"CPButtonImageKey",
{ {
[super encodeWithCoder:aCoder]; [super encodeWithCoder:aCoder];
[aCoder encodeObject:_image forKey:CPButtonImageKey];
[aCoder encodeObject:_alternateImage forKey:CPButtonAlternateImageKey];
[aCoder encodeObject:_title forKey:CPButtonTitleKey]; [aCoder encodeObject:_title forKey:CPButtonTitleKey];
[aCoder encodeObject:_alternateTitle forKey:CPButtonAlternateTitleKey]; [aCoder encodeObject:_alternateTitle forKey:CPButtonAlternateTitleKey];
[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 @end
+29 -57
View File
@@ -1,5 +1,7 @@
@import "CPView.j" @import <AppKit/CPView.j>
#include "CoreGraphics/CGGeometry.h"
@implementation CPButtonBar : CPView @implementation CPButtonBar : CPView
@@ -12,9 +14,8 @@
+ (id)plusButton + (id)plusButton
{ {
var button = [[CPButton alloc] initWithFrame:CGRectMake(0, 0, 35, 25)], var button = [[CPButton alloc] initWithFrame:CGRectMake(0, 0, 35, 25)],
image = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPButtonBar class]] pathForResource:@"plus_button.png"] size:CGSizeMake(11, 12)]; image = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:self] pathForResource:@"plus_button.png"] size:CGSizeMake(11, 12)];
[button setBordered:NO];
[button setImage:image]; [button setImage:image];
[button setImagePosition:CPImageOnly]; [button setImagePosition:CPImageOnly];
@@ -24,39 +25,23 @@
+ (id)minusButton + (id)minusButton
{ {
var button = [[CPButton alloc] initWithFrame:CGRectMake(0, 0, 35, 25)], var button = [[CPButton alloc] initWithFrame:CGRectMake(0, 0, 35, 25)],
image = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPButtonBar class]] pathForResource:@"minus_button.png"] size:CGSizeMake(11, 4)]; image = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:self] pathForResource:@"minus_button.png"] size:CGSizeMake(11, 4)];
[button setBordered:NO];
[button setImage:image]; [button setImage:image];
[button setImagePosition:CPImageOnly]; [button setImagePosition:CPImageOnly];
return button; return button;
} }
+ (id)actionPopupButton + (CPString)themeClass
{
var button = [[CPPopUpButton alloc] initWithFrame:CGRectMake(0, 0, 35, 25)],
image = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPButtonBar class]] pathForResource:@"action_button.png"] size:CGSizeMake(22, 14)];
[button addItemWithTitle:nil];
[[button lastItem] setImage:image];
[button setImagePosition:CPImageOnly];
[button setValue:CGInsetMake(0, 0, 0, 0) forThemeAttribute:"content-inset"];
[button setPullsDown:YES];
return button;
}
+ (CPString)defaultThemeClass
{ {
return @"button-bar"; return @"button-bar";
} }
+ (id)themeAttributes + (id)themeAttributes
{ {
return [CPDictionary dictionaryWithObjects:[CGInsetMake(0.0, 0.0, 0.0, 0.0), CGSizeMakeZero(), [CPNull null], [CPNull null], [CPNull null], [CPNull null]] return [CPDictionary dictionaryWithObjects:[CGInsetMake(0.0, 0.0, 0.0, 0.0), CGSizeMakeZero(), [CPNull null], [CPNull null], [CPNull null]]
forKeys:[@"resize-control-inset", @"resize-control-size", @"resize-control-color", @"bezel-color", @"button-bezel-color", @"button-text-color"]]; forKeys:[@"resize-control-inset", @"resize-control-size", @"resize-control-color", @"bezel-color", @"button-bezel-color"]];
} }
- (id)initWithFrame:(CGRect)aFrame - (id)initWithFrame:(CGRect)aFrame
@@ -97,8 +82,25 @@
_buttons = [CPArray arrayWithArray:buttons]; _buttons = [CPArray arrayWithArray:buttons];
for (var i = 0, count = [_buttons count]; i < count; i++) for (var i = 0, count = [_buttons count]; i < count; i++)
[_buttons[i] setBordered:YES]; {
var button = _buttons[i];
var normalColor = [self valueForThemeAttribute:@"button-bezel-color" inState:CPThemeStateNormal],
highlightedColor = [self valueForThemeAttribute:@"button-bezel-color" inState:CPThemeStateHighlighted],
disabledColor = [self valueForThemeAttribute:@"button-bezel-color" inState:CPThemeStateDisabled];
[button setValue:normalColor forThemeAttribute:@"bezel-color" inState:CPThemeStateNormal|CPThemeStateBordered];
[button setValue:highlightedColor forThemeAttribute:@"bezel-color" inState:CPThemeStateHighlighted|CPThemeStateBordered];
[button setValue:disabledColor forThemeAttribute:@"bezel-color" inState:CPThemeStateDisabled|CPThemeStateBordered];
// FIXME shouldn't need this
[button setValue:normalColor forThemeAttribute:@"bezel-color" inState:CPThemeStateNormal|CPThemeStateBordered|CPPopUpButtonStatePullsDown];
[button setValue:highlightedColor forThemeAttribute:@"bezel-color" inState:CPThemeStateHighlighted|CPThemeStateBordered|CPPopUpButtonStatePullsDown];
[button setValue:disabledColor forThemeAttribute:@"bezel-color" inState:CPThemeStateDisabled|CPThemeStateBordered|CPPopUpButtonStatePullsDown];
[button setBordered:YES];
}
[self setNeedsLayout]; [self setNeedsLayout];
} }
@@ -174,11 +176,6 @@
{ {
[self setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]]; [self setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
var normalColor = [self valueForThemeAttribute:@"button-bezel-color" inState:CPThemeStateNormal],
highlightedColor = [self valueForThemeAttribute:@"button-bezel-color" inState:CPThemeStateHighlighted],
disabledColor = [self valueForThemeAttribute:@"button-bezel-color" inState:CPThemeStateDisabled],
textColor = [self valueForThemeAttribute:@"button-text-color" inState:CPThemeStateNormal];
var buttonsNotHidden = [CPArray arrayWithArray:_buttons], var buttonsNotHidden = [CPArray arrayWithArray:_buttons],
count = [buttonsNotHidden count]; count = [buttonsNotHidden count];
@@ -187,23 +184,13 @@
[buttonsNotHidden removeObject:buttonsNotHidden[count]]; [buttonsNotHidden removeObject:buttonsNotHidden[count]];
var currentButtonOffset = _resizeControlIsLeftAligned ? CGRectGetMaxX([self bounds]) + 1 : -1, var currentButtonOffset = _resizeControlIsLeftAligned ? CGRectGetMaxX([self bounds]) + 1 : -1,
bounds = [self bounds], height = CGRectGetHeight([self bounds]) - 1;
height = CGRectGetHeight(bounds) - 1,
frameWidth = CGRectGetWidth(bounds),
resizeRect = _hasResizeControl ? [self rectForEphemeralSubviewNamed:"resize-control-view"] : CGRectMakeZero(),
resizeWidth = CGRectGetWidth(resizeRect),
availableWidth = frameWidth - resizeWidth - 1;
for (var i = 0, count = [buttonsNotHidden count]; i < count; i++) for (var i = 0, count = [buttonsNotHidden count]; i < count; i++)
{ {
var button = buttonsNotHidden[i], var button = buttonsNotHidden[i],
width = CGRectGetWidth([button frame]); width = CGRectGetWidth([button frame]);
if (availableWidth > width)
availableWidth -= width;
else
break;
if (_resizeControlIsLeftAligned) if (_resizeControlIsLeftAligned)
{ {
[button setFrame:CGRectMake(currentButtonOffset - width, 1, width, height)]; [button setFrame:CGRectMake(currentButtonOffset - width, 1, width, height)];
@@ -215,16 +202,6 @@
currentButtonOffset += width - 1; currentButtonOffset += width - 1;
} }
[button setValue:normalColor forThemeAttribute:@"bezel-color" inState:CPThemeStateNormal | CPThemeStateBordered];
[button setValue:highlightedColor forThemeAttribute:@"bezel-color" inState:CPThemeStateHighlighted | CPThemeStateBordered];
[button setValue:disabledColor forThemeAttribute:@"bezel-color" inState:CPThemeStateDisabled | CPThemeStateBordered];
[button setValue:textColor forThemeAttribute:@"text-color" inState:CPThemeStateBordered];
// FIXME shouldn't need this
[button setValue:normalColor forThemeAttribute:@"bezel-color" inState:CPThemeStateNormal | CPThemeStateBordered | CPPopUpButtonStatePullsDown];
[button setValue:highlightedColor forThemeAttribute:@"bezel-color" inState:CPThemeStateHighlighted | CPThemeStateBordered | CPPopUpButtonStatePullsDown];
[button setValue:disabledColor forThemeAttribute:@"bezel-color" inState:CPThemeStateDisabled | CPThemeStateBordered | CPPopUpButtonStatePullsDown];
[self addSubview:button]; [self addSubview:button];
} }
@@ -239,12 +216,6 @@
} }
} }
- (void)setFrameSize:(CGSize)aSize
{
[super setFrameSize:aSize];
[self setNeedsLayout];
}
@end @end
var CPButtonBarHasResizeControlKey = @"CPButtonBarHasResizeControlKey", var CPButtonBarHasResizeControlKey = @"CPButtonBarHasResizeControlKey",
@@ -275,3 +246,4 @@ var CPButtonBarHasResizeControlKey = @"CPButtonBarHasResizeControlKey",
} }
@end @end
+2 -27
View File
@@ -23,8 +23,6 @@
@import "CPButton.j" @import "CPButton.j"
CPCheckBoxImageOffset = 4.0;
@implementation CPCheckBox : CPButton @implementation CPCheckBox : CPButton
{ {
} }
@@ -39,7 +37,7 @@ CPCheckBoxImageOffset = 4.0;
return [self buttonWithTitle:aTitle]; return [self buttonWithTitle:aTitle];
} }
+ (CPString)defaultThemeClass + (CPString)themeClass
{ {
return @"check-box"; return @"check-box";
} }
@@ -57,33 +55,10 @@ CPCheckBoxImageOffset = 4.0;
[self setImagePosition:CPImageLeft]; [self setImagePosition:CPImageLeft];
[self setAlignment:CPLeftTextAlignment]; [self setAlignment:CPLeftTextAlignment];
[self setBordered:NO]; [self setBordered:YES];
} }
return self; return self;
} }
- (void)takeStateFromKeyPath:(CPString)aKeyPath ofObjects:(CPArray)objects
{
var count = objects.length,
value = [objects[0] valueForKeyPath:aKeyPath] ? CPOnState : CPOffState;
[self setAllowsMixedState:NO];
[self setState:value];
while (count-- > 1)
{
if (value !== ([objects[count] valueForKeyPath:aKeyPath] ? CPOnState : CPOffState))
{
[self setAllowsMixedState:YES];
[self setState:CPMixedState];
}
}
}
- (void)takeValueFromKeyPath:(CPString)aKeyPath ofObjects:(CPArray)objects
{
[self takeStateFromKeyPath:aKeyPath ofObjects:objects];
}
@end @end
+31 -51
View File
@@ -22,12 +22,14 @@
@import "CPView.j" @import "CPView.j"
#include "CoreGraphics/CGGeometry.h"
/*!
/*!
@ingroup appkit @ingroup appkit
@class CPClipView @class CPClipView
CPClipView allows you to define a clip rect and display only that portion of its containing view. CPClipView allows you to define a clip rect and display only that portion of its containing view.
It is used to hold the document view in a CPScrollView. It is used to hold the document view in a CPScrollView.
*/ */
@implementation CPClipView : CPView @implementation CPClipView : CPView
@@ -45,7 +47,7 @@
return; return;
var defaultCenter = [CPNotificationCenter defaultCenter]; var defaultCenter = [CPNotificationCenter defaultCenter];
if (_documentView) if (_documentView)
{ {
[defaultCenter [defaultCenter
@@ -57,29 +59,29 @@
removeObserver:self removeObserver:self
name:CPViewBoundsDidChangeNotification name:CPViewBoundsDidChangeNotification
object:_documentView]; object:_documentView];
[_documentView removeFromSuperview]; [_documentView removeFromSuperview];
} }
_documentView = aView; _documentView = aView;
if (_documentView) if (_documentView)
{ {
[self addSubview:_documentView]; [self addSubview:_documentView];
[_documentView setPostsFrameChangedNotifications:YES];
[_documentView setPostsBoundsChangedNotifications:YES];
[_documentView setPostsFrameChangedNotifications:YES]; [defaultCenter
[_documentView setPostsBoundsChangedNotifications:YES];
[defaultCenter
addObserver:self addObserver:self
selector:@selector(viewFrameChanged:) selector:@selector(viewFrameChanged:)
name:CPViewFrameDidChangeNotification name:CPViewFrameDidChangeNotification
object:_documentView]; object:_documentView];
[defaultCenter [defaultCenter
addObserver:self addObserver:self
selector:@selector(viewBoundsChanged:) selector:@selector(viewBoundsChanged:)
name:CPViewBoundsDidChangeNotification name:CPViewBoundsDidChangeNotification
object:_documentView]; object:_documentView];
} }
} }
@@ -104,7 +106,7 @@
return _CGPointMakeZero(); return _CGPointMakeZero();
var documentFrame = [_documentView frame]; var documentFrame = [_documentView frame];
aPoint.x = MAX(0.0, MIN(aPoint.x, MAX(_CGRectGetWidth(documentFrame) - _CGRectGetWidth(_bounds), 0.0))); aPoint.x = MAX(0.0, MIN(aPoint.x, MAX(_CGRectGetWidth(documentFrame) - _CGRectGetWidth(_bounds), 0.0)));
aPoint.y = MAX(0.0, MIN(aPoint.y, MAX(_CGRectGetHeight(documentFrame) - _CGRectGetHeight(_bounds), 0.0))); aPoint.y = MAX(0.0, MIN(aPoint.y, MAX(_CGRectGetHeight(documentFrame) - _CGRectGetHeight(_bounds), 0.0)));
@@ -115,7 +117,7 @@
{ {
if (_CGPointEqualToPoint(_bounds.origin, aPoint)) if (_CGPointEqualToPoint(_bounds.origin, aPoint))
return; return;
[super setBoundsOrigin:aPoint]; [super setBoundsOrigin:aPoint];
var superview = [self superview], var superview = [self superview],
@@ -124,7 +126,7 @@
// FIXME: Should CPScrollView be finding out about this on its own somehow? // FIXME: Should CPScrollView be finding out about this on its own somehow?
scrollViewClass = objj_getClass("CPScrollView"); scrollViewClass = objj_getClass("CPScrollView");
if ([superview isKindOfClass:scrollViewClass]) if([superview isKindOfClass:scrollViewClass])
[superview reflectScrolledClipView:self]; [superview reflectScrolledClipView:self];
} }
@@ -164,12 +166,12 @@
- (void)_constrainScrollPoint - (void)_constrainScrollPoint
{ {
var oldScrollPoint = [self bounds].origin; var oldScrollPoint = [self bounds].origin;
// Call scrollToPoint: because the current scroll point may no longer make // Call scrollToPoint: because the current scroll point may no longer make
// sense given the new frame of the document view. // sense given the new frame of the document view.
[self scrollToPoint:oldScrollPoint]; [self scrollToPoint:oldScrollPoint];
// scrollToPoint: takes care of reflectScrollClipView: for us, so bail if // scrollToPoint: takes care of reflectScrollClipView: for us, so bail if
// the scroll points are not equal (meaning scrollToPoint: didn't early bail). // the scroll points are not equal (meaning scrollToPoint: didn't early bail).
if (!CGPointEqualToPoint(oldScrollPoint, [self bounds].origin)) if (!CGPointEqualToPoint(oldScrollPoint, [self bounds].origin))
return; return;
@@ -185,42 +187,20 @@
[superview reflectScrolledClipView:self]; [superview reflectScrolledClipView:self];
} }
- (BOOL)autoscroll:(CPEvent)anEvent - (BOOL)autoscroll:(CPEvent)anEvent
{ {
var bounds = [self bounds], var bounds = [self bounds],
eventLocation = [self convertPoint:[anEvent locationInWindow] fromView:nil], eventLocation = [self convertPoint:[anEvent locationInWindow] fromView:nil];
superview = [self superview],
deltaX = 0,
deltaY = 0;
if (CGRectContainsPoint(bounds, eventLocation)) if (CPRectContainsPoint(bounds, eventLocation))
return NO; return NO;
if (![superview isKindOfClass:[CPScrollView class]] || [superview hasVerticalScroller]) var newRect = CGRectMakeZero();
{
if (eventLocation.y < CGRectGetMinY(bounds))
deltaY = CGRectGetMinY(bounds) - eventLocation.y;
else if (eventLocation.y > CGRectGetMaxY(bounds))
deltaY = CGRectGetMaxY(bounds) - eventLocation.y;
if (deltaY < -bounds.size.height)
deltaY = -bounds.size.height;
if (deltaY > bounds.size.height)
deltaY = bounds.size.height;
}
if (![superview isKindOfClass:[CPScrollView class]] || [superview hasHorizontalScroller]) newRect.origin = eventLocation;
{ newRect.size = CPSizeMake(10, 10);
if (eventLocation.x < CGRectGetMinX(bounds))
deltaX = CGRectGetMinX(bounds) - eventLocation.x;
else if (eventLocation.x > CGRectGetMaxX(bounds))
deltaX = CGRectGetMaxX(bounds) - eventLocation.x;
if (deltaX < -bounds.size.width)
deltaX = -bounds.size.width;
if (deltaX > bounds.size.width)
deltaX = bounds.size.width;
}
return [self scrollToPoint:CGPointMake(bounds.origin.x - deltaX, bounds.origin.y - deltaY)]; return [_documentView scrollRectToVisible:newRect];
} }
@end @end
@@ -234,14 +214,14 @@ var CPClipViewDocumentViewKey = @"CPScrollViewDocumentView";
{ {
if (self = [super initWithCoder:aCoder]) if (self = [super initWithCoder:aCoder])
[self setDocumentView:[aCoder decodeObjectForKey:CPClipViewDocumentViewKey]]; [self setDocumentView:[aCoder decodeObjectForKey:CPClipViewDocumentViewKey]];
return self; return self;
} }
- (void)encodeWithCoder:(CPCoder)aCoder - (void)encodeWithCoder:(CPCoder)aCoder
{ {
[super encodeWithCoder:aCoder]; [super encodeWithCoder:aCoder];
[aCoder encodeObject:_documentView forKey:CPClipViewDocumentViewKey]; [aCoder encodeObject:_documentView forKey:CPClipViewDocumentViewKey];
} }
+100 -196
View File
@@ -30,16 +30,16 @@
@import "CPCollectionViewItem.j" @import "CPCollectionViewItem.j"
/*! /*!
@ingroup appkit @ingroup appkit
@class CPCollectionView @class CPCollectionView
This class displays an array as a grid of objects, where each object is represented by a view. This class displays an array as a grid of objects, where each object is represented by a view.
The view is controlled by creating a CPCollectionViewItem and specifying its view, then The view is controlled by creating a CPCollectionViewItem and specifying its view, then
setting that item as the collection view prototype. setting that item as the collection view prototype.
@par Delegate Methods @par Delegate Methods
@delegate -(void)collectionViewDidChangeSelection:(CPCollectionView)collectionView; @delegate -(void)collectionViewDidChangeSelection:(CPCollectionView)collectionView;
Called when the selection in the collection view has changed. Called when the selection in the collection view has changed.
@param collectionView the collection view who's selection changed @param collectionView the collection view who's selection changed
@@ -67,35 +67,35 @@
{ {
CPArray _content; CPArray _content;
CPArray _items; CPArray _items;
CPData _itemData; CPData _itemData;
CPCollectionViewItem _itemPrototype; CPCollectionViewItem _itemPrototype;
CPCollectionViewItem _itemForDragging; CPCollectionViewItem _itemForDragging;
CPMutableArray _cachedItems; CPMutableArray _cachedItems;
unsigned _maxNumberOfRows; unsigned _maxNumberOfRows;
unsigned _maxNumberOfColumns; unsigned _maxNumberOfColumns;
CGSize _minItemSize; CGSize _minItemSize;
CGSize _maxItemSize; CGSize _maxItemSize;
CPArray _backgroundColors; CPArray _backgroundColors;
float _tileWidth; float _tileWidth;
BOOL _isSelectable; BOOL _isSelectable;
BOOL _allowsMultipleSelection; BOOL _allowsMultipleSelection;
BOOL _allowsEmptySelection; BOOL _allowsEmptySelection;
CPIndexSet _selectionIndexes; CPIndexSet _selectionIndexes;
CGSize _itemSize; CGSize _itemSize;
float _horizontalMargin; float _horizontalMargin;
float _verticalMargin; float _verticalMargin;
unsigned _numberOfRows; unsigned _numberOfRows;
unsigned _numberOfColumns; unsigned _numberOfColumns;
id _delegate; id _delegate;
CPEvent _mouseDownEvent; CPEvent _mouseDownEvent;
@@ -104,14 +104,14 @@
- (id)initWithFrame:(CGRect)aFrame - (id)initWithFrame:(CGRect)aFrame
{ {
self = [super initWithFrame:aFrame]; self = [super initWithFrame:aFrame];
if (self) if (self)
{ {
_items = []; _items = [];
_content = []; _content = [];
_cachedItems = []; _cachedItems = [];
_itemSize = CGSizeMakeZero(); _itemSize = CGSizeMakeZero();
_minItemSize = CGSizeMakeZero(); _minItemSize = CGSizeMakeZero();
_maxItemSize = CGSizeMakeZero(); _maxItemSize = CGSizeMakeZero();
@@ -120,12 +120,12 @@
_verticalMargin = 5.0; _verticalMargin = 5.0;
_tileWidth = -1.0; _tileWidth = -1.0;
_selectionIndexes = [CPIndexSet indexSet]; _selectionIndexes = [CPIndexSet indexSet];
_allowsEmptySelection = YES; _allowsEmptySelection = YES;
_isSelectable = YES; _isSelectable = YES;
} }
return self; return self;
} }
@@ -196,8 +196,8 @@
// Setting the Content // Setting the Content
/*! /*!
Sets the content of the collection view to the content in \c anArray. Sets the content of the collection view to the content in \c anArray.
This array can be of any type, and each element will be passed to the \c -setRepresentedObject: method. This array can be of any type, and each element will be passed to the \c -setRepresentedObject: method.
It's the responsibility of your custom collection view item to interpret the object. It's the responsibility of your custom collection view item to interpret the object.
@param anArray the content array @param anArray the content array
*/ */
@@ -205,9 +205,9 @@
{ {
if (_content == anArray) if (_content == anArray)
return; return;
_content = anArray; _content = anArray;
[self reloadContent]; [self reloadContent];
} }
@@ -236,13 +236,13 @@
{ {
if (_isSelectable == isSelectable) if (_isSelectable == isSelectable)
return; return;
_isSelectable = isSelectable; _isSelectable = isSelectable;
if (!_isSelectable) if (!_isSelectable)
{ {
var index = CPNotFound; var index = CPNotFound;
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound) while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound)
[_items[index] setSelected:NO]; [_items[index] setSelected:NO];
} }
@@ -297,25 +297,23 @@
*/ */
- (void)setSelectionIndexes:(CPIndexSet)anIndexSet - (void)setSelectionIndexes:(CPIndexSet)anIndexSet
{ {
if ([_selectionIndexes isEqual:anIndexSet] || !_isSelectable) if (_selectionIndexes == anIndexSet || !_isSelectable)
return; return;
var index = CPNotFound; var index = CPNotFound;
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound) while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound)
[_items[index] setSelected:NO]; [_items[index] setSelected:NO];
_selectionIndexes = anIndexSet; _selectionIndexes = anIndexSet;
var index = CPNotFound; var index = CPNotFound;
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound) while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound)
[_items[index] setSelected:YES]; [_items[index] setSelected:YES];
[[CPKeyValueBinding getBinding:@"selectionIndexes" forObject:self] reverseSetValueFor:@"selectionIndexes"];
if ([_delegate respondsToSelector:@selector(collectionViewDidChangeSelection:)]) if ([_delegate respondsToSelector:@selector(collectionViewDidChangeSelection:)])
[_delegate collectionViewDidChangeSelection:self]; [_delegate collectionViewDidChangeSelection:self]
} }
/*! /*!
@@ -328,10 +326,10 @@
/* @ignore */ /* @ignore */
- (void)reloadContent - (void)reloadContent
{ {
// Remove current views // Remove current views
var count = _items.length; var count = _items.length;
while (count--) while (count--)
{ {
[[_items[count] view] removeFromSuperview]; [[_items[count] view] removeFromSuperview];
@@ -339,7 +337,7 @@
_cachedItems.push(_items[count]); _cachedItems.push(_items[count]);
} }
_items = []; _items = [];
if (!_itemPrototype || !_content) if (!_itemPrototype || !_content)
@@ -352,7 +350,7 @@
for (; index < count; ++index) for (; index < count; ++index)
{ {
_items.push([self newItemForRepresentedObject:_content[index]]); _items.push([self newItemForRepresentedObject:_content[index]]);
[self addSubview:[_items[index] view]]; [self addSubview:[_items[index] view]];
} }
@@ -367,49 +365,49 @@
- (void)tile - (void)tile
{ {
var width = CGRectGetWidth([self bounds]); var width = CGRectGetWidth([self bounds]);
if (![_content count] || width == _tileWidth) if (![_content count] || width == _tileWidth)
return; return;
// We try to fit as many views per row as possible. Any remaining space is then // We try to fit as many views per row as possible. Any remaining space is then
// either proportioned out to the views (if their minSize != maxSize) or used as // either proportioned out to the views (if their minSize != maxSize) or used as
// margin // margin
var itemSize = CGSizeMakeCopy(_minItemSize); var itemSize = CGSizeMakeCopy(_minItemSize);
_numberOfColumns = MAX(1.0, FLOOR(width / itemSize.width)); _numberOfColumns = MAX(1.0, FLOOR(width / itemSize.width));
if (_maxNumberOfColumns > 0) if (_maxNumberOfColumns > 0)
_numberOfColumns = MIN(_maxNumberOfColumns, _numberOfColumns); _numberOfColumns = MIN(_maxNumberOfColumns, _numberOfColumns);
var remaining = width - _numberOfColumns * itemSize.width, var remaining = width - _numberOfColumns * itemSize.width,
itemsNeedSizeUpdate = NO; itemsNeedSizeUpdate = NO;
if (remaining > 0 && itemSize.width < _maxItemSize.width) if (remaining > 0 && itemSize.width < _maxItemSize.width)
itemSize.width = MIN(_maxItemSize.width, itemSize.width + FLOOR(remaining / _numberOfColumns)); itemSize.width = MIN(_maxItemSize.width, itemSize.width + FLOOR(remaining / _numberOfColumns));
// When we ONE column and a non-integral width, the FLOORing above can cause the item width to be smaller than the total width. // When we ONE column and a non-integral width, the FLOORing above can cause the item width to be smaller than the total width.
if (_maxNumberOfColumns == 1 && itemSize.width < _maxItemSize.width && itemSize.width < width) if (_maxNumberOfColumns == 1 && itemSize.width < _maxItemSize.width && itemSize.width < width)
itemSize.width = MIN(_maxItemSize.width, width); itemSize.width = MIN(_maxItemSize.width, width);
if (!CGSizeEqualToSize(_itemSize, itemSize)) if (!CGSizeEqualToSize(_itemSize, itemSize))
{ {
_itemSize = itemSize; _itemSize = itemSize;
itemsNeedSizeUpdate = YES; itemsNeedSizeUpdate = YES;
} }
var index = 0, var index = 0,
count = _items.length; count = _items.length;
if (_maxNumberOfColumns > 0 && _maxNumberOfRows > 0) if (_maxNumberOfColumns > 0 && _maxNumberOfRows > 0)
count = MIN(count, _maxNumberOfColumns * _maxNumberOfRows); count = MIN(count, _maxNumberOfColumns * _maxNumberOfRows);
_numberOfRows = CEIL(count / _numberOfColumns); _numberOfRows = CEIL(count / _numberOfColumns);
_horizontalMargin = FLOOR((width - _numberOfColumns * itemSize.width) / (_numberOfColumns + 1)); _horizontalMargin = FLOOR((width - _numberOfColumns * itemSize.width) / (_numberOfColumns + 1));
var x = _horizontalMargin, var x = _horizontalMargin,
y = -itemSize.height; y = -itemSize.height;
for (; index < count; ++index) for (; index < count; ++index)
{ {
if (index % _numberOfColumns == 0) if (index % _numberOfColumns == 0)
@@ -417,28 +415,19 @@
x = _horizontalMargin; x = _horizontalMargin;
y += _verticalMargin + itemSize.height; y += _verticalMargin + itemSize.height;
} }
var view = [_items[index] view]; var view = [_items[index] view];
[view setFrameOrigin:CGPointMake(x, y)]; [view setFrameOrigin:CGPointMake(x, y)];
if (itemsNeedSizeUpdate) if (itemsNeedSizeUpdate)
[view setFrameSize:_itemSize]; [view setFrameSize:_itemSize];
x += itemSize.width + _horizontalMargin; x += itemSize.width + _horizontalMargin;
} }
var superview = [self superview],
proposedHeight = y + itemSize.height + _verticalMargin;
if ([superview isKindOfClass:[CPClipView class]])
{
var superviewSize = [superview bounds].size;
proposedHeight = MAX(superviewSize.height, proposedHeight);
}
_tileWidth = width; _tileWidth = width;
[self setFrameSize:CGSizeMake(width, proposedHeight)]; [self setFrameSize:CGSizeMake(width, y + itemSize.height + _verticalMargin)];
_tileWidth = -1.0; _tileWidth = -1.0;
} }
@@ -456,9 +445,9 @@
{ {
if (_maxNumberOfRows == aMaxNumberOfRows) if (_maxNumberOfRows == aMaxNumberOfRows)
return; return;
_maxNumberOfRows = aMaxNumberOfRows; _maxNumberOfRows = aMaxNumberOfRows;
[self tile]; [self tile];
} }
@@ -478,9 +467,9 @@
{ {
if (_maxNumberOfColumns == aMaxNumberOfColumns) if (_maxNumberOfColumns == aMaxNumberOfColumns)
return; return;
_maxNumberOfColumns = aMaxNumberOfColumns; _maxNumberOfColumns = aMaxNumberOfColumns;
[self tile]; [self tile];
} }
@@ -517,9 +506,9 @@
{ {
if (CGSizeEqualToSize(_minItemSize, aSize)) if (CGSizeEqualToSize(_minItemSize, aSize))
return; return;
_minItemSize = CGSizeMakeCopy(aSize); _minItemSize = CGSizeMakeCopy(aSize);
[self tile]; [self tile];
} }
@@ -539,9 +528,9 @@
{ {
if (CGSizeEqualToSize(_maxItemSize, aSize)) if (CGSizeEqualToSize(_maxItemSize, aSize))
return; return;
_maxItemSize = CGSizeMakeCopy(aSize); _maxItemSize = CGSizeMakeCopy(aSize);
[self tile]; [self tile];
} }
@@ -593,51 +582,14 @@
index = row * _numberOfColumns + column; index = row * _numberOfColumns + column;
if (index >= 0 && index < _items.length) if (index >= 0 && index < _items.length)
{ [self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
if (_allowsMultipleSelection && ([anEvent modifierFlags] & CPCommandKeyMask || [anEvent modifierFlags] & CPShiftKeyMask))
{
if ([anEvent modifierFlags] & CPCommandKeyMask)
{
var indexes = [_selectionIndexes copy];
if ([indexes containsIndex:index])
[indexes removeIndex:index];
else
[indexes addIndex:index];
}
else if ([anEvent modifierFlags] & CPShiftKeyMask)
{
var firstSelectedIndex = [[self selectionIndexes] firstIndex],
newSelectedRange = nil;
if (index < firstSelectedIndex)
newSelectedRange = CPMakeRange(index, (firstSelectedIndex - index) + 1);
else
newSelectedRange = CPMakeRange(firstSelectedIndex, (index - firstSelectedIndex) + 1);
indexes = [[self selectionIndexes] copy];
[indexes addIndexesInRange:newSelectedRange];
}
}
else
indexes = [CPIndexSet indexSetWithIndex:index];
[self setSelectionIndexes:indexes];
}
else if (_allowsEmptySelection) else if (_allowsEmptySelection)
[self setSelectionIndexes:[CPIndexSet indexSet]]; [self setSelectionIndexes:[CPIndexSet indexSet]];
} }
- (void)mouseDragged:(CPEvent)anEvent - (void)mouseDragged:(CPEvent)anEvent
{ {
var locationInWindow = [anEvent locationInWindow],
mouseDownLocationInWindow = [_mouseDownEvent locationInWindow];
// FIXME: This is because Safari's drag hysteresis is 3px x 3px
if ((ABS(locationInWindow.x - mouseDownLocationInWindow.x) < 3) &&
(ABS(locationInWindow.y - mouseDownLocationInWindow.y) < 3))
return;
if (![_delegate respondsToSelector:@selector(collectionView:dragTypesForItemsAtIndexes:)]) if (![_delegate respondsToSelector:@selector(collectionView:dragTypesForItemsAtIndexes:)])
return; return;
@@ -654,6 +606,8 @@
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:dragTypes owner:self]; [[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:dragTypes owner:self];
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
if (!_itemForDragging) if (!_itemForDragging)
_itemForDragging = [self newItemForRepresentedObject:_content[[_selectionIndexes firstIndex]]]; _itemForDragging = [self newItemForRepresentedObject:_content[[_selectionIndexes firstIndex]]];
else else
@@ -694,9 +648,9 @@
{ {
if (_verticalMargin == aVerticalMargin) if (_verticalMargin == aVerticalMargin)
return; return;
_verticalMargin = aVerticalMargin; _verticalMargin = aVerticalMargin;
[self tile]; [self tile];
} }
@@ -747,7 +701,7 @@
count = [indexArray count]; count = [indexArray count];
for (; index < count; ++index) for (; index < count; ++index)
frame = CGRectUnion(frame, [self frameForItemAtIndex:indexArray[index]]); frame = CGRectUnion(frame, [self rectForItemAtIndex:indexArray[index]]);
return frame; return frame;
} }
@@ -756,29 +710,6 @@
@implementation CPCollectionView (KeyboardInteraction) @implementation CPCollectionView (KeyboardInteraction)
- (void)_modifySelectionWithNewIndex:(int)anIndex direction:(int)aDirection expand:(BOOL)shouldExpand
{
anIndex = MIN(MAX(anIndex, 0), [[self items] count] - 1);
if (_allowsMultipleSelection && shouldExpand)
{
var indexes = [_selectionIndexes copy],
bottomAnchor = [indexes firstIndex],
topAnchor = [indexes lastIndex];
// if the direction is backward (-1) check with the bottom anchor
if (aDirection === -1)
[indexes addIndexesInRange:CPMakeRange(anIndex, bottomAnchor - anIndex + 1)];
else
[indexes addIndexesInRange:CPMakeRange(topAnchor, anIndex - topAnchor + 1)];
}
else
indexes = [CPIndexSet indexSetWithIndex:anIndex];
[self setSelectionIndexes:indexes];
[self _scrollToSelection];
}
- (void)_scrollToSelection - (void)_scrollToSelection
{ {
var frame = [self frameForItemsAtIndexes:[self selectionIndexes]]; var frame = [self frameForItemsAtIndexes:[self selectionIndexes]];
@@ -790,57 +721,41 @@
- (void)moveLeft:(id)sender - (void)moveLeft:(id)sender
{ {
var index = [[self selectionIndexes] firstIndex]; var index = [[self selectionIndexes] firstIndex];
if (index === CPNotFound) if (index === CPNotFound)
index = [[self items] count]; index = [[self items] count];
[self _modifySelectionWithNewIndex:index - 1 direction:-1 expand:NO]; index = MAX(index - 1, 0);
}
- (void)moveLeftAndModifySelection:(id)sender [self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
{ [self _scrollToSelection];
var index = [[self selectionIndexes] firstIndex];
if (index === CPNotFound)
index = [[self items] count];
[self _modifySelectionWithNewIndex:index - 1 direction:-1 expand:YES];
} }
- (void)moveRight:(id)sender - (void)moveRight:(id)sender
{ {
[self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + 1 direction:1 expand:NO]; var index = MIN([[self selectionIndexes] firstIndex] + 1, [[self items] count]-1);
}
- (void)moveRightAndModifySelection:(id)sender [self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
{ [self _scrollToSelection];
[self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + 1 direction:1 expand:YES];
} }
- (void)moveDown:(id)sender - (void)moveDown:(id)sender
{ {
[self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + [self numberOfColumns] direction:1 expand:NO]; var index = MIN([[self selectionIndexes] firstIndex] + [self numberOfColumns], [[self items] count]-1);
}
- (void)moveDownAndModifySelection:(id)sender [self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
{ [self _scrollToSelection];
[self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + [self numberOfColumns] direction:1 expand:YES];
} }
- (void)moveUp:(id)sender - (void)moveUp:(id)sender
{ {
var index = [[self selectionIndexes] firstIndex]; var index = [[self selectionIndexes] firstIndex];
if (index == CPNotFound) if (index == CPNotFound)
index = [[self items] count]; index = [[self items] count];
[self _modifySelectionWithNewIndex:index - [self numberOfColumns] direction:-1 expand:NO]; index = MAX(0, index - [self numberOfColumns]);
}
- (void)moveUpAndModifySelection:(id)sender [self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
{ [self _scrollToSelection];
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 - (void)deleteBackward:(id)sender
@@ -850,8 +765,8 @@
[[self delegate] collectionView:self shouldDeleteItemsAtIndexes:[self selectionIndexes]]; [[self delegate] collectionView:self shouldDeleteItemsAtIndexes:[self selectionIndexes]];
var index = [[self selectionIndexes] firstIndex]; var index = [[self selectionIndexes] firstIndex];
if (index > [[self content] count] - 1) if (index > [[self content] count]-1)
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:[[self content] count] - 1]]; [self setSelectionIndexes:[CPIndexSet indexSetWithIndex:[[self content] count]-1]];
[self _scrollToSelection]; [self _scrollToSelection];
[self setNeedsDisplay:YES]; [self setNeedsDisplay:YES];
@@ -885,14 +800,11 @@
@end @end
var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey", var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
CPCollectionViewMaxItemSizeKey = @"CPCollectionViewMaxItemSizeKey", CPCollectionViewMaxItemSizeKey = @"CPCollectionViewMaxItemSizeKey",
CPCollectionViewVerticalMarginKey = @"CPCollectionViewVerticalMarginKey", CPCollectionViewVerticalMarginKey = @"CPCollectionViewVerticalMarginKey",
CPCollectionViewMaxNumberOfRowsKey = @"CPCollectionViewMaxNumberOfRowsKey", CPCollectionViewSelectableKey = @"CPCollectionViewSelectableKey",
CPCollectionViewMaxNumberOfColumnsKey = @"CPCollectionViewMaxNumberOfColumnsKey", CPCollectionViewBackgroundColorsKey = @"CPCollectionViewBackgroundColorsKey";
CPCollectionViewSelectableKey = @"CPCollectionViewSelectableKey",
CPCollectionViewAllowsMultipleSelectionKey = @"CPCollectionViewAllowsMultipleSelectionKey",
CPCollectionViewBackgroundColorsKey = @"CPCollectionViewBackgroundColorsKey";
@implementation CPCollectionView (CPCoding) @implementation CPCollectionView (CPCoding)
@@ -909,24 +821,20 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeK
_cachedItems = []; _cachedItems = [];
_itemSize = CGSizeMakeZero(); _itemSize = CGSizeMakeZero();
_minItemSize = [aCoder decodeSizeForKey:CPCollectionViewMinItemSizeKey] || CGSizeMakeZero(); _minItemSize = [aCoder decodeSizeForKey:CPCollectionViewMinItemSizeKey] || CGSizeMakeZero();
_maxItemSize = [aCoder decodeSizeForKey:CPCollectionViewMaxItemSizeKey] || CGSizeMakeZero(); _maxItemSize = [aCoder decodeSizeForKey:CPCollectionViewMaxItemSizeKey] || CGSizeMakeZero();
_maxNumberOfRows = [aCoder decodeIntForKey:CPCollectionViewMaxNumberOfRowsKey] || 0;
_maxNumberOfColumns = [aCoder decodeIntForKey:CPCollectionViewMaxNumberOfColumnsKey] || 0;
_verticalMargin = [aCoder decodeFloatForKey:CPCollectionViewVerticalMarginKey]; _verticalMargin = [aCoder decodeFloatForKey:CPCollectionViewVerticalMarginKey];
_isSelectable = [aCoder decodeBoolForKey:CPCollectionViewSelectableKey]; _isSelectable = [aCoder decodeBoolForKey:CPCollectionViewSelectableKey];
_allowsMultipleSelection = [aCoder decodeBoolForKey:CPCollectionViewAllowsMultipleSelectionKey];
[self setBackgroundColors:[aCoder decodeObjectForKey:CPCollectionViewBackgroundColorsKey]]; [self setBackgroundColors:[aCoder decodeObjectForKey:CPCollectionViewBackgroundColorsKey]];
_tileWidth = -1.0; _tileWidth = -1.0;
_selectionIndexes = [CPIndexSet indexSet]; _selectionIndexes = [CPIndexSet indexSet];
_allowsEmptySelection = YES; _allowsEmptySelection = YES;
} }
@@ -939,16 +847,12 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeK
if (!CGSizeEqualToSize(_minItemSize, CGSizeMakeZero())) if (!CGSizeEqualToSize(_minItemSize, CGSizeMakeZero()))
[aCoder encodeSize:_minItemSize forKey:CPCollectionViewMinItemSizeKey]; [aCoder encodeSize:_minItemSize forKey:CPCollectionViewMinItemSizeKey];
if (!CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero())) if (!CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero()))
[aCoder encodeSize:_maxItemSize forKey:CPCollectionViewMaxItemSizeKey]; [aCoder encodeSize:_maxItemSize forKey:CPCollectionViewMaxItemSizeKey];
[aCoder encodeInt:_maxNumberOfRows forKey:CPCollectionViewMaxNumberOfRowsKey];
[aCoder encodeInt:_maxNumberOfColumns forKey:CPCollectionViewMaxNumberOfColumnsKey];
[aCoder encodeBool:_isSelectable forKey:CPCollectionViewSelectableKey]; [aCoder encodeBool:_isSelectable forKey:CPCollectionViewSelectableKey];
[aCoder encodeBool:_allowsMultipleSelection forKey:CPCollectionViewAllowsMultipleSelectionKey];
[aCoder encodeFloat:_verticalMargin forKey:CPCollectionViewVerticalMarginKey]; [aCoder encodeFloat:_verticalMargin forKey:CPCollectionViewVerticalMarginKey];
[aCoder encodeObject:_backgroundColors forKey:CPCollectionViewBackgroundColorsKey]; [aCoder encodeObject:_backgroundColors forKey:CPCollectionViewBackgroundColorsKey];
-1
View File
@@ -22,7 +22,6 @@
@import "CPViewController.j" @import "CPViewController.j"
/*! /*!
Represents an object inside a CPCollectionView. Represents an object inside a CPCollectionView.
*/ */
+91 -87
View File
@@ -32,7 +32,7 @@ var _redComponent = 0,
_greenComponent = 1, _greenComponent = 1,
_blueComponent = 2, _blueComponent = 2,
_alphaCompnent = 3; _alphaCompnent = 3;
var _hueComponent = 0, var _hueComponent = 0,
_saturationComponent = 1, _saturationComponent = 1,
_brightnessComponent = 2; _brightnessComponent = 2;
@@ -54,21 +54,27 @@ var cachedBlackColor,
cachedShadowColor, cachedShadowColor,
cachedClearColor; cachedClearColor;
/*! /*!
@ingroup appkit @ingroup appkit
@code CPColor
\c CPColor can be used to represent color \c CPColor can be used to represent color
in an RGB or HSB model with an optional transparency value.</p> in an RGB or HSB model with an optional transparency value.</p>
<p>It also provides some class helper methods that <p>It also provides some class helper methods that
returns instances of commonly used colors.</p> 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 @implementation CPColor : CPObject
{ {
CPArray _components; CPArray _components;
CPImage _patternImage; CPImage _patternImage;
CPString _cssString; CPString _cssString;
} }
/*! /*!
@@ -76,12 +82,12 @@ var cachedBlackColor,
Each component should be between the range of 0.0 to 1.0. For 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 the alpha component, a value of 1.0 is opaque, and 0.0 means
completely transparent. completely transparent.
@param red the red component of the color @param red the red component of the color
@param green the green component of the color @param green the green component of the color
@param blue the blue component of the color @param blue the blue component of the color
@param alpha the alpha component @param alpha the alpha component
@return a color initialized to the values specified @return a color initialized to the values specified
*/ */
+ (CPColor)colorWithRed:(float)red green:(float)green blue:(float)blue alpha:(float)alpha + (CPColor)colorWithRed:(float)red green:(float)green blue:(float)blue alpha:(float)alpha
@@ -91,17 +97,17 @@ var cachedBlackColor,
/*! /*!
@deprecated in favor of colorWithRed:green:blue:alpha: @deprecated in favor of colorWithRed:green:blue:alpha:
Creates a color in the RGB color space, with an alpha value. 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 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 the alpha component, a value of 1.0 is opaque, and 0.0 means
completely transparent. completely transparent.
@param red the red component of the color @param red the red component of the color
@param green the green component of the color @param green the green component of the color
@param blue the blue component of the color @param blue the blue component of the color
@param alpha the alpha component @param alpha the alpha component
@return a color initialized to the values specified @return a color initialized to the values specified
*/ */
+ (CPColor)colorWithCalibratedRed:(float)red green:(float)green blue:(float)blue alpha:(float)alpha + (CPColor)colorWithCalibratedRed:(float)red green:(float)green blue:(float)blue alpha:(float)alpha
@@ -113,10 +119,10 @@ var cachedBlackColor,
/*! /*!
Creates a new color object with \c white for the RGB components. 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. 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 white a float between 0.0 and 1.0
@param alpha the alpha component 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 @return a color initialized to the values specified
*/ */
+ (CPColor)colorWithWhite:(float)white alpha:(float)alpha + (CPColor)colorWithWhite:(float)white alpha:(float)alpha
@@ -126,13 +132,13 @@ var cachedBlackColor,
/*! /*!
@deprecated in favor of colorWithWhite:apha: @deprecated in favor of colorWithWhite:apha:
Creates a new color object with \c white for the RGB components. 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. 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 white a float between 0.0 and 1.0
@param alpha the alpha component 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 @return a color initialized to the values specified
*/ */
+ (CPColor)colorWithCalibratedWhite:(float)white alpha:(float)alpha + (CPColor)colorWithCalibratedWhite:(float)white alpha:(float)alpha
@@ -142,11 +148,11 @@ var cachedBlackColor,
/*! /*!
Creates a new color in HSB space. Creates a new color in HSB space.
@param hue the hue value @param hue the hue value
@param saturation the saturation value @param saturation the saturation value
@param brightness the brightness value @param brightness the brightness value
@return the initialized color @return the initialized color
*/ */
+ (CPColor)colorWithHue:(float)hue saturation:(float)saturation brightness:(float)brightness + (CPColor)colorWithHue:(float)hue saturation:(float)saturation brightness:(float)brightness
@@ -156,16 +162,16 @@ var cachedBlackColor,
+ (CPColor)colorWithHue:(float)hue saturation:(float)saturation brightness:(float)brightness alpha:(float)alpha + (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]; return [CPColor colorWithCalibratedWhite:brightness / 100.0 alpha:alpha];
var f = hue % 60, var f = hue % 60,
p = (brightness * (100 - saturation)) / 10000, p = (brightness * (100 - saturation)) / 10000,
q = (brightness * (6000 - saturation * f)) / 600000, q = (brightness * (6000 - saturation * f)) / 600000,
t = (brightness * (6000 - saturation * (60 -f))) / 600000, t = (brightness * (6000 - saturation * (60 -f))) / 600000,
b = brightness / 100.0; 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 0: return [CPColor colorWithCalibratedRed: b green: t blue: p alpha: alpha];
case 1: return [CPColor colorWithCalibratedRed: q green: b blue: p alpha: alpha]; case 1: return [CPColor colorWithCalibratedRed: q green: b blue: p alpha: alpha];
@@ -180,7 +186,7 @@ var cachedBlackColor,
Creates an RGB color from a hexadecimal string. For example, Creates an RGB color from a hexadecimal string. For example,
the a string of "FFFFFF" would return a white CPColor. the a string of "FFFFFF" would return a white CPColor.
"FF0000" would return a pure red, "00FF00" would return a "FF0000" would return a pure red, "00FF00" would return a
pure blue, and "0000FF" would return a pure green. pure blue, and "0000FF" would return a pure green.
@param hex a 6 character long string of hex @param hex a 6 character long string of hex
@@ -188,8 +194,7 @@ var cachedBlackColor,
*/ */
+ (CPColor)colorWithHexString:(string)hex + (CPColor)colorWithHexString:(string)hex
{ {
var rgba = hexToRGB(hex); return [[CPColor alloc] _initWithRGBA: hexToRGB(hex)];
return rgba ? [[CPColor alloc] _initWithRGBA: rgba] : null;
} }
/*! /*!
@@ -392,7 +397,7 @@ var cachedBlackColor,
/*! /*!
Creates a CPColor from a valid CSS RGB string. Example, "rgb(32,64,129)". Creates a CPColor from a valid CSS RGB string. Example, "rgb(32,64,129)".
@param aString a CSS color string @param aString a CSS color string
@return a color initialized to the value in the css string @return a color initialized to the value in the css string
*/ */
@@ -404,23 +409,23 @@ var cachedBlackColor,
/* @ignore */ /* @ignore */
- (id)_initWithCSSString:(CPString)aString - (id)_initWithCSSString:(CPString)aString
{ {
if (aString.indexOf("rgb") == CPNotFound) if(aString.indexOf("rgb") == CPNotFound)
return nil; return nil;
self = [super init]; self = [super init];
var startingIndex = aString.indexOf("("), var startingIndex = aString.indexOf("(");
parts = aString.substring(startingIndex + 1).split(','); var parts = aString.substring(startingIndex+1).split(',');
_components = [ _components = [
parseInt(parts[0], 10) / 255.0, parseInt(parts[0], 10) / 255.0,
parseInt(parts[1], 10) / 255.0, parseInt(parts[1], 10) / 255.0,
parseInt(parts[2], 10) / 255.0, parseInt(parts[2], 10) / 255.0,
parts[3] ? parseInt(parts[3], 10) / 255.0 : 1.0 parts[3] ? parseInt(parts[3], 10) / 255.0 : 1.0
]; ]
_cssString = aString; _cssString = aString;
return self; return self;
} }
@@ -428,7 +433,7 @@ var cachedBlackColor,
- (id)_initWithRGBA:(CPArray)components - (id)_initWithRGBA:(CPArray)components
{ {
self = [super init]; self = [super init];
if (self) if (self)
{ {
_components = components; _components = components;
@@ -449,14 +454,14 @@ var cachedBlackColor,
- (id)_initWithPatternImage:(CPImage)anImage - (id)_initWithPatternImage:(CPImage)anImage
{ {
self = [super init]; self = [super init];
if (self) if (self)
{ {
_patternImage = anImage; _patternImage = anImage;
_cssString = "url(\"" + [_patternImage filename] + "\")"; _cssString = "url(\"" + [_patternImage filename] + "\")";
_components = [0.0, 0.0, 0.0, 1.0]; _components = [0.0, 0.0, 0.0, 1.0];
} }
return self; return self;
} }
@@ -518,17 +523,17 @@ var cachedBlackColor,
/*! /*!
Returns a new color with the same RGB as the receiver but a new alpha component. 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 @param anAlphaComponent the alpha component for the new color
@return a new color object @return a new color object
*/ */
- (CPColor)colorWithAlphaComponent:(float)anAlphaComponent - (CPColor)colorWithAlphaComponent:(float)anAlphaComponent
{ {
var components = _components.slice(); var components = _components.slice();
components[components.length - 1] = anAlphaComponent; components[components.length - 1] = anAlphaComponent;
return [[[self class] alloc] _initWithRGBA:components]; return [[[self class] alloc] _initWithRGBA:components];
} }
@@ -547,40 +552,37 @@ var cachedBlackColor,
var red = ROUND(_components[_redComponent] * 255.0), var red = ROUND(_components[_redComponent] * 255.0),
green = ROUND(_components[_greenComponent] * 255.0), green = ROUND(_components[_greenComponent] * 255.0),
blue = ROUND(_components[_blueComponent] * 255.0); blue = ROUND(_components[_blueComponent] * 255.0);
var max = MAX(red, green, blue), var max = MAX(red, green, blue),
min = MIN(red, green, blue), min = MIN(red, green, blue),
delta = max - min; delta = max - min;
var brightness = max / 255.0, var brightness = max / 255.0,
saturation = (max != 0) ? delta / max : 0; saturation = (max != 0) ? delta / max : 0;
var hue; var hue;
if(saturation == 0)
if (saturation == 0)
{
hue = 0; hue = 0;
}
else else
{ {
var rr = (max - red) / delta, var rr = (max - red) / delta;
gr = (max - green) / delta, var gr = (max - green) / delta;
br = (max - blue) / delta; var br = (max - blue) / delta;
if (red == max) if (red == max)
hue = br - gr; hue = br - gr;
else if (green == max) else if (green == max)
hue = 2 + rr - br; hue = 2 + rr - br;
else else
hue = 4 + gr - rr; hue = 4 + gr - rr;
hue /= 6; hue /= 6;
if (hue < 0) if (hue < 0)
hue++; hue++;
} }
return [ return [
ROUND(hue * 360.0), ROUND(hue * 360.0),
ROUND(saturation * 100.0), ROUND(saturation * 100.0),
ROUND(brightness * 100.0) ROUND(brightness * 100.0)
]; ];
@@ -628,7 +630,7 @@ url("data:image/png;base64,BASE64ENCODEDDATA") // if there is a pattern image
@implementation CPColor (CoreGraphicsExtensions) @implementation CPColor (CoreGraphicsExtensions)
/*! /*!
Set's the receiver to be the fill and stroke color in the current graphics context Set's the receiver to be the fill and stroke color in the current graphics context
*/ */
- (void)set - (void)set
@@ -637,16 +639,16 @@ url("data:image/png;base64,BASE64ENCODEDDATA") // if there is a pattern image
[self setStroke]; [self setStroke];
} }
/*! /*!
Set's the receiver to be the fill color in the current graphics context Set's the receiver to be the fill color in the current graphics context
*/ */
- (void)setFill - (void)setFill
{ {
var ctx = [[CPGraphicsContext currentContext] graphicsPort]; var ctx = [[CPGraphicsContext currentContext] graphicsPort];
CGContextSetFillColor(ctx, self); CGContextSetFillColor(ctx, self);
} }
/*! /*!
Set's the receiver to be the stroke color in the current graphics context Set's the receiver to be the stroke color in the current graphics context
*/ */
- (void)setStroke - (void)setStroke
@@ -679,7 +681,7 @@ var CPColorComponentsKey = @"CPColorComponentsKey",
{ {
if ([aCoder containsValueForKey:CPColorPatternImageKey]) if ([aCoder containsValueForKey:CPColorPatternImageKey])
return [self _initWithPatternImage:[aCoder decodeObjectForKey:CPColorPatternImageKey]]; return [self _initWithPatternImage:[aCoder decodeObjectForKey:CPColorPatternImageKey]];
return [self _initWithRGBA:[aCoder decodeObjectForKey:CPColorComponentsKey]]; return [self _initWithRGBA:[aCoder decodeObjectForKey:CPColorComponentsKey]];
} }
@@ -697,48 +699,50 @@ var CPColorComponentsKey = @"CPColorComponentsKey",
@end @end
var hexCharacters = "0123456789ABCDEF"; var hexCharacters = "0123456789ABCDEF";
// HACK: prevent these from becoming globals. workaround for obj-j "function foo(){}" behavior
var hexToRGB, rgbToHex, byteToHex;
/*! /*!
Used for the CPColor \c +colorWithHexString: implementation Used for the CPColor \c +colorWithHexString: implementation
@ignore @ignore
@class CPColor @class CPColor
@return an array of rgb components @return an array of rgb components
*/ */
var hexToRGB = function(hex) function hexToRGB(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); 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; return null;
hex = hex.toUpperCase(); hex = hex.toUpperCase();
for (var i = 0; i < hex.length; i++) for(var i=0; i<hex.length; i++)
if (hexCharacters.indexOf(hex.charAt(i)) == -1) if(hexCharacters.indexOf(hex.charAt(i)) == -1)
return null; return null;
var red = (hexCharacters.indexOf(hex.charAt(0)) * 16 + hexCharacters.indexOf(hex.charAt(1))) / 255.0, var red = (hexCharacters.indexOf(hex.charAt(0)) * 16 + hexCharacters.indexOf(hex.charAt(1))) / 255.0;
green = (hexCharacters.indexOf(hex.charAt(2)) * 16 + hexCharacters.indexOf(hex.charAt(3))) / 255.0, var green = (hexCharacters.indexOf(hex.charAt(2)) * 16 + hexCharacters.indexOf(hex.charAt(3))) / 255.0;
blue = (hexCharacters.indexOf(hex.charAt(4)) * 16 + hexCharacters.indexOf(hex.charAt(5))) / 255.0; var blue = (hexCharacters.indexOf(hex.charAt(4)) * 16 + hexCharacters.indexOf(hex.charAt(5))) / 255.0;
return [red, green, blue, 1.0]; return [red, green, blue, 1.0];
}; }
var rgbToHex = function(r,g,b) function rgbToHex(r,g,b) {
{
return byteToHex(r) + byteToHex(g) + byteToHex(b); return byteToHex(r) + byteToHex(g) + byteToHex(b);
}; }
var byteToHex = function(n) function byteToHex(n) {
{ if (!n || isNaN(n)) return "00";
if (!n || isNaN(n)) n = ROUND(MIN(255,MAX(0,256*n)));
return "00"; return hexCharacters.charAt((n - n % 16) / 16) +
hexCharacters.charAt(n % 16);
}
n = FLOOR(MIN(255, MAX(0, 256 * n))); // Toll-Free bridge CPColor to CGColor.
//CGColor.prototype.isa = CPColor;
//[CPColor initialize];
return hexCharacters.charAt((n - n % 16) / 16) + //http://dev.mootools.net/browser/trunk/Source/Utilities/Color.js?rev=1184
hexCharacters.charAt(n % 16);
};
+80 -83
View File
@@ -20,13 +20,11 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
@import "CPApplication.j"
@import "CPButton.j" @import "CPButton.j"
@import "CPCookie.j" @import "CPCookie.j"
@import "CPPanel.j" @import "CPPanel.j"
@import "CPView.j" @import "CPView.j"
CPColorPanelColorDidChangeNotification = @"CPColorPanelColorDidChangeNotification"; CPColorPanelColorDidChangeNotification = @"CPColorPanelColorDidChangeNotification";
var PREVIEW_HEIGHT = 20.0, var PREVIEW_HEIGHT = 20.0,
@@ -37,7 +35,7 @@ var PREVIEW_HEIGHT = 20.0,
var SharedColorPanel = nil, var SharedColorPanel = nil,
ColorPickerClasses = []; ColorPickerClasses = [];
/* /*
A color wheel A color wheel
@global @global
@@ -54,7 +52,7 @@ CPSliderColorPickerMode = 2;
CPColorPickerViewWidth = 265, CPColorPickerViewWidth = 265,
CPColorPickerViewHeight = 370; CPColorPickerViewHeight = 370;
/*! /*!
@ingroup appkit @ingroup appkit
@class CPColorPanel @class CPColorPanel
@@ -63,7 +61,7 @@ CPColorPickerViewHeight = 370;
obtain the panel, call the \c +sharedColorPanel method. obtain the panel, call the \c +sharedColorPanel method.
*/ */
@implementation CPColorPanel : CPPanel @implementation CPColorPanel : CPPanel
{ {
_CPColorPanelToolbar _toolbar; _CPColorPanelToolbar _toolbar;
_CPColorPanelSwatches _swatchView; _CPColorPanelSwatches _swatchView;
_CPColorPanelPreview _previewView; _CPColorPanelPreview _previewView;
@@ -82,8 +80,8 @@ CPColorPickerViewHeight = 370;
int _mode; 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. any picker in this list up to this point. In other words, call before creating a color panel.
*/ */
+ (void)provideColorPickerClass:(Class)aColorPickerSubclass + (void)provideColorPickerClass:(Class)aColorPickerSubclass
@@ -98,7 +96,7 @@ CPColorPickerViewHeight = 370;
{ {
if (!SharedColorPanel) if (!SharedColorPanel)
SharedColorPanel = [[CPColorPanel alloc] init]; SharedColorPanel = [[CPColorPanel alloc] init];
return SharedColorPanel; return SharedColorPanel;
} }
@@ -109,7 +107,7 @@ CPColorPickerViewHeight = 370;
+ (void)setPickerMode:(CPColorPanelMode)mode + (void)setPickerMode:(CPColorPanelMode)mode
{ {
var panel = [CPColorPanel sharedColorPanel]; var panel = [CPColorPanel sharedColorPanel];
[panel setMode:mode]; [panel setMode: mode];
} }
/* /*
@@ -118,7 +116,7 @@ CPColorPickerViewHeight = 370;
*/ */
- (id)init - (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)]; styleMask:(CPTitledWindowMask | CPClosableWindowMask | CPResizableWindowMask)];
if (self) if (self)
@@ -127,14 +125,14 @@ CPColorPickerViewHeight = 370;
[self setTitle:@"Color Panel"]; [self setTitle:@"Color Panel"];
[self setLevel:CPFloatingWindowLevel]; [self setLevel:CPFloatingWindowLevel];
[self setFloatingPanel:YES]; [self setFloatingPanel:YES];
[self setBecomesKeyOnlyIfNeeded:YES]; [self setBecomesKeyOnlyIfNeeded:YES];
[self setMinSize:CGSizeMake(219.0, 342.0)]; [self setMinSize:CGSizeMake(219.0, 342.0)];
[self setMaxSize:CGSizeMake(323.0, 537.0)]; [self setMaxSize:CGSizeMake(323.0, 537.0)];
} }
return self; return self;
} }
@@ -145,12 +143,12 @@ CPColorPickerViewHeight = 370;
{ {
_color = aColor; _color = aColor;
[_previewView setBackgroundColor: _color]; [_previewView setBackgroundColor: _color];
[CPApp sendAction:@selector(changeColor:) to:nil from:self]; [CPApp sendAction:@selector(changeColor:) to:nil from:self];
if (_target && _action) if (_target && _action)
[CPApp sendAction:_action to:_target from:self]; [CPApp sendAction:_action to:_target from:self];
[[CPNotificationCenter defaultCenter] [[CPNotificationCenter defaultCenter]
postNotificationName:CPColorPanelColorDidChangeNotification postNotificationName:CPColorPanelColorDidChangeNotification
object:self]; object:self];
@@ -167,7 +165,7 @@ CPColorPickerViewHeight = 370;
- (void)setColor:(CPColor)aColor updatePicker:(BOOL)bool - (void)setColor:(CPColor)aColor updatePicker:(BOOL)bool
{ {
[self setColor:aColor]; [self setColor:aColor];
if (bool) if (bool)
[_activePicker setColor:_color]; [_activePicker setColor:_color];
} }
@@ -234,30 +232,30 @@ CPColorPickerViewHeight = 370;
{ {
var picker = _colorPickers[[sender tag]], var picker = _colorPickers[[sender tag]],
view = [picker provideNewView:NO]; view = [picker provideNewView:NO];
if (!view) if (!view)
view = [picker provideNewView:YES]; view = [picker provideNewView:YES];
if (view == _currentView) if (view == _currentView)
return; return;
if (_currentView) if (_currentView)
[view setFrame:[_currentView frame]]; [view setFrame:[_currentView frame]];
else 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]; bounds = [[self contentView] bounds];
[view setFrameSize:CPSizeMake(bounds.size.width - 10, bounds.size.height - height)]; [view setFrameSize: CPSizeMake(bounds.size.width - 10, bounds.size.height - height)];
[view setFrameOrigin:CPPointMake(5, height)]; [view setFrameOrigin: CPPointMake(5, height)];
} }
[_currentView removeFromSuperview]; [_currentView removeFromSuperview];
[[self contentView] addSubview:view]; [[self contentView] addSubview:view];
_currentView = view; _currentView = view;
_activePicker = picker; _activePicker = picker;
[picker setColor:[self color]]; [picker setColor:[self color]];
} }
@@ -287,7 +285,7 @@ CPColorPickerViewHeight = 370;
_colorPickers = []; _colorPickers = [];
var count = [ColorPickerClasses count]; var count = [ColorPickerClasses count];
for (var i = 0; i < count; i++) for (var i=0; i<count; i++)
{ {
var currentPickerClass = ColorPickerClasses[i], var currentPickerClass = ColorPickerClasses[i],
currentPicker = [[currentPickerClass alloc] initWithPickerMask:0 colorPanel:self]; currentPicker = [[currentPickerClass alloc] initWithPickerMask:0 colorPanel:self];
@@ -299,29 +297,29 @@ CPColorPickerViewHeight = 370;
bounds = [contentView bounds]; bounds = [contentView bounds];
_toolbar = [[CPView alloc] initWithFrame:CGRectMake(0, 6, CGRectGetWidth(bounds), TOOLBAR_HEIGHT)]; _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, var totalToolbarWidth = count * ICON_WIDTH + (count - 1) * ICON_PADDING,
leftOffset = (CGRectGetWidth(bounds) - totalToolbarWidth) / 2.0, leftOffset = (CGRectGetWidth(bounds) - totalToolbarWidth) / 2.0,
buttonForLater = nil; buttonForLater = nil;
for (var i = 0; i < count; i++) for (var i=0; i<count; i++)
{ {
var image = [_colorPickers[i] provideNewButtonImage], var image = [_colorPickers[i] provideNewButtonImage],
highlightImage = [_colorPickers[i] provideNewAlternateButtonImage], 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 setTag:i];
[button setTarget:self]; [button setTarget:self];
[button setAction:@selector(_setPicker:)]; [button setAction:@selector(_setPicker:)];
[button setBordered:NO]; [button setBordered:NO];
[button setAutoresizingMask:CPViewMinXMargin | CPViewMaxXMargin]; [button setAutoresizingMask:CPViewMinXMargin|CPViewMaxXMargin];
[button setImage:image]; [button setImage:image];
[button setAlternateImage:highlightImage]; [button setAlternateImage:highlightImage];
[_toolbar addSubview:button]; [_toolbar addSubview:button];
if (!buttonForLater) if (!buttonForLater)
buttonForLater = button; buttonForLater = button;
} }
@@ -332,7 +330,7 @@ CPColorPickerViewHeight = 370;
_previewView = [[_CPColorPanelPreview alloc] initWithFrame:CGRectInset([previewBox bounds], 2.0, 2.0)]; _previewView = [[_CPColorPanelPreview alloc] initWithFrame:CGRectInset([previewBox bounds], 2.0, 2.0)];
[_previewView setColorPanel:self]; [_previewView setColorPanel:self];
[_previewView setAutoresizingMask:CPViewWidthSizable]; [_previewView setAutoresizingMask:CPViewWidthSizable];
[previewBox setBackgroundColor:[CPColor colorWithWhite:0.8 alpha:1.0]]; [previewBox setBackgroundColor:[CPColor colorWithWhite:0.8 alpha:1.0]];
[previewBox setAutoresizingMask:CPViewWidthSizable]; [previewBox setAutoresizingMask:CPViewWidthSizable];
@@ -340,7 +338,7 @@ CPColorPickerViewHeight = 370;
[previewBox addSubview:_previewView]; [previewBox addSubview:_previewView];
var _previewLabel = [[CPTextField alloc] initWithFrame: CPRectMake(10, TOOLBAR_HEIGHT + 10, 60, 15)]; var _previewLabel = [[CPTextField alloc] initWithFrame: CPRectMake(10, TOOLBAR_HEIGHT + 10, 60, 15)];
[_previewLabel setStringValue:"Preview:"]; [_previewLabel setStringValue: "Preview:"];
[_previewLabel setTextColor:[CPColor blackColor]]; [_previewLabel setTextColor:[CPColor blackColor]];
[_previewLabel setAlignment:CPRightTextAlignment]; [_previewLabel setAlignment:CPRightTextAlignment];
@@ -352,8 +350,8 @@ CPColorPickerViewHeight = 370;
_swatchView = [[_CPColorPanelSwatches alloc] initWithFrame:CGRectInset([swatchBox bounds], 1.0, 1.0)]; _swatchView = [[_CPColorPanelSwatches alloc] initWithFrame:CGRectInset([swatchBox bounds], 1.0, 1.0)];
[_swatchView setColorPanel:self]; [_swatchView setColorPanel: self];
[_swatchView setAutoresizingMask:CPViewWidthSizable]; [_swatchView setAutoresizingMask: CPViewWidthSizable];
[swatchBox addSubview:_swatchView]; [swatchBox addSubview:_swatchView];
@@ -369,7 +367,7 @@ CPColorPickerViewHeight = 370;
[opacityLabel setAlignment:CPRightTextAlignment]; [opacityLabel setAlignment:CPRightTextAlignment];
_opacitySlider = [[CPSlider alloc] initWithFrame:CGRectMake(76, TOOLBAR_HEIGHT + PREVIEW_HEIGHT + 34, CGRectGetWidth(bounds) - 86, 20.0)]; _opacitySlider = [[CPSlider alloc] initWithFrame:CGRectMake(76, TOOLBAR_HEIGHT + PREVIEW_HEIGHT + 34, CGRectGetWidth(bounds) - 86, 20.0)];
[_opacitySlider setMinValue:0.0]; [_opacitySlider setMinValue:0.0];
[_opacitySlider setMaxValue:1.0]; [_opacitySlider setMaxValue:1.0];
@@ -417,37 +415,37 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
CPCookie _swatchCookie; CPCookie _swatchCookie;
} }
- (id)initWithFrame:(CPRect)aFrame -(id)initWithFrame:(CPRect)aFrame
{ {
self = [super initWithFrame:aFrame]; self = [super initWithFrame:aFrame];
[self setBackgroundColor: [CPColor grayColor]]; [self setBackgroundColor: [CPColor grayColor]];
[self registerForDraggedTypes:[CPArray arrayWithObjects:CPColorDragType]]; [self registerForDraggedTypes:[CPArray arrayWithObjects:CPColorDragType]];
var whiteColor = [CPColor whiteColor]; var whiteColor = [CPColor whiteColor];
_swatchCookie = [[CPCookie alloc] initWithName: CPColorPanelSwatchesCookie]; _swatchCookie = [[CPCookie alloc] initWithName: CPColorPanelSwatchesCookie];
var colorList = [self startingColorList]; var colorList = [self startingColorList];
_swatches = []; _swatches = [];
for (var i = 0; i < 50; i++) for(var i=0; i < 50; i++)
{ {
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox // FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
var view = [[CPView alloc] initWithFrame: CPRectMake(13 * i + 1, 1, 12, 12)], var view = [[CPView alloc] initWithFrame: CPRectMake(13*i+1, 1, 12, 12)],
fillView = [[CPView alloc] initWithFrame:CGRectInset([view bounds], 1.0, 1.0)]; fillView = [[CPView alloc] initWithFrame:CGRectInset([view bounds], 1.0, 1.0)];
[view setBackgroundColor:whiteColor]; [view setBackgroundColor:whiteColor];
[fillView setBackgroundColor: (i < colorList.length) ? colorList[i] : whiteColor]; [fillView setBackgroundColor: (i < colorList.length) ? colorList[i] : whiteColor];
[view addSubview:fillView]; [view addSubview:fillView];
[self addSubview: view]; [self addSubview: view];
_swatches.push(view); _swatches.push(view);
} }
return self; return self;
} }
@@ -459,8 +457,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
- (CPArray)startingColorList - (CPArray)startingColorList
{ {
var cookieValue = [_swatchCookie value]; var cookieValue = [_swatchCookie value];
if(cookieValue == "")
if (cookieValue == "")
{ {
return [ return [
[CPColor blackColor], [CPColor blackColor],
@@ -474,11 +471,11 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
[CPColor yellowColor] [CPColor yellowColor]
]; ];
} }
var cookieValue = eval(cookieValue), var cookieValue = eval(cookieValue);
result = []; var result = [];
for (var i = 0; i < cookieValue.length; i++) for(var i=0; i<cookieValue.length; i++)
result.push([CPColor colorWithHexString: cookieValue[i]]); result.push([CPColor colorWithHexString: cookieValue[i]]);
return result; return result;
@@ -488,12 +485,12 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
{ {
var result = []; var result = [];
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox // FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
for (var i = 0; i < _swatches.length; i++) for(var i=0; i<_swatches.length; i++)
result.push([[[_swatches[i] subviews][0] backgroundColor] hexString]); result.push([[[_swatches[i] subviews][0] backgroundColor] hexString]);
var future = new Date(); var future = new Date();
future.setYear(2019); future.setYear(2019);
[_swatchCookie setValue: JSON.stringify(result) expires:future domain: nil]; [_swatchCookie setValue: JSON.stringify(result) expires:future domain: nil];
} }
@@ -523,8 +520,8 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
{ {
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil], var point = [self convertPoint:[anEvent locationInWindow] fromView:nil],
bounds = [self bounds]; bounds = [self bounds];
if (!CGRectContainsPoint(bounds, point) || point.x > [self bounds].size.width - 1 || point.x < 1) if(!CGRectContainsPoint(bounds, point) || point.x > [self bounds].size.width - 1 || point.x < 1)
return NO; return NO;
[_colorPanel setColor: [self colorAtIndex:FLOOR(point.x / 13)] updatePicker: YES]; [_colorPanel setColor: [self colorAtIndex:FLOOR(point.x / 13)] updatePicker: YES];
@@ -538,21 +535,21 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
return NO; return NO;
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:[CPArray arrayWithObject:CPColorDragType] owner:self]; [[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:[CPArray arrayWithObject:CPColorDragType] owner:self];
var swatch = _swatches[FLOOR(point.x / 13)]; var swatch = _swatches[FLOOR(point.x / 13)];
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox // FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
_dragColor = [[swatch subviews][0] backgroundColor]; _dragColor = [[swatch subviews][0] backgroundColor];
var bounds = CPRectCreateCopy([swatch bounds]); var bounds = CPRectCreateCopy([swatch bounds]);
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox // 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)]; dragFillView = [[CPView alloc] initWithFrame:CGRectInset(bounds, 1.0, 1.0)];
[dragView setBackgroundColor:[CPColor blackColor]]; [dragView setBackgroundColor:[CPColor blackColor]];
[dragFillView setBackgroundColor:_dragColor]; [dragFillView setBackgroundColor:_dragColor];
[dragView addSubview:dragFillView]; [dragView addSubview:dragFillView];
[self dragView: dragView [self dragView: dragView
@@ -566,19 +563,19 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType - (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
{ {
if (aType == CPColorDragType) if(aType == CPColorDragType)
[aPasteboard setData:[CPKeyedArchiver archivedDataWithRootObject:_dragColor] forType:aType]; [aPasteboard setData:[CPKeyedArchiver archivedDataWithRootObject:_dragColor] forType:aType];
} }
- (void)performDragOperation:(id <CPDraggingInfo>)aSender - (void)performDragOperation:(id <CPDraggingInfo>)aSender
{ {
var location = [self convertPoint:[aSender draggingLocation] fromView:nil], var location = [self convertPoint:[aSender draggingLocation] fromView:nil],
pasteboard = [aSender draggingPasteboard], pasteboard = [aSender draggingPasteboard],
swatch = nil; swatch = nil;
if (![pasteboard availableTypeFromArray:[CPColorDragType]] || location.x > [self bounds].size.width - 1 || location.x < 1) if(![pasteboard availableTypeFromArray:[CPColorDragType]] || location.x > [self bounds].size.width - 1 || location.x < 1)
return NO; return NO;
[self setColor:[CPKeyedUnarchiver unarchiveObjectWithData:[pasteboard dataForType:CPColorDragType]] atIndex: FLOOR(location.x / 13)]; [self setColor:[CPKeyedUnarchiver unarchiveObjectWithData:[pasteboard dataForType:CPColorDragType]] atIndex: FLOOR(location.x / 13)];
} }
@@ -593,9 +590,9 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
- (id)initWithFrame:(CPRect)aFrame - (id)initWithFrame:(CPRect)aFrame
{ {
self = [super initWithFrame:aFrame]; self = [super initWithFrame:aFrame];
[self registerForDraggedTypes:[CPArray arrayWithObjects:CPColorDragType]]; [self registerForDraggedTypes:[CPArray arrayWithObjects:CPColorDragType]];
return self; return self;
} }
@@ -613,9 +610,9 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
{ {
var pasteboard = [aSender draggingPasteboard]; var pasteboard = [aSender draggingPasteboard];
if (![pasteboard availableTypeFromArray:[CPColorDragType]]) if(![pasteboard availableTypeFromArray:[CPColorDragType]])
return NO; return NO;
var color = [CPKeyedUnarchiver unarchiveObjectWithData:[pasteboard dataForType:CPColorDragType]]; var color = [CPKeyedUnarchiver unarchiveObjectWithData:[pasteboard dataForType:CPColorDragType]];
[_colorPanel setColor:color updatePicker:YES]; [_colorPanel setColor:color updatePicker:YES];
} }
@@ -629,19 +626,19 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
{ {
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil]; 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); var bounds = CPRectMake(0, 0, 15, 15);
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox // 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)]; dragFillView = [[CPView alloc] initWithFrame:CGRectInset(bounds, 1.0, 1.0)];
[dragView setBackgroundColor:[CPColor blackColor]]; [dragView setBackgroundColor:[CPColor blackColor]];
[dragFillView setBackgroundColor:[self backgroundColor]]; [dragFillView setBackgroundColor:[self backgroundColor]];
[dragView addSubview:dragFillView]; [dragView addSubview:dragFillView];
[self dragView: dragView [self dragView: dragView
at: CPPointMake(point.x - bounds.size.width / 2.0, point.y - bounds.size.height / 2.0) at: CPPointMake(point.x - bounds.size.width / 2.0, point.y - bounds.size.height / 2.0)
offset: CPPointMake(0.0, 0.0) offset: CPPointMake(0.0, 0.0)
@@ -653,7 +650,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType - (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
{ {
if (aType == CPColorDragType) if(aType == CPColorDragType)
[aPasteboard setData:[CPKeyedArchiver archivedDataWithRootObject:[self backgroundColor]] forType:aType]; [aPasteboard setData:[CPKeyedArchiver archivedDataWithRootObject:[self backgroundColor]] forType:aType];
} }
+39 -36
View File
@@ -21,11 +21,11 @@
*/ */
@import <Foundation/CPObject.j> @import <Foundation/CPObject.j>
@import "CPColorPanel.j"
@import "CPView.j" #include "Platform/Platform.h"
/*!
/*!
@ingroup appkit @ingroup appkit
@class CPColorPicker @class CPColorPicker
@@ -102,18 +102,18 @@
CPColor _cachedColor; CPColor _cachedColor;
} }
- (id)initWithPickerMask:(int)mask colorPanel:(CPColorPanel)owningColorPanel - (id)initWithPickerMask:(int)mask colorPanel:(CPColorPanel)owningColorPanel
{ {
return [super initWithPickerMask:mask colorPanel: owningColorPanel]; return [super initWithPickerMask:mask colorPanel: owningColorPanel];
} }
- (id)initView -(id)initView
{ {
aFrame = CPRectMake(0, 0, CPColorPickerViewWidth, CPColorPickerViewHeight); aFrame = CPRectMake(0, 0, CPColorPickerViewWidth, CPColorPickerViewHeight);
_pickerView = [[CPView alloc] initWithFrame:aFrame]; _pickerView = [[CPView alloc] initWithFrame:aFrame];
[_pickerView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]; [_pickerView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
_brightnessSlider = [[CPSlider alloc] initWithFrame:CGRectMake(0, (aFrame.size.height - 34), aFrame.size.width, 15)]; _brightnessSlider = [[CPSlider alloc] initWithFrame:CGRectMake(0, (aFrame.size.height - 34), aFrame.size.width, 15)];
@@ -136,17 +136,17 @@
[_pickerView addSubview:_brightnessSlider]; [_pickerView addSubview:_brightnessSlider];
} }
- (void)brightnessSliderDidChange:(id)sender -(void)brightnessSliderDidChange:(id)sender
{ {
[self updateColor]; [self updateColor];
} }
- (void)colorWheelDidChange:(id)sender -(void)colorWheelDidChange:(id)sender
{ {
[self updateColor]; [self updateColor];
} }
- (void)updateColor -(void)updateColor
{ {
var hue = [_hueSaturationView angle], var hue = [_hueSaturationView angle],
saturation = [_hueSaturationView distance], saturation = [_hueSaturationView distance],
@@ -223,7 +223,7 @@
float _radius; float _radius;
} }
- (id)initWithFrame:(CPRect)aFrame -(id)initWithFrame:(CPRect)aFrame
{ {
self = [super initWithFrame:aFrame]; self = [super initWithFrame:aFrame];
@@ -261,19 +261,19 @@
return self; return self;
} }
- (void)setWheelBrightness:(float)brightness -(void)setWheelBrightness:(float)brightness
{ {
_blackWheelImage.style.opacity = 1.0 - brightness; _blackWheelImage.style.opacity = 1.0 - brightness;
_blackWheelImage.style.filter = "alpha(opacity=" + (1.0 - brightness) * 100 + ")" _blackWheelImage.style.filter = "alpha(opacity=" + (1.0 - brightness)*100 + ")"
} }
- (void)setFrameSize:(CPSize)aSize -(void)setFrameSize:(CPSize)aSize
{ {
[super setFrameSize:aSize]; [super setFrameSize:aSize];
[self setWheelSize:aSize]; [self setWheelSize:aSize];
} }
- (void)setWheelSize:(CPSize)aSize -(void)setWheelSize:(CPSize)aSize
{ {
var min = MIN(aSize.width, aSize.height); var min = MIN(aSize.width, aSize.height);
@@ -296,55 +296,57 @@
[self setAngle:[self degreesToRadians:_angle] distance:(_distance / 100.0) * _radius]; [self setAngle:[self degreesToRadians:_angle] distance:(_distance / 100.0) * _radius];
} }
- (void)setDelegate:(id)aDelegate -(void)setDelegate:(id)aDelegate
{ {
_delegate = aDelegate; _delegate = aDelegate;
} }
- (id)delegate -(id)delegate
{ {
return _delegate; return _delegate;
} }
- (float)angle -(float)angle
{ {
return _angle; return _angle;
} }
- (float)distance -(float)distance
{ {
return _distance; return _distance;
} }
- (void)mouseDown:(CPEvent)anEvent -(void)mouseDown:(CPEvent)anEvent
{ {
[self reposition:anEvent]; [self reposition:anEvent];
} }
- (void)mouseDragged:(CPEvent)anEvent -(void)mouseDragged:(CPEvent)anEvent
{ {
[self reposition:anEvent]; [self reposition:anEvent];
} }
- (void)reposition:(CPEvent)anEvent -(void)reposition:(CPEvent)anEvent
{ {
var bounds = [self bounds], var bounds = [self bounds],
location = [self convertPoint:[anEvent locationInWindow] fromView:nil], location = [self convertPoint:[anEvent locationInWindow] fromView:nil];
midX = CGRectGetMidX(bounds),
midY = CGRectGetMidY(bounds), var midX = CGRectGetMidX(bounds);
distance = MIN(SQRT((location.x - midX) * (location.x - midX) + (location.y - midY) * (location.y - midY)), _radius), var midY = CGRectGetMidY(bounds);
angle = ATAN2(location.y - midY, location.x - midX);
var distance = MIN(SQRT((location.x - midX)*(location.x - midX) + (location.y - midY)*(location.y - midY)), _radius);
var angle = ATAN2(location.y - midY, location.x - midX);
[self setAngle:angle distance:distance]; [self setAngle:angle distance:distance];
[_delegate colorWheelDidChange:self]; [_delegate colorWheelDidChange:self];
} }
- (void)setAngle:(int)angle distance:(float)distance -(void)setAngle:(int)angle distance:(float)distance
{ {
var bounds = [self bounds], var bounds = [self bounds];
midX = CGRectGetMidX(bounds), var midX = CGRectGetMidX(bounds);
midY = CGRectGetMidY(bounds); var midY = CGRectGetMidY(bounds);
_angle = [self radiansToDegrees:angle]; _angle = [self radiansToDegrees:angle];
_distance = (distance / _radius) * 100.0; _distance = (distance / _radius) * 100.0;
@@ -352,22 +354,23 @@
[_crosshair setFrameOrigin:CPPointMake(COS(angle) * distance + midX - 2.0, SIN(angle) * distance + midY - 2.0)]; [_crosshair setFrameOrigin:CPPointMake(COS(angle) * distance + midX - 2.0, SIN(angle) * distance + midY - 2.0)];
} }
- (void)setPositionToColor:(CPColor)aColor -(void)setPositionToColor:(CPColor)aColor
{ {
var hsb = [aColor hsbComponents], var hsb = [aColor hsbComponents],
bounds = [self bounds], bounds = [self bounds];
angle = [self degreesToRadians:hsb[0]],
var angle = [self degreesToRadians:hsb[0]],
distance = (hsb[1] / 100.0) * _radius; distance = (hsb[1] / 100.0) * _radius;
[self setAngle:angle distance:distance]; [self setAngle:angle distance:distance];
} }
- (int)radiansToDegrees:(float)radians -(int)radiansToDegrees:(float)radians
{ {
return ((-radians / PI) * 180 + 360) % 360; return ((-radians / PI) * 180 + 360) % 360;
} }
- (float)degreesToRadians:(float)degrees -(float)degreesToRadians:(float)degrees
{ {
return -(((degrees - 360) / 180) * PI); return -(((degrees - 360) / 180) * PI);
} }
+30 -36
View File
@@ -29,7 +29,7 @@
var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiveNotification"; var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiveNotification";
/*! /*!
@ingroup appkit @ingroup appkit
@class CPColorWell @class CPColorWell
@@ -41,7 +41,7 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
{ {
BOOL _active; BOOL _active;
BOOL _bordered; BOOL _bordered;
CPColor _color; CPColor _color;
CPView _wellView; CPView _wellView;
} }
@@ -49,19 +49,19 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
- (id)initWithFrame:(CGRect)aFrame - (id)initWithFrame:(CGRect)aFrame
{ {
self = [super initWithFrame:aFrame]; self = [super initWithFrame:aFrame];
if (self) if (self)
{ {
_active = NO; _active = NO;
_bordered = YES; _bordered = YES;
_color = [CPColor whiteColor]; _color = [CPColor whiteColor];
[self drawBezelWithHighlight:NO]; [self drawBezelWithHighlight:NO];
[self drawWellInside:CGRectInset([self bounds], 3.0, 3.0)]; [self drawWellInside:CGRectInset([self bounds], 3.0, 3.0)];
[self _registerForNotifications]; [self _registerForNotifications];
} }
return self; return self;
} }
@@ -97,9 +97,9 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
{ {
if (_bordered == bordered) if (_bordered == bordered)
return; return;
_bordered = bordered; _bordered = bordered;
[self drawWellInside:CGRectInset([self bounds], 3.0, 3.0)]; [self drawWellInside:CGRectInset([self bounds], 3.0, 3.0)];
} }
@@ -120,9 +120,9 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
{ {
if (_color == aColor) if (_color == aColor)
return; return;
_color = aColor; _color = aColor;
[self drawWellInside:CGRectInset([self bounds], 3.0, 3.0)]; [self drawWellInside:CGRectInset([self bounds], 3.0, 3.0)];
} }
@@ -137,7 +137,7 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
// Activating and Deactivating Color Wells // Activating and Deactivating Color Wells
/*! /*!
Activates the color well, displays the color panel, and makes the panel's current color the same as its own. Activates the color well, displays the color panel, and makes the panel's current color the same as its own.
If exclusive is \c YES, deactivates any other CPColorWells. \c NO, keeps them active. If exclusive is \c YES, deactivates any other CPColorWells. \c NO, keeps them active.
@param shouldBeExclusive whether other color wells should be deactivated. @param shouldBeExclusive whether other color wells should be deactivated.
*/ */
@@ -152,9 +152,9 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
if ([self isActive]) if ([self isActive])
return; return;
_active = YES; _active = YES;
[[CPNotificationCenter defaultCenter] [[CPNotificationCenter defaultCenter]
addObserver:self addObserver:self
selector:@selector(colorPanelDidChangeColor:) selector:@selector(colorPanelDidChangeColor:)
@@ -169,9 +169,9 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
{ {
if (![self isActive]) if (![self isActive])
return; return;
_active = NO; _active = NO;
[[CPNotificationCenter defaultCenter] [[CPNotificationCenter defaultCenter]
removeObserver:self removeObserver:self
name:CPColorPanelColorDidChangeNotification name:CPColorPanelColorDidChangeNotification
@@ -202,19 +202,19 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
{ {
_wellView = [[CPView alloc] initWithFrame:aRect]; _wellView = [[CPView alloc] initWithFrame:aRect];
[_wellView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]; [_wellView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
[self addSubview:_wellView]; [self addSubview:_wellView];
} }
else else
[_wellView setFrame:aRect]; [_wellView setFrame:aRect];
[_wellView setBackgroundColor:_color]; [_wellView setBackgroundColor:_color];
} }
- (void)colorPanelDidChangeColor:(CPNotification)aNotification - (void)colorPanelDidChangeColor:(CPNotification)aNotification
{ {
[self takeColorFrom:[aNotification object]]; [self takeColorFrom:[aNotification object]];
[self sendAction:[self action] to:[self target]]; [self sendAction:[self action] to:[self target]];
} }
@@ -231,31 +231,25 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
- (void)mouseDown:(CPEvent)anEvent - (void)mouseDown:(CPEvent)anEvent
{ {
if (![self isEnabled])
return;
[self drawBezelWithHighlight:YES]; [self drawBezelWithHighlight:YES];
} }
- (void)mouseDragged:(CPEvent)anEvent - (void)mouseDragged:(CPEvent)anEvent
{ {
if (![self isEnabled])
return;
[self drawBezelWithHighlight:CGRectContainsPoint([self bounds], [self convertPoint:[anEvent locationInWindow] fromView:nil])]; [self drawBezelWithHighlight:CGRectContainsPoint([self bounds], [self convertPoint:[anEvent locationInWindow] fromView:nil])];
} }
- (void)mouseUp:(CPEvent)anEvent -(void)mouseUp:(CPEvent)anEvent
{ {
[self drawBezelWithHighlight:NO]; [self drawBezelWithHighlight:NO];
if (!CGRectContainsPoint([self bounds], [self convertPoint:[anEvent locationInWindow] fromView:nil]) || ![self isEnabled]) if (!CGRectContainsPoint([self bounds], [self convertPoint:[anEvent locationInWindow] fromView:nil]))
return; return;
[self activate:YES]; [self activate:YES];
var colorPanel = [CPColorPanel sharedColorPanel]; var colorPanel = [CPColorPanel sharedColorPanel];
[colorPanel setColor:_color]; [colorPanel setColor:_color];
[colorPanel orderFront:self]; [colorPanel orderFront:self];
} }
@@ -274,11 +268,11 @@ var CPColorWellColorKey = "CPColorWellColorKey",
- (id)initWithCoder:(CPCoder)aCoder - (id)initWithCoder:(CPCoder)aCoder
{ {
self = [super initWithCoder:aCoder]; self = [super initWithCoder:aCoder];
if (self) if (self)
{ {
_active = NO; _active = NO;
_bordered = [aCoder decodeBoolForKey:CPColorWellBorderedKey]; _bordered = [aCoder decodeObjectForKey:CPColorWellBorderedKey];
_color = [aCoder decodeObjectForKey:CPColorWellColorKey]; _color = [aCoder decodeObjectForKey:CPColorWellColorKey];
[self drawBezelWithHighlight:NO]; [self drawBezelWithHighlight:NO];
@@ -286,7 +280,7 @@ var CPColorWellColorKey = "CPColorWellColorKey",
[self _registerForNotifications]; [self _registerForNotifications];
} }
return self; return self;
} }
@@ -296,17 +290,17 @@ var CPColorWellColorKey = "CPColorWellColorKey",
*/ */
- (void)encodeWithCoder:(CPCoder)aCoder - (void)encodeWithCoder:(CPCoder)aCoder
{ {
// We do this in order to avoid encoding the _wellView, which // We do this in order to avoid encoding the _wellView, which
// should just automatically be created programmatically as needed. // should just automatically be created programmatically as needed.
var actualSubviews = _subviews; var actualSubviews = _subviews;
_subviews = [_subviews copy]; _subviews = [_subviews copy];
[_subviews removeObjectIdenticalTo:_wellView]; [_subviews removeObjectIdenticalTo:_wellView];
[super encodeWithCoder:aCoder]; [super encodeWithCoder:aCoder];
_subviews = actualSubviews; _subviews = actualSubviews;
[aCoder encodeObject:_color forKey:CPColorWellColorKey]; [aCoder encodeObject:_color forKey:CPColorWellColorKey];
[aCoder encodeObject:_bordered forKey:CPColorWellBorderedKey]; [aCoder encodeObject:_bordered forKey:CPColorWellBorderedKey];
} }
+15 -16
View File
@@ -23,7 +23,6 @@
@import "CPEvent.j" @import "CPEvent.j"
@import "CPPlatform.j" @import "CPPlatform.j"
// Browser Engines // Browser Engines
CPUnknownBrowserEngine = 0; CPUnknownBrowserEngine = 0;
CPGeckoBrowserEngine = 1; CPGeckoBrowserEngine = 1;
@@ -78,23 +77,23 @@ if (typeof window !== "undefined" && typeof window.navigator !== "undefined")
USER_AGENT = window.navigator.userAgent; USER_AGENT = window.navigator.userAgent;
// Opera // Opera
if (typeof window !== "undefined" && window.opera) if (window.opera)
{ {
PLATFORM_ENGINE = CPOperaBrowserEngine; PLATFORM_ENGINE = CPOperaBrowserEngine;
PLATFORM_FEATURES |= CPJavaScriptCanvasDrawFeature; PLATFORM_FEATURES |= CPJavaScriptCanvasDrawFeature;
} }
// Internet Explorer // Internet Explorer
else if (typeof window !== "undefined" && window.attachEvent) // Must follow Opera check. else if (window.attachEvent) // Must follow Opera check.
{ {
PLATFORM_ENGINE = CPInternetExplorerBrowserEngine; PLATFORM_ENGINE = CPInternetExplorerBrowserEngine;
// Features we can only be sure of with IE (no known independent tests) // Features we can only be sure of with IE (no known independent tests)
PLATFORM_FEATURES |= CPVMLFeature; PLATFORM_FEATURES |= CPVMLFeature;
PLATFORM_FEATURES |= CPJavascriptRemedialKeySupport; PLATFORM_FEATURES |= CPJavascriptRemedialKeySupport;
PLATFORM_FEATURES |= CPJavaScriptShadowFeature; PLATFORM_FEATURES |= CPJavaScriptShadowFeature;
PLATFORM_FEATURES |= CPOpacityRequiresFilterFeature; PLATFORM_FEATURES |= CPOpacityRequiresFilterFeature;
PLATFORM_FEATURES &= ~CPInputTypeCanBeChangedFeature; PLATFORM_FEATURES &= ~CPInputTypeCanBeChangedFeature;
@@ -104,7 +103,7 @@ else if (typeof window !== "undefined" && window.attachEvent) // Must follow Ope
else if (USER_AGENT.indexOf("AppleWebKit/") != -1) else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
{ {
PLATFORM_ENGINE = CPWebKitBrowserEngine; PLATFORM_ENGINE = CPWebKitBrowserEngine;
// Features we can only be sure of with WebKit (no known independent tests) // Features we can only be sure of with WebKit (no known independent tests)
PLATFORM_FEATURES |= CPCSSRGBAFeature; PLATFORM_FEATURES |= CPCSSRGBAFeature;
PLATFORM_FEATURES |= CPHTMLContentEditableFeature; PLATFORM_FEATURES |= CPHTMLContentEditableFeature;
@@ -115,7 +114,7 @@ else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
PLATFORM_FEATURES |= CPJavascriptClipboardEventsFeature; PLATFORM_FEATURES |= CPJavascriptClipboardEventsFeature;
PLATFORM_FEATURES |= CPJavascriptClipboardAccessFeature; PLATFORM_FEATURES |= CPJavascriptClipboardAccessFeature;
PLATFORM_FEATURES |= CPJavaScriptShadowFeature; PLATFORM_FEATURES |= CPJavaScriptShadowFeature;
var versionStart = USER_AGENT.indexOf("AppleWebKit/") + "AppleWebKit/".length, var versionStart = USER_AGENT.indexOf("AppleWebKit/") + "AppleWebKit/".length,
versionEnd = USER_AGENT.indexOf(" ", versionStart), versionEnd = USER_AGENT.indexOf(" ", versionStart),
versionString = USER_AGENT.substring(versionStart, versionEnd), versionString = USER_AGENT.substring(versionStart, versionEnd),
@@ -123,7 +122,7 @@ else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
majorVersion = parseInt(versionString.substring(0, versionDivision)), majorVersion = parseInt(versionString.substring(0, versionDivision)),
minorVersion = parseInt(versionString.substr(versionDivision + 1)); minorVersion = parseInt(versionString.substr(versionDivision + 1));
if ((USER_AGENT.indexOf("Safari") !== CPNotFound && (majorVersion > 525 || (majorVersion === 525 && minorVersion > 14))) || USER_AGENT.indexOf("Chrome") !== CPNotFound) if((USER_AGENT.indexOf("Safari") !== CPNotFound && (majorVersion > 525 || (majorVersion === 525 && minorVersion > 14))) || USER_AGENT.indexOf("Chrome") !== CPNotFound)
PLATFORM_FEATURES |= CPJavascriptRemedialKeySupport; PLATFORM_FEATURES |= CPJavascriptRemedialKeySupport;
// FIXME this is a terrible hack to get around this bug: // FIXME this is a terrible hack to get around this bug:
@@ -145,12 +144,12 @@ else if (USER_AGENT.indexOf("KHTML") != -1) // Must follow WebKit check.
else if (USER_AGENT.indexOf("Gecko") !== -1) // Must follow KHTML check. else if (USER_AGENT.indexOf("Gecko") !== -1) // Must follow KHTML check.
{ {
PLATFORM_ENGINE = CPGeckoBrowserEngine; PLATFORM_ENGINE = CPGeckoBrowserEngine;
PLATFORM_FEATURES |= CPJavaScriptCanvasDrawFeature; PLATFORM_FEATURES |= CPJavaScriptCanvasDrawFeature;
var index = USER_AGENT.indexOf("Firefox"), var index = USER_AGENT.indexOf("Firefox"),
version = (index === -1) ? 2.0 : parseFloat(USER_AGENT.substring(index + "Firefox".length + 1)); version = (index === -1) ? 2.0 : parseFloat(USER_AGENT.substring(index + "Firefox".length + 1));
if (version >= 3.0) if (version >= 3.0)
PLATFORM_FEATURES |= CPCSSRGBAFeature; PLATFORM_FEATURES |= CPCSSRGBAFeature;
@@ -166,16 +165,16 @@ if (typeof document != "undefined")
if (canvasElement && canvasElement.getContext) if (canvasElement && canvasElement.getContext)
{ {
PLATFORM_FEATURES |= CPHTMLCanvasFeature; PLATFORM_FEATURES |= CPHTMLCanvasFeature;
// Detect Canvas setTransform/transform support // Detect Canvas setTransform/transform support
var context = document.createElement("canvas").getContext("2d"); var context = document.createElement("canvas").getContext("2d");
if (context && context.setTransform && context.transform) if (context && context.setTransform && context.transform)
PLATFORM_FEATURES |= CPJavaScriptCanvasTransformFeature; PLATFORM_FEATURES |= CPJavaScriptCanvasTransformFeature;
} }
var DOMElement = document.createElement("div"); var DOMElement = document.createElement("div");
// Detect whether we have innerText or textContent (or neither) // Detect whether we have innerText or textContent (or neither)
if (DOMElement.innerText != undefined) if (DOMElement.innerText != undefined)
PLATFORM_FEATURES |= CPJavascriptInnerTextFeature; PLATFORM_FEATURES |= CPJavascriptInnerTextFeature;
+64 -176
View File
@@ -23,8 +23,9 @@
@import "CPFont.j" @import "CPFont.j"
@import "CPShadow.j" @import "CPShadow.j"
@import "CPView.j" @import "CPView.j"
@import "CPKeyValueBinding.j"
#include "CoreGraphics/CGGeometry.h"
#include "Platform/Platform.h"
CPLeftTextAlignment = 0; CPLeftTextAlignment = 0;
CPRightTextAlignment = 1; CPRightTextAlignment = 1;
@@ -74,7 +75,7 @@ CPControlTextDidEndEditingNotification = "CPControlTextDidEndEditingNotific
var CPControlBlackColor = [CPColor blackColor]; var CPControlBlackColor = [CPColor blackColor];
/*! /*!
@ingroup appkit @ingroup appkit
@class CPControl @class CPControl
@@ -83,7 +84,7 @@ var CPControlBlackColor = [CPColor blackColor];
@implementation CPControl : CPView @implementation CPControl : CPView
{ {
id _value; id _value;
// Target-Action Support // Target-Action Support
id _target; id _target;
SEL _action; SEL _action;
@@ -125,46 +126,16 @@ var CPControlBlackColor = [CPColor blackColor];
@"max-size"]]; @"max-size"]];
} }
+ (void)initialize
{
if (self === [CPControl class])
{
[self exposeBinding:@"value"];
[self exposeBinding:@"objectValue"];
[self exposeBinding:@"stringValue"];
[self exposeBinding:@"integerValue"];
[self exposeBinding:@"intValue"];
[self exposeBinding:@"doubleValue"];
[self exposeBinding:@"floatValue"];
[self exposeBinding:@"enabled"];
}
}
- (void)_reverseSetBinding
{
var theBinding = [CPKeyValueBinding getBinding:CPValueBinding forObject:self];
[theBinding reverseSetValueFor:@"objectValue"];
}
- (void)_replacementKeyPathForBinding:(CPString)aBinding
{
if (aBinding === @"value")
return @"objectValue";
return [super _replacementKeyPathForBinding:aBinding];
}
- (id)initWithFrame:(CGRect)aFrame - (id)initWithFrame:(CGRect)aFrame
{ {
self = [super initWithFrame:aFrame]; self = [super initWithFrame:aFrame];
if (self) if (self)
{ {
_sendActionOn = CPLeftMouseUpMask; _sendActionOn = CPLeftMouseUpMask;
_trackingMouseDownFlags = 0; _trackingMouseDownFlags = 0;
} }
return self; return self;
} }
@@ -209,16 +180,15 @@ var CPControlBlackColor = [CPColor blackColor];
*/ */
- (void)sendAction:(SEL)anAction to:(id)anObject - (void)sendAction:(SEL)anAction to:(id)anObject
{ {
[self _reverseSetBinding];
[CPApp sendAction:anAction to:anObject from:self]; [CPApp sendAction:anAction to:anObject from:self];
} }
- (int)sendActionOn:(int)mask - (int)sendActionOn:(int)mask
{ {
var previousMask = _sendActionOn; var previousMask = _sendActionOn;
_sendActionOn = mask; _sendActionOn = mask;
return previousMask; return previousMask;
} }
@@ -231,7 +201,7 @@ var CPControlBlackColor = [CPColor blackColor];
{ {
if (_toolTip == aToolTip) if (_toolTip == aToolTip)
return; return;
_toolTip = aToolTip; _toolTip = aToolTip;
#if PLATFORM(DOM) #if PLATFORM(DOM)
@@ -266,7 +236,7 @@ var CPControlBlackColor = [CPColor blackColor];
// Some subclasses should redefine this with CPLeftMouseDraggedMask // Some subclasses should redefine this with CPLeftMouseDraggedMask
if (flag) if (flag)
_sendActionOn |= CPPeriodicMask; _sendActionOn |= CPPeriodicMask;
else else
_sendActionOn &= ~CPPeriodicMask; _sendActionOn &= ~CPPeriodicMask;
} }
@@ -278,15 +248,16 @@ var CPControlBlackColor = [CPColor blackColor];
- (void)trackMouse:(CPEvent)anEvent - (void)trackMouse:(CPEvent)anEvent
{ {
var type = [anEvent type], 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); isWithinFrame = [self tracksMouseOutsideOfFrame] || CGRectContainsPoint([self bounds], currentLocation);
if (type === CPLeftMouseUp) if (type === CPLeftMouseUp)
{ {
[self stopTracking:_previousTrackingLocation at:currentLocation mouseIsUp:YES]; [self stopTracking:_previousTrackingLocation at:currentLocation mouseIsUp:YES];
_trackingMouseDownFlags = 0; _trackingMouseDownFlags = 0;
} }
else else
{ {
if (type === CPLeftMouseDown) if (type === CPLeftMouseDown)
@@ -300,20 +271,20 @@ var CPControlBlackColor = [CPColor blackColor];
{ {
if (!_trackingWasWithinFrame) if (!_trackingWasWithinFrame)
_continuousTracking = [self startTrackingAt:currentLocation]; _continuousTracking = [self startTrackingAt:currentLocation];
else if (_continuousTracking) else if (_continuousTracking)
_continuousTracking = [self continueTracking:_previousTrackingLocation at:currentLocation]; _continuousTracking = [self continueTracking:_previousTrackingLocation at:currentLocation];
} }
else else
[self stopTracking:_previousTrackingLocation at:currentLocation mouseIsUp:NO]; [self stopTracking:_previousTrackingLocation at:currentLocation mouseIsUp:NO];
} }
[CPApp setTarget:self selector:@selector(trackMouse:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES]; [CPApp setTarget:self selector:@selector(trackMouse:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
} }
if ((_sendActionOn & (1 << type)) && isWithinFrame) if ((_sendActionOn & (1 << type)) && isWithinFrame)
[self sendAction:_action to:_target]; [self sendAction:_action to:_target];
_trackingWasWithinFrame = isWithinFrame; _trackingWasWithinFrame = isWithinFrame;
_previousTrackingLocation = currentLocation; _previousTrackingLocation = currentLocation;
} }
@@ -327,26 +298,13 @@ var CPControlBlackColor = [CPColor blackColor];
return 0; return 0;
} }
- (void)performClick:(id)sender - (void)performClick:(id)sender
{ {
if (![self isEnabled])
return;
[self highlight:YES]; [self highlight:YES];
[self setState:[self nextState]]; [self setState:[self nextState]];
[self sendAction:[self action] to:[self target]];
try
{ [CPTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(unhighlightButtonTimerDidFinish:) userInfo:nil repeats:NO];
[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 - (void)unhighlightButtonTimerDidFinish:(id)sender
@@ -362,7 +320,7 @@ var CPControlBlackColor = [CPColor blackColor];
- (BOOL)startTrackingAt:(CGPoint)aPoint - (BOOL)startTrackingAt:(CGPoint)aPoint
{ {
[self highlight:YES]; [self highlight:YES];
return (_sendActionOn & CPPeriodicMask) || (_sendActionOn & CPLeftMouseDraggedMask); return (_sendActionOn & CPPeriodicMask) || (_sendActionOn & CPLeftMouseDraggedMask);
} }
@@ -380,7 +338,7 @@ var CPControlBlackColor = [CPColor blackColor];
{ {
if (![self isEnabled]) if (![self isEnabled])
return; return;
[self trackMouse:anEvent]; [self trackMouse:anEvent];
} }
@@ -398,7 +356,7 @@ var CPControlBlackColor = [CPColor blackColor];
- (void)setObjectValue:(id)anObject - (void)setObjectValue:(id)anObject
{ {
_value = anObject; _value = anObject;
[self setNeedsLayout]; [self setNeedsLayout];
[self setNeedsDisplay:YES]; [self setNeedsDisplay:YES];
} }
@@ -472,7 +430,7 @@ var CPControlBlackColor = [CPColor blackColor];
} }
/*! /*!
Returns the receiver's string value Returns the receiver's int value
*/ */
- (CPString)stringValue - (CPString)stringValue
{ {
@@ -480,7 +438,7 @@ var CPControlBlackColor = [CPColor blackColor];
} }
/*! /*!
Set's the receiver's string value Set's the receiver's int value
*/ */
- (void)setStringValue:(CPString)anObject - (void)setStringValue:(CPString)anObject
{ {
@@ -527,124 +485,54 @@ var CPControlBlackColor = [CPColor blackColor];
[self setStringValue:[sender stringValue]]; [self setStringValue:[sender stringValue]];
} }
- (void)textDidBeginEditing:(CPNotification)note - (void)textDidBeginEditing:(CPNotification)note
{ {
//this looks to prevent false propagation of notifications for other objects //this looks to prevent false propagation of notifications for other objects
if ([note object] != self) if([note object] != self)
return; return;
[[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidBeginEditingNotification object:self userInfo:[CPDictionary dictionaryWithObject:[note object] forKey:"CPFieldEditor"]]; [[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidBeginEditingNotification object:self userInfo:[CPDictionary dictionaryWithObject:[note object] forKey:"CPFieldEditor"]];
} }
- (void)textDidChange:(CPNotification)note - (void)textDidChange:(CPNotification)note
{ {
//this looks to prevent false propagation of notifications for other objects //this looks to prevent false propagation of notifications for other objects
if ([note object] != self) if([note object] != self)
return; return;
[[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidChangeNotification object:self userInfo:[CPDictionary dictionaryWithObject:[note object] forKey:"CPFieldEditor"]]; [[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidChangeNotification object:self userInfo:[CPDictionary dictionaryWithObject:[note object] forKey:"CPFieldEditor"]];
} }
- (void)textDidEndEditing:(CPNotification)note - (void)textDidEndEditing:(CPNotification)note
{ {
//this looks to prevent false propagation of notifications for other objects //this looks to prevent false propagation of notifications for other objects
if ([note object] != self) if([note object] != self)
return; return;
[self _reverseSetBinding];
[[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidEndEditingNotification object:self userInfo:[CPDictionary dictionaryWithObject:[note object] forKey:"CPFieldEditor"]]; [[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidEndEditingNotification object:self userInfo:[CPDictionary dictionaryWithObject:[note object] forKey:"CPFieldEditor"]];
} }
- (void)setAlignment:(CPTextAlignment)alignment #define BRIDGE(UPPERCASE, LOWERCASE, ATTRIBUTENAME) \
{ /*! Sets the value for ATTRIBUTENAME */\
[self setValue:alignment forThemeAttribute:@"alignment"]; - (void)set##UPPERCASE:(id)aValue\
{\
[self setValue:aValue forThemeAttribute:ATTRIBUTENAME];\
}\
/*! Returns the current value for ATTRIBUTENAME */\
- (id)LOWERCASE\
{\
return [self valueForThemeAttribute:ATTRIBUTENAME];\
} }
- (CPTextAlignment)alignment BRIDGE(Alignment, alignment, "alignment")
{ BRIDGE(VerticalAlignment, verticalAlignment, "vertical-alignment")
return [self valueForThemeAttribute:@"alignment"]; BRIDGE(LineBreakMode, lineBreakMode, "line-break-mode")
} BRIDGE(TextColor, textColor, "text-color")
BRIDGE(Font, font, "font")
- (void)setVerticalAlignment:(CPTextVerticalAlignment)alignment BRIDGE(TextShadowColor, textShadowColor, "text-shadow-color")
{ BRIDGE(TextShadowOffset, textShadowOffset, "text-shadow-offset")
[self setValue:alignment forThemeAttribute:@"vertical-alignment"]; BRIDGE(ImagePosition, imagePosition, "image-position")
} BRIDGE(ImageScaling, imageScaling, "image-scaling")
- (CPTextVerticalAlignment)verticalAlignment
{
return [self valueForThemeAttribute:@"vertical-alignment"];
}
- (void)setLineBreakMode:(CPLineBreakMode)mode
{
[self setValue:mode forThemeAttribute:@"line-break-mode"];
}
- (CPLineBreakMode)lineBreakMode
{
return [self valueForThemeAttribute:@"line-break-mode"];
}
- (void)setTextColor:(CPColor)aColor
{
[self setValue:aColor forThemeAttribute:@"text-color"];
}
- (CPColor)textColor
{
return [self valueForThemeAttribute:@"text-color"];
}
- (void)setTextShadowColor:(CPColor)aColor
{
[self setValue:aColor forThemeAttribute:@"text-shadow-color"];
}
- (CPColor)textShadowColor
{
return [self valueForThemeAttribute:@"text-shadow-color"];
}
- (void)setTextShadowOffset:(float)offset
{
[self setValue:offset forThemeAttribute:@"text-shadow-offset"];
}
- (float)textShadowOffset
{
return [self valueForThemeAttribute:@"text-shadow-offset"];
}
- (void)setFont:(CPFont)aFont
{
[self setValue:aFont forThemeAttribute:@"font"];
}
- (CPFont)font
{
return [self valueForThemeAttribute:@"font"];
}
- (void)setImagePosition:(CPCellImagePosition)position
{
[self setValue:position forThemeAttribute:@"image-position"];
}
- (CPCellImagePosition)imagePosition
{
return [self valueForThemeAttribute:@"image-position"];
}
- (void)setImageScaling:(CPImageScaling)scaling
{
[self setValue:scaling forThemeAttribute:@"image-scaling"];
}
- (CPImageScaling)imageScaling
{
return [self valueForThemeAttribute:@"image-scaling"];
}
- (void)setEnabled:(BOOL)isEnabled - (void)setEnabled:(BOOL)isEnabled
{ {
@@ -682,7 +570,7 @@ var CPControlBlackColor = [CPColor blackColor];
var CPControlValueKey = "CPControlValueKey", var CPControlValueKey = "CPControlValueKey",
CPControlControlStateKey = @"CPControlControlStateKey", CPControlControlStateKey = @"CPControlControlStateKey",
CPControlIsEnabledKey = "CPControlIsEnabledKey", CPControlIsEnabledKey = "CPControlIsEnabledKey",
CPControlTargetKey = "CPControlTargetKey", CPControlTargetKey = "CPControlTargetKey",
CPControlActionKey = "CPControlActionKey", CPControlActionKey = "CPControlActionKey",
CPControlSendActionOnKey = "CPControlSendActionOnKey", CPControlSendActionOnKey = "CPControlSendActionOnKey",
@@ -712,7 +600,7 @@ var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
[self sendActionOn:[aCoder decodeIntForKey:CPControlSendActionOnKey]]; [self sendActionOn:[aCoder decodeIntForKey:CPControlSendActionOnKey]];
[self setSendsActionOnEndEditing:[aCoder decodeBoolForKey:CPControlSendsActionOnEndEditingKey]]; [self setSendsActionOnEndEditing:[aCoder decodeBoolForKey:CPControlSendsActionOnEndEditingKey]];
} }
return self; return self;
} }
@@ -748,7 +636,7 @@ var _CPControlSizeIdentifiers = [],
_CPControlSizeIdentifiers[CPRegularControlSize] = "Regular"; _CPControlSizeIdentifiers[CPRegularControlSize] = "Regular";
_CPControlSizeIdentifiers[CPSmallControlSize] = "Small"; _CPControlSizeIdentifiers[CPSmallControlSize] = "Small";
_CPControlSizeIdentifiers[CPMiniControlSize] = "Mini"; _CPControlSizeIdentifiers[CPMiniControlSize] = "Mini";
function _CPControlIdentifierForControlSize(aControlSize) function _CPControlIdentifierForControlSize(aControlSize)
{ {
return _CPControlSizeIdentifiers[aControlSize]; return _CPControlSizeIdentifiers[aControlSize];
@@ -759,21 +647,21 @@ function _CPControlColorWithPatternImage(sizes, aClassName)
var index = 1, var index = 1,
count = arguments.length, count = arguments.length,
identifier = ""; identifier = "";
for (; index < count; ++index) for (; index < count; ++index)
identifier += arguments[index]; identifier += arguments[index];
var color = _CPControlCachedColorWithPatternImages[identifier]; var color = _CPControlCachedColorWithPatternImages[identifier];
if (!color) if (!color)
{ {
var bundle = [CPBundle bundleForClass:[CPControl class]]; var bundle = [CPBundle bundleForClass:[CPControl class]];
color = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:aClassName + "/" + identifier + ".png"] size:sizes[identifier]]]; color = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:aClassName + "/" + identifier + ".png"] size:sizes[identifier]]];
_CPControlCachedColorWithPatternImages[identifier] = color; _CPControlCachedColorWithPatternImages[identifier] = color;
} }
return color; return color;
} }
@@ -782,17 +670,17 @@ function _CPControlThreePartImagePattern(isVertical, sizes, aClassName)
var index = 2, var index = 2,
count = arguments.length, count = arguments.length,
identifier = ""; identifier = "";
for (; index < count; ++index) for (; index < count; ++index)
identifier += arguments[index]; identifier += arguments[index];
var color = _CPControlCachedThreePartImagePattern[identifier]; var color = _CPControlCachedThreePartImagePattern[identifier];
if (!color) if (!color)
{ {
var bundle = [CPBundle bundleForClass:[CPControl class]], var bundle = [CPBundle bundleForClass:[CPControl class]],
path = aClassName + "/" + identifier; path = aClassName + "/" + identifier;
sizes = sizes[identifier]; sizes = sizes[identifier];
color = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:[ color = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:[
@@ -800,9 +688,9 @@ function _CPControlThreePartImagePattern(isVertical, sizes, aClassName)
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:path + "1.png"] size:sizes[1]], [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:path + "1.png"] size:sizes[1]],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:path + "2.png"] size:sizes[2]] [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:path + "2.png"] size:sizes[2]]
] isVertical:isVertical]]; ] isVertical:isVertical]];
_CPControlCachedThreePartImagePattern[identifier] = color; _CPControlCachedThreePartImagePattern[identifier] = color;
} }
return color; return color;
} }
-88
View File
@@ -1,88 +0,0 @@
//
// CPController.j
// AppKit
//
// Created by Ross Boucher 1/15/09
// Copyright 280 North
//
// Adapted from GNUStep
// Copyright (C) 2007 Free Software Foundation, Inc
// Released under the LGPL.
//
@import <Foundation/CPObject.j>
var CPControllerDeclaredKeysKey = @"CPControllerDeclaredKeysKey";
@implementation CPController : CPObject
{
CPArray _editors;
CPArray _declaredKeys;
}
- (id)init
{
self = [super init];
if (self)
{
_editors = [];
_declaredKeys = [];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
if ([_declaredKeys count] > 0)
[aCoder encodeObject:_declaredKeys forKey:CPControllerDeclaredKeysKey];
}
- (id)initWithCoder:(CPCoder)aDecoder
{
self = [super init];
if (self)
{
_editors = [];
_declaredKeys = [aDecoder decodeObjectForKey:CPControllerDeclaredKeysKey] || [];
}
return nil;
}
- (BOOL)isEditing
{
return [_editors count] > 0;
}
- (BOOL)commitEditing
{
var index = 0,
count = _editors.length;
for (; index < count; ++index)
if (![[_editors objectAtIndex:i] commitEditing])
return NO;
return YES;
}
- (void)discardEditing
{
[_editors makeObjectsPerformSelector:@selector(discardEditing)];
}
- (void)objectDidBeginEditing:(id)anEditor
{
[_editors addObject:anEditor];
}
- (void)objectDidEndEditing:(id)anEditor
{
[_editors removeObject:anEditor];
}
@end
+20 -29
View File
@@ -24,7 +24,7 @@
@import <Foundation/CPString.j> @import <Foundation/CPString.j>
/*! /*!
@ingroup appkit @ingroup appkit
@class CPCookie @class CPCookie
CPCookie is the Cappuccino interface to a web browser cookie. You can set the name CPCookie is the Cappuccino interface to a web browser cookie. You can set the name
@@ -33,7 +33,7 @@
{ {
CPString _cookieName; CPString _cookieName;
CPString _cookieValue; CPString _cookieValue;
CPString _expires; CPString _expires;
} }
@@ -44,7 +44,7 @@
- (id)initWithName:(CPString)aName - (id)initWithName:(CPString)aName
{ {
self = [super init]; self = [super init];
_cookieName = aName; _cookieName = aName;
_cookieValue = [self _readCookieValue]; _cookieValue = [self _readCookieValue];
@@ -83,39 +83,30 @@
*/ */
- (void)setValue:(CPString)value expires:(CPDate)date domain:(CPString)domain - (void)setValue:(CPString)value expires:(CPDate)date domain:(CPString)domain
{ {
if (date) if(date)
var expires = "; expires=" + date.toGMTString(); var expires = "; expires="+date.toGMTString();
else else
var expires = ""; var expires = "";
if (domain) if(domain)
domain = "; domain=" + domain; domain = "; domain="+domain;
else else
domain = ""; domain = "";
#if PLATFORM(DOM) document.cookie = _cookieName+"="+value+expires+"; path=/"+domain;
document.cookie = _cookieName+"="+value+expires+"; path=/"+domain;
#else
_cookieValue = value;
_expires = expires;
#endif
} }
/* @ignore */ /* @ignore */
- (CPString)_readCookieValue - (CPString)_readCookieValue
{ {
#if PLATFORM(DOM) var nameEQ = _cookieName + "=";
var nameEQ = _cookieName + "=", var ca = document.cookie.split(';');
ca = document.cookie.split(';'); for(var i=0;i < ca.length;i++) {
var c = ca[i];
for (var i = 0; i < ca.length; i++) while (c.charAt(0)==' ') c = c.substring(1,c.length);
{ if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
var c = ca[i]; }
while (c.charAt(0) == ' ') c = c.substring(1, c.length); return "";
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
}
#endif
return "";
} }
@end @end
+10 -15
View File
@@ -12,7 +12,7 @@ Implemented class methods:
Opera : All except resizeLeftRightCursor resizeUpDownCursor operationNotAllowedCursor dragCopyCursor dragLinkCursor contextualMenuCursor openHandCursor closedHandCursor disappearingItemCursor // Opera does not support url cursors so these won't work with images Opera : All except resizeLeftRightCursor resizeUpDownCursor operationNotAllowedCursor dragCopyCursor dragLinkCursor contextualMenuCursor openHandCursor closedHandCursor disappearingItemCursor // Opera does not support url cursors so these won't work with images
*/ */
@import <Foundation/CPObject.j> #include "Platform/Platform.h"
var currentCursor = nil, var currentCursor = nil,
cursorStack = [], cursorStack = [],
@@ -61,9 +61,9 @@ var currentCursor = nil,
if (CPBrowserIsEngine(CPGeckoBrowserEngine)) if (CPBrowserIsEngine(CPGeckoBrowserEngine))
cursorURLFormat += ", default"; cursorURLFormat += ", default";
} }
var url = [CPString stringWithFormat:cursorURLFormat, imageName]; var url = [CPString stringWithFormat:cursorURLFormat, imageName];
return [[CPCursor alloc] initWithCSSString:url]; return [[CPCursor alloc] initWithCSSString:url];
} }
@@ -96,7 +96,7 @@ var currentCursor = nil,
{ {
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine)) if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)]; return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)];
return [CPCursor cursorWithCSSString:"s-resize"]; // WebKit | FF | opera return [CPCursor cursorWithCSSString:"s-resize"]; // WebKit | FF | opera
} }
@@ -167,22 +167,18 @@ var currentCursor = nil,
{ {
if (CPBrowserIsEngine(CPWebKitBrowserEngine)) if (CPBrowserIsEngine(CPWebKitBrowserEngine))
return [CPCursor cursorWithCSSString:@"-webkit-grab"]; return [CPCursor cursorWithCSSString:@"-webkit-grab"];
else if (CPBrowserIsEngine(CPGeckoBrowserEngine)) else if (CPBrowserIsEngine(CPGeckoBrowserEngine) || CPBrowserIsEngine(CPOperaBrowserEngine))
return [CPCursor cursorWithCSSString:@"-moz-grab"];
else if (CPBrowserIsEngine(CPOperaBrowserEngine))
return [CPCursor cursorWithCSSString:@"move"]; return [CPCursor cursorWithCSSString:@"move"];
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)]; // WebKit only. move in FFMac|Opera return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)]; // WebKit only. move in FFMac|Opera
} }
+ (CPCursor)closedHandCursor + (CPCursor)closedHandCursor
{ {
if (CPBrowserIsEngine(CPWebKitBrowserEngine)) if (CPBrowserIsEngine(CPWebKitBrowserEngine))
return [CPCursor cursorWithCSSString:@"-webkit-grabbing"]; return [CPCursor cursorWithCSSString:@"-webkit-grabbing"];
else if (CPBrowserIsEngine(CPGeckoBrowserEngine))
return [CPCursor cursorWithCSSString:@"-moz-grabbing"];
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)]; // WebKit || FF return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)]; // WebKit only
} }
+ (CPCursor)disappearingItemCursor + (CPCursor)disappearingItemCursor
@@ -197,7 +193,7 @@ var currentCursor = nil,
+ (void)unhide + (void)unhide
{ {
[self _setCursorCSS:[currentCursor _cssString]]; [self _setCursorCSS:[currentCursor _cssString]]
} }
+ (void)setHiddenUntilMouseMoves:(BOOL)flag + (void)setHiddenUntilMouseMoves:(BOOL)flag
@@ -210,10 +206,9 @@ var currentCursor = nil,
- (id)initWithImage:(CPImage)image hotSpot:(CPPoint)hotSpot - (id)initWithImage:(CPImage)image hotSpot:(CPPoint)hotSpot
{ {
return [self initWithCSSString:"url(" + [image filename] + "), auto"]; return [self initWithCSSString:"url(" + [image filename] + ")"];
} }
- (void)mouseEntered:(CPEvent)event - (void)mouseEntered:(CPEvent)event
{ {
} }
@@ -224,7 +219,7 @@ var currentCursor = nil,
- (void)set - (void)set
{ {
currentCursor = self; currentCursor = self;
#if PLATFORM(DOM) #if PLATFORM(DOM)
[[self class] _setCursorCSS:_cssString]; [[self class] _setCursorCSS:_cssString];
+67 -55
View File
@@ -23,7 +23,6 @@
@import <Foundation/CPString.j> @import <Foundation/CPString.j>
@import <Foundation/CPArray.j> @import <Foundation/CPArray.j>
@import "CPApplication.j"
@import "CPResponder.j" @import "CPResponder.j"
@import "CPSavePanel.j" @import "CPSavePanel.j"
@import "CPViewController.j" @import "CPViewController.j"
@@ -83,7 +82,7 @@ CPDocumentDidFailToSaveNotification = @"CPDocumentDidFailToSaveNotification";
var CPDocumentUntitledCount = 0; var CPDocumentUntitledCount = 0;
/*! /*!
@ingroup appkit @ingroup appkit
@class CPDocument @class CPDocument
@@ -121,7 +120,7 @@ var CPDocumentUntitledCount = 0;
- (id)init - (id)init
{ {
self = [super init]; self = [super init];
if (self) if (self)
{ {
_windowControllers = []; _windowControllers = [];
@@ -132,7 +131,7 @@ var CPDocumentUntitledCount = 0;
[self setNextResponder:CPApp]; [self setNextResponder:CPApp];
} }
return self; return self;
} }
@@ -145,10 +144,10 @@ var CPDocumentUntitledCount = 0;
- (id)initWithType:(CPString)aType error:({CPError})anError - (id)initWithType:(CPString)aType error:({CPError})anError
{ {
self = [self init]; self = [self init];
if (self) if (self)
[self setFileType:aType]; [self setFileType:aType];
return self; return self;
} }
@@ -166,7 +165,7 @@ var CPDocumentUntitledCount = 0;
- (id)initWithContentsOfURL:(CPURL)anAbsoluteURL ofType:(CPString)aType delegate:(id)aDelegate didReadSelector:(SEL)aDidReadSelector contextInfo:(id)aContextInfo - (id)initWithContentsOfURL:(CPURL)anAbsoluteURL ofType:(CPString)aType delegate:(id)aDelegate didReadSelector:(SEL)aDidReadSelector contextInfo:(id)aContextInfo
{ {
self = [self init]; self = [self init];
if (self) if (self)
{ {
[self setFileURL:anAbsoluteURL]; [self setFileURL:anAbsoluteURL];
@@ -174,7 +173,7 @@ var CPDocumentUntitledCount = 0;
[self readFromURL:anAbsoluteURL ofType:aType delegate:aDelegate didReadSelector:aDidReadSelector contextInfo:aContextInfo]; [self readFromURL:anAbsoluteURL ofType:aType delegate:aDelegate didReadSelector:aDidReadSelector contextInfo:aContextInfo];
} }
return self; return self;
} }
@@ -191,7 +190,7 @@ var CPDocumentUntitledCount = 0;
- (id)initForURL:(CPURL)anAbsoluteURL withContentsOfURL:(CPURL)absoluteContentsURL ofType:(CPString)aType delegate:(id)aDelegate didReadSelector:(SEL)aDidReadSelector contextInfo:(id)aContextInfo - (id)initForURL:(CPURL)anAbsoluteURL withContentsOfURL:(CPURL)absoluteContentsURL ofType:(CPString)aType delegate:(id)aDelegate didReadSelector:(SEL)aDidReadSelector contextInfo:(id)aContextInfo
{ {
self = [self init]; self = [self init];
if (self) if (self)
{ {
[self setFileURL:anAbsoluteURL]; [self setFileURL:anAbsoluteURL];
@@ -199,7 +198,7 @@ var CPDocumentUntitledCount = 0;
[self readFromURL:absoluteContentsURL ofType:aType delegate:aDelegate didReadSelector:aDidReadSelector contextInfo:aContextInfo]; [self readFromURL:absoluteContentsURL ofType:aType delegate:aDelegate didReadSelector:aDidReadSelector contextInfo:aContextInfo];
} }
return self; return self;
} }
@@ -211,10 +210,10 @@ var CPDocumentUntitledCount = 0;
@throws CPUnsupportedMethodException if this method hasn't been overriden by the subclass @throws CPUnsupportedMethodException if this method hasn't been overriden by the subclass
@return the document data @return the document data
*/ */
- (CPData)dataOfType:(CPString)aType error:({CPError})anError - (CPData)dataOfType:(CPString)aType
{ {
[CPException raise:CPUnsupportedMethodException [CPException raise:CPUnsupportedMethodException
reason:"dataOfType:error: must be overridden by the document subclass."]; reason:"dataOfType: must be overridden by the document subclass."];
} }
/*! /*!
@@ -282,7 +281,7 @@ var CPDocumentUntitledCount = 0;
{ {
var view = [viewController view], var view = [viewController view],
viewFrame = [view frame]; viewFrame = [view frame];
viewFrame.origin = CGPointMake(50, 50); viewFrame.origin = CGPointMake(50, 50);
var theWindow = [[CPWindow alloc] initWithContentRect:viewFrame styleMask:CPTitledWindowMask | CPClosableWindowMask | CPMiniaturizableWindowMask | CPResizableWindowMask]; var theWindow = [[CPWindow alloc] initWithContentRect:viewFrame styleMask:CPTitledWindowMask | CPClosableWindowMask | CPMiniaturizableWindowMask | CPResizableWindowMask];
@@ -382,14 +381,14 @@ var CPDocumentUntitledCount = 0;
{ {
if (_fileURL) if (_fileURL)
return [_fileURL lastPathComponent]; return [_fileURL lastPathComponent];
if (!_untitledDocumentIndex) if (!_untitledDocumentIndex)
_untitledDocumentIndex = ++CPDocumentUntitledCount; _untitledDocumentIndex = ++CPDocumentUntitledCount;
if (_untitledDocumentIndex == 1)
return @"Untitled";
if (_untitledDocumentIndex == 1) return @"Untitled " + _untitledDocumentIndex;
return @"Untitled";
return @"Untitled " + _untitledDocumentIndex;
} }
- (CPString)viewCibName - (CPString)viewCibName
@@ -458,7 +457,7 @@ var CPDocumentUntitledCount = 0;
return; return;
_fileURL = aFileURL; _fileURL = aFileURL;
[_windowControllers makeObjectsPerformSelector:@selector(synchronizeWindowTitleWithDocumentName)]; [_windowControllers makeObjectsPerformSelector:@selector(synchronizeWindowTitleWithDocumentName)];
} }
@@ -474,8 +473,21 @@ var CPDocumentUntitledCount = 0;
*/ */
- (void)saveToURL:(CPURL)anAbsoluteURL ofType:(CPString)aTypeName forSaveOperation:(CPSaveOperationType)aSaveOperation delegate:(id)aDelegate didSaveSelector:(SEL)aDidSaveSelector contextInfo:(id)aContextInfo - (void)saveToURL:(CPURL)anAbsoluteURL ofType:(CPString)aTypeName forSaveOperation:(CPSaveOperationType)aSaveOperation delegate:(id)aDelegate didSaveSelector:(SEL)aDidSaveSelector contextInfo:(id)aContextInfo
{ {
var data = [self dataOfType:[self fileType] error:nil], if (anAbsoluteURL.isLocalStorageURL())
oldChangeCount = _changeCount; [[CPDocumentController sharedDocumentController] _addLocalDocumentURL:anAbsoluteURL];
var data = nil;
if ([self respondsToSelector:@selector(dataOfType:error:)])
{
CPLog.warn("[" + CPStringFromClass([self class]) + " " + CPStringFromSelector(@selector(dataOfType:error:)) + "] is deprecated, please implement " + CPStringFromSelector(@selector(dataOfType:)) + " instead and simply throw exceptions when necessary.");
data = [self dataOfType:[self fileType] error:nil];
}
else
data = [self dataOfType:[self fileType]];
var oldChangeCount = _changeCount;
_writeRequest = [CPURLRequest requestWithURL:anAbsoluteURL]; _writeRequest = [CPURLRequest requestWithURL:anAbsoluteURL];
@@ -510,21 +522,21 @@ var CPDocumentUntitledCount = 0;
// If we got this far and it wasn't an HTTP request, then everything is fine. // If we got this far and it wasn't an HTTP request, then everything is fine.
if (![aResponse isKindOfClass:[CPHTTPURLResponse class]]) if (![aResponse isKindOfClass:[CPHTTPURLResponse class]])
return; return;
var statusCode = [aResponse statusCode]; var statusCode = [aResponse statusCode];
// Nothing to do if everything is hunky dory. // Nothing to do if everything is hunky dory.
if (statusCode === 200) if (statusCode === 200)
return; return;
var session = aConnection.session; var session = aConnection.session;
if (aConnection == _readConnection) if (aConnection == _readConnection)
{ {
[aConnection cancel]; [aConnection cancel];
alert("There was an error retrieving the document."); alert("There was an error retrieving the document.");
objj_msgSend(session.delegate, session.didReadSelector, self, NO, session.contextInfo); objj_msgSend(session.delegate, session.didReadSelector, self, NO, session.contextInfo);
} }
else else
@@ -533,23 +545,23 @@ var CPDocumentUntitledCount = 0;
if (statusCode == 409) if (statusCode == 409)
{ {
[aConnection cancel]; [aConnection cancel];
if (confirm("There already exists a file with that name, would you like to overwrite it?")) if (confirm("There already exists a file with that name, would you like to overwrite it?"))
{ {
[_writeRequest setValue:@"true" forHTTPHeaderField:@"x-cappuccino-overwrite"]; [_writeRequest setValue:@"true" forHTTPHeaderField:@"x-cappuccino-overwrite"];
[aConnection start]; [aConnection start];
} }
else else
{ {
if (session.saveOperation != CPSaveToOperation) if (session.saveOperation != CPSaveToOperation)
{ {
_changeCount += session.changeCount; _changeCount += session.changeCount;
[_windowControllers makeObjectsPerformSelector:@selector(setDocumentEdited:) withObject:[self isDocumentEdited]]; [_windowControllers makeObjectsPerformSelector:@selector(setDocumentEdited:) withObject:[self isDocumentEdited]];
} }
_writeRequest = nil; _writeRequest = nil;
objj_msgSend(session.delegate, session.didSaveSelector, self, NO, session.contextInfo); objj_msgSend(session.delegate, session.didSaveSelector, self, NO, session.contextInfo);
[self _sendDocumentSavedNotification:NO]; [self _sendDocumentSavedNotification:NO];
} }
@@ -564,7 +576,7 @@ var CPDocumentUntitledCount = 0;
- (void)connection:(CPURLConnection)aConnection didReceiveData:(CPString)aData - (void)connection:(CPURLConnection)aConnection didReceiveData:(CPString)aData
{ {
var session = aConnection.session; var session = aConnection.session;
// READ // READ
if (aConnection == _readConnection) if (aConnection == _readConnection)
{ {
@@ -576,9 +588,9 @@ var CPDocumentUntitledCount = 0;
{ {
if (session.saveOperation != CPSaveToOperation) if (session.saveOperation != CPSaveToOperation)
[self setFileURL:session.absoluteURL]; [self setFileURL:session.absoluteURL];
_writeRequest = nil; _writeRequest = nil;
objj_msgSend(session.delegate, session.didSaveSelector, self, YES, session.contextInfo); objj_msgSend(session.delegate, session.didSaveSelector, self, YES, session.contextInfo);
[self _sendDocumentSavedNotification:YES]; [self _sendDocumentSavedNotification:YES];
} }
@@ -591,17 +603,17 @@ var CPDocumentUntitledCount = 0;
- (void)connection:(CPURLConnection)aConnection didFailWithError:(CPError)anError - (void)connection:(CPURLConnection)aConnection didFailWithError:(CPError)anError
{ {
var session = aConnection.session; var session = aConnection.session;
if (_readConnection == aConnection) if (_readConnection == aConnection)
objj_msgSend(session.delegate, session.didReadSelector, self, NO, session.contextInfo); objj_msgSend(session.delegate, session.didReadSelector, self, NO, session.contextInfo);
else else
{ {
if (session.saveOperation != CPSaveToOperation) if (session.saveOperation != CPSaveToOperation)
{ {
_changeCount += session.changeCount; _changeCount += session.changeCount;
[_windowControllers makeObjectsPerformSelector:@selector(setDocumentEdited:) withObject:[self isDocumentEdited]]; [_windowControllers makeObjectsPerformSelector:@selector(setDocumentEdited:) withObject:[self isDocumentEdited]];
} }
_writeRequest = nil; _writeRequest = nil;
@@ -644,9 +656,9 @@ var CPDocumentUntitledCount = 0;
else if (aChangeType == CPChangeCleared) else if (aChangeType == CPChangeCleared)
_changeCount = 0; _changeCount = 0;
/*else if (aChangeType == CPCHangeReadOtherContents) /*else if (aChangeType == CPCHangeReadOtherContents)
else if (aChangeType == CPChangeAutosaved)*/ else if (aChangeType == CPChangeAutosaved)*/
[_windowControllers makeObjectsPerformSelector:@selector(setDocumentEdited:) withObject:[self isDocumentEdited]]; [_windowControllers makeObjectsPerformSelector:@selector(setDocumentEdited:) withObject:[self isDocumentEdited]];
} }
@@ -686,9 +698,9 @@ var CPDocumentUntitledCount = 0;
{ {
if (_hasUndoManager == aFlag) if (_hasUndoManager == aFlag)
return; return;
_hasUndoManager = aFlag; _hasUndoManager = aFlag;
if (!_hasUndoManager) if (!_hasUndoManager)
[self setUndoManager:nil]; [self setUndoManager:nil];
} }
@@ -697,7 +709,7 @@ var CPDocumentUntitledCount = 0;
- (void)_undoManagerWillCloseGroup:(CPNotification)aNotification - (void)_undoManagerWillCloseGroup:(CPNotification)aNotification
{ {
var undoManager = [aNotification object]; var undoManager = [aNotification object];
if ([undoManager isUndoing] || [undoManager isRedoing]) if ([undoManager isUndoing] || [undoManager isRedoing])
return; return;
@@ -724,13 +736,13 @@ var CPDocumentUntitledCount = 0;
- (void)setUndoManager:(CPUndoManager)anUndoManager - (void)setUndoManager:(CPUndoManager)anUndoManager
{ {
var defaultCenter = [CPNotificationCenter defaultCenter]; var defaultCenter = [CPNotificationCenter defaultCenter];
if (_undoManager) if (_undoManager)
{ {
[defaultCenter removeObserver:self [defaultCenter removeObserver:self
name:CPUndoManagerDidUndoChangeNotification name:CPUndoManagerDidUndoChangeNotification
object:_undoManager]; object:_undoManager];
[defaultCenter removeObserver:self [defaultCenter removeObserver:self
name:CPUndoManagerDidRedoChangeNotification name:CPUndoManagerDidRedoChangeNotification
object:_undoManager]; object:_undoManager];
@@ -739,17 +751,17 @@ var CPDocumentUntitledCount = 0;
name:CPUndoManagerWillCloseUndoGroupNotification name:CPUndoManagerWillCloseUndoGroupNotification
object:_undoManager]; object:_undoManager];
} }
_undoManager = anUndoManager; _undoManager = anUndoManager;
if (_undoManager) if (_undoManager)
{ {
[defaultCenter addObserver:self [defaultCenter addObserver:self
selector:@selector(_undoManagerDidUndoChange:) selector:@selector(_undoManagerDidUndoChange:)
name:CPUndoManagerDidUndoChangeNotification name:CPUndoManagerDidUndoChangeNotification
object:_undoManager]; object:_undoManager];
[defaultCenter addObserver:self [defaultCenter addObserver:self
selector:@selector(_undoManagerDidRedoChange:) selector:@selector(_undoManagerDidRedoChange:)
name:CPUndoManagerDidRedoChangeNotification name:CPUndoManagerDidRedoChangeNotification
@@ -775,7 +787,7 @@ var CPDocumentUntitledCount = 0;
return _undoManager; return _undoManager;
} }
/* /*
Implemented as a delegate of a CPWindow Implemented as a delegate of a CPWindow
@ignore @ignore
@@ -804,7 +816,7 @@ var CPDocumentUntitledCount = 0;
[[CPNotificationCenter defaultCenter] [[CPNotificationCenter defaultCenter]
postNotificationName:CPDocumentWillSaveNotification postNotificationName:CPDocumentWillSaveNotification
object:self]; object:self];
[self saveToURL:_fileURL ofType:[self fileType] forSaveOperation:CPSaveOperation delegate:delegate didSaveSelector:didSaveSelector contextInfo:contextInfo]; [self saveToURL:_fileURL ofType:[self fileType] forSaveOperation:CPSaveOperation delegate:delegate didSaveSelector:didSaveSelector contextInfo:contextInfo];
} }
else else
@@ -862,7 +874,7 @@ var CPDocumentUntitledCount = 0;
[[CPDocumentController sharedDocumentController] removeDocument:self]; [[CPDocumentController sharedDocumentController] removeDocument:self];
} }
- (void)shouldCloseWindowController:(CPWindowController)controller delegate:(id)delegate shouldCloseSelector:(SEL)selector contextInfo:(Object)info - (void)shouldCloseWindowController:(CPWindowController)controller delegate:(id)delegate shouldCloseSelector:(SEL)selector contextInfo:(Object)info
{ {
if ([controller shouldCloseDocument] || ([_windowControllers count] < 2 && [_windowControllers indexOfObject:controller] !== CPNotFound)) if ([controller shouldCloseDocument] || ([_windowControllers count] < 2 && [_windowControllers indexOfObject:controller] !== CPNotFound))
[self canCloseDocumentWithDelegate:self shouldCloseSelector:@selector(_document:shouldClose:context:) contextInfo:{delegate:delegate, selector:selector, context:info}]; [self canCloseDocumentWithDelegate:self shouldCloseSelector:@selector(_document:shouldClose:context:) contextInfo:{delegate:delegate, selector:selector, context:info}];
@@ -879,7 +891,7 @@ var CPDocumentUntitledCount = 0;
objj_msgSend(context.delegate, context.selector, aDocument, shouldClose, context.context); objj_msgSend(context.delegate, context.selector, aDocument, shouldClose, context.context);
} }
- (void)canCloseDocumentWithDelegate:(id)aDelegate shouldCloseSelector:(SEL)aSelector contextInfo:(Object)context - (void)canCloseDocumentWithDelegate:(id)aDelegate shouldCloseSelector:(SEL)aSelector contextInfo:(Object)context
{ {
if (![self isDocumentEdited]) if (![self isDocumentEdited])
return [aDelegate respondsToSelector:aSelector] && objj_msgSend(aDelegate, aSelector, self, YES, context); return [aDelegate respondsToSelector:aSelector] && objj_msgSend(aDelegate, aSelector, self, YES, context);
+78 -23
View File
@@ -29,7 +29,7 @@
var CPSharedDocumentController = nil; var CPSharedDocumentController = nil;
/*! /*!
@ingroup appkit @ingroup appkit
@class CPDocumentController @class CPDocumentController
This class is responsible for managing an application's open documents. This class is responsible for managing an application's open documents.
@@ -38,10 +38,11 @@ var CPSharedDocumentController = nil;
{ {
CPArray _documents; CPArray _documents;
CPArray _documentTypes; CPArray _documentTypes;
CPArray _localDocumentURLs;
} }
/*! /*!
Returns the singleton instance of the application's document controller. If it has not Returns the singleton instance of the application's document controller. If it has not
been created yet, it will be created then returned. been created yet, it will be created then returned.
@return a CPDocumentController @return a CPDocumentController
*/ */
@@ -49,7 +50,7 @@ var CPSharedDocumentController = nil;
{ {
if (!CPSharedDocumentController) if (!CPSharedDocumentController)
[[self alloc] init]; [[self alloc] init];
return CPSharedDocumentController; return CPSharedDocumentController;
} }
@@ -62,11 +63,27 @@ var CPSharedDocumentController = nil;
if (self) if (self)
{ {
_documents = [[CPArray alloc] init];
if (!CPSharedDocumentController) if (!CPSharedDocumentController)
CPSharedDocumentController = self; CPSharedDocumentController = self;
_localDocumentURLs = [CPSet set];
if (window.localStorage)
{
var localDocumentURLs = localStorage.getItem(CPDocumentControllerLocalDocumentURLsKey);
if (localDocumentURLs)
{
localDocumentURLs = JSON.parse(localDocumentURLs);
var count = [localDocumentURLs count];
while (count--)
[_localDocumentURLs addObject:new CFURL(localDocumentURLs[count])];
}
}
_documents = [];
_documentTypes = [[[CPBundle mainBundle] infoDictionary] objectForKey:@"CPBundleDocumentTypes"]; _documentTypes = [[[CPBundle mainBundle] infoDictionary] objectForKey:@"CPBundleDocumentTypes"];
} }
return self; return self;
@@ -85,16 +102,16 @@ var CPSharedDocumentController = nil;
{ {
var index = 0, var index = 0,
count = [_documents count]; count = [_documents count];
for (; index < count; ++index) for (; index < count; ++index)
{ {
var theDocument = _documents[index]; var theDocument = _documents[index];
if ([[theDocument fileURL] isEqual:aURL]) if ([[theDocument fileURL] isEqual:aURL])
return theDocument; return theDocument;
} }
return nil; return nil;
} }
/*! /*!
@@ -105,10 +122,10 @@ var CPSharedDocumentController = nil;
- (void)openUntitledDocumentOfType:(CPString)aType display:(BOOL)shouldDisplay - (void)openUntitledDocumentOfType:(CPString)aType display:(BOOL)shouldDisplay
{ {
var theDocument = [self makeUntitledDocumentOfType:aType error:nil]; var theDocument = [self makeUntitledDocumentOfType:aType error:nil];
if (theDocument) if (theDocument)
[self addDocument:theDocument]; [self addDocument:theDocument];
if (shouldDisplay) if (shouldDisplay)
{ {
[theDocument makeWindowControllers]; [theDocument makeWindowControllers];
@@ -210,7 +227,7 @@ var CPSharedDocumentController = nil;
return; return;
[aDocument makeWindowControllers]; [aDocument makeWindowControllers];
if ([aContextInfo objectForKey:@"shouldDisplay"]) if ([aContextInfo objectForKey:@"shouldDisplay"])
[aDocument showWindows]; [aDocument showWindows];
} }
@@ -219,12 +236,12 @@ var CPSharedDocumentController = nil;
Opens a new document in the application. Opens a new document in the application.
@param aSender the requesting object @param aSender the requesting object
*/ */
- (CFAction)newDocument:(id)aSender - (@action)newDocument:(id)aSender
{ {
[self openUntitledDocumentOfType:[[_documentTypes objectAtIndex:0] objectForKey:@"CPBundleTypeName"] display:YES]; [self openUntitledDocumentOfType:[[_documentTypes objectAtIndex:0] objectForKey:@"CPBundleTypeName"] display:YES];
} }
- (void)openDocument:(id)aSender -(void)openDocument:(id)aSender
{ {
var openPanel = [CPOpenPanel openPanel]; var openPanel = [CPOpenPanel openPanel];
@@ -276,17 +293,17 @@ var CPSharedDocumentController = nil;
{ {
var index = 0, var index = 0,
count = _documentTypes.length, count = _documentTypes.length,
extension = [[anAbsoluteURL pathExtension] lowercaseString], extension = [[anAbsoluteURL pathExtension] lowercaseString],
starType = nil; starType = nil;
for (; index < count; ++index) for (; index < count; ++index)
{ {
var documentType = _documentTypes[index], var documentType = _documentTypes[index],
extensions = [documentType objectForKey:@"CFBundleTypeExtensions"], extensions = [documentType objectForKey:@"CFBundleTypeExtensions"],
extensionIndex = 0, extensionIndex = 0,
extensionCount = extensions.length; extensionCount = extensions.length;
for (; extensionIndex < extensionCount; ++extensionIndex) for (; extensionIndex < extensionCount; ++extensionIndex)
{ {
var thisExtension = [extensions[extensionIndex] lowercaseString]; var thisExtension = [extensions[extensionIndex] lowercaseString];
@@ -312,11 +329,11 @@ var CPSharedDocumentController = nil;
for (;i < count; ++i) for (;i < count; ++i)
{ {
var documentType = _documentTypes[i]; var documentType = _documentTypes[i];
if ([documentType objectForKey:@"CPBundleTypeName"] == aType) if ([documentType objectForKey:@"CPBundleTypeName"] == aType)
return documentType; return documentType;
} }
return nil; return nil;
} }
@@ -336,7 +353,7 @@ var CPSharedDocumentController = nil;
@implementation CPDocumentController (Closing) @implementation CPDocumentController (Closing)
- (void)closeAllDocumentsWithDelegate:(id)aDelegate didCloseAllSelector:(SEL)didCloseSelector contextInfo:(Object)info - (void)closeAllDocumentsWithDelegate:(id)aDelegate didCloseAllSelector:(SEL)didCloseSelector contextInfo:(Object)info
{ {
var context = { var context = {
delegate: aDelegate, delegate: aDelegate,
@@ -455,3 +472,41 @@ var CPSharedDocumentController = nil;
} }
@end @end
var CPDocumentControllerLocalDocumentURLsKey = @"Cappuccino.CPDocumentController.documentURLs";
@implementation CPDocumentController (LocalStorage)
- (void)_addLocalDocumentURL:(CPURL)aURL
{
if (!window.localStorage)
return;
[_localDocumentURLs addObject:aURL];
var stringURLs = [],
URL = nil,
URLEnumerator = [_localDocumentURLs objectEnumerator];
while (URL = [URLEnumerator nextObject])
stringURLs.push(URL + "");
localStorage.setItem(CPDocumentControllerLocalDocumentURLsKey, JSON.stringify(stringURLs));
}
- (void)_removeLocalDocumentURL:(CPURL)aURL
{
if (!window.localStorage)
return;
[_localDocumentURLs removeObject:aURL];
localStorage.setItem(CPDocumentControllerLocalDocumentURLsKey, JSON.stringify([self allObjects]));
}
- (CPSet)localDocumentURLs
{
return [_localDocumentURLs copy];
}
@end
+38 -100
View File
@@ -20,12 +20,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
@import "CPApplication.j" @import <AppKit/CPView.j>
@import "CPEvent.j" @import <AppKit/CPEvent.j>
@import "CPImageView.j" @import <AppKit/CPPasteboard.j>
@import "CPPasteboard.j" @import <AppKit/CPImageView.j>
@import "CPView.j"
@import "CPWindow.j" #import "CoreGraphics/CGGeometry.h"
#import "Platform/Platform.h"
CPDragOperationNone = 0, CPDragOperationNone = 0,
@@ -39,10 +40,29 @@ CPDragOperationEvery = -1;
#define DRAGGING_WINDOW(anObject) ([anObject isKindOfClass:[CPWindow class]] ? anObject : [anObject window]) #define DRAGGING_WINDOW(anObject) ([anObject isKindOfClass:[CPWindow class]] ? anObject : [anObject window])
var CPDragServerPreviousEvent = nil, var CPDragServerPreviousEvent = nil,
CPDragServerPeriodicUpdateInterval = 0.05; CPDragServerAutoscrollInterval = nil;
/*
var CPDragServerAutoscroll = function()
{
[CPDragServerSource autoscroll:CPDragServerPreviousEvent];
}
var CPSharedDragServer = nil; if (CPDragServerAutoscrollInterval === nil)
{
if ([CPDragServerSource respondsToSelector:@selector(autoscroll:)])
CPDragServerAutoscrollInterval = setInterval(CPDragServerAutoscroll, 100);
}
CPDragServerPreviousEvent = anEvent;
if (CPDragServerAutoscrollInterval !== nil)
clearInterval(CPDragServerAutoscrollInterval);
CPDragServerAutoscrollInterval = nil;
*/
var CPSharedDragServer = nil;
var CPDragServerSource = nil; var CPDragServerSource = nil;
var CPDragServerDraggingInfo = nil; var CPDragServerDraggingInfo = nil;
@@ -130,13 +150,10 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
CGPoint _draggingLocation; CGPoint _draggingLocation;
id _draggingDestination; id _draggingDestination;
BOOL _draggingDestinationWantsPeriodicUpdates;
CGPoint _startDragLocation; CGPoint _startDragLocation;
BOOL _shouldSlideBack; BOOL _shouldSlideBack;
unsigned _dragOperation; unsigned _dragOperation;
CPTimer _draggingUpdateTimer;
} }
/* /*
@@ -217,9 +234,6 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
- (CPDragOperation)draggingUpdatedInPlatformWindow:(CPPlatformWindow)aPlatformWindow location:(CGPoint)aLocation - (CPDragOperation)draggingUpdatedInPlatformWindow:(CPPlatformWindow)aPlatformWindow location:(CGPoint)aLocation
{ {
[_draggingUpdateTimer invalidate];
_draggingUpdateTimer = nil;
var dragOperation = CPDragOperationCopy; var dragOperation = CPDragOperationCopy;
// We have to convert base to bridge since the drag event comes from the source window, not the drag window. // We have to convert base to bridge since the drag event comes from the source window, not the drag window.
var draggingDestination = [aPlatformWindow _dragHitTest:aLocation pasteboard:[CPDragServerDraggingInfo draggingPasteboard]]; var draggingDestination = [aPlatformWindow _dragHitTest:aLocation pasteboard:[CPDragServerDraggingInfo draggingPasteboard]];
@@ -229,89 +243,25 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
if(draggingDestination !== _draggingDestination) if(draggingDestination !== _draggingDestination)
{ {
if ([_draggingDestination respondsToSelector:@selector(draggingExited:)]) if (_draggingDestination && [_draggingDestination respondsToSelector:@selector(draggingExited:)])
[_draggingDestination draggingExited:CPDragServerDraggingInfo]; [_draggingDestination draggingExited:CPDragServerDraggingInfo];
_draggingDestination = draggingDestination; _draggingDestination = draggingDestination;
if ([_draggingDestination respondsToSelector:@selector(wantsPeriodicDraggingUpdates)]) if (_draggingDestination && [_draggingDestination respondsToSelector:@selector(draggingEntered:)])
_draggingDestinationWantsPeriodicUpdates = [_draggingDestination wantsPeriodicDraggingUpdates];
else
_draggingDestinationWantsPeriodicUpdates = YES;
if ([_draggingDestination respondsToSelector:@selector(draggingEntered:)])
dragOperation = [_draggingDestination draggingEntered:CPDragServerDraggingInfo]; dragOperation = [_draggingDestination draggingEntered:CPDragServerDraggingInfo];
} }
else if ([_draggingDestination respondsToSelector:@selector(draggingUpdated:)]) else if (_draggingDestination && [_draggingDestination respondsToSelector:@selector(draggingUpdated:)])
dragOperation = [_draggingDestination draggingUpdated:CPDragServerDraggingInfo]; dragOperation = [_draggingDestination draggingUpdated:CPDragServerDraggingInfo];
if (!_draggingDestination) if (!_draggingDestination)
dragOperation = CPDragOperationNone; dragOperation = CPDragOperationNone;
else
{
if (_draggingDestinationWantsPeriodicUpdates)
_draggingUpdateTimer = [CPTimer scheduledTimerWithTimeInterval:CPDragServerPeriodicUpdateInterval
target:self
selector:@selector(_sendPeriodicDraggingUpdate:)
userInfo:[CPDictionary dictionaryWithJSObject:{platformWindow:aPlatformWindow, location:aLocation}]
repeats:NO];
var scrollView = [_draggingDestination isKindOfClass:[CPView class]] ? [_draggingDestination enclosingScrollView] : nil;
if (scrollView)
{
var contentView = [scrollView contentView],
bounds = [contentView bounds],
insetBounds = CGRectInset(bounds, 10, 10),
eventLocation = [contentView convertPoint:_draggingLocation fromView:nil],
deltaX = 0,
deltaY = 0;
if (!CGRectContainsPoint(insetBounds, eventLocation))
{
if ([scrollView hasVerticalScroller])
{
if (eventLocation.y < CGRectGetMinY(insetBounds))
deltaY = CGRectGetMinY(insetBounds) - eventLocation.y;
else if (eventLocation.y > CGRectGetMaxY(insetBounds))
deltaY = CGRectGetMaxY(insetBounds) - eventLocation.y;
if (deltaY < -insetBounds.size.height)
deltaY = -insetBounds.size.height;
if (deltaY > insetBounds.size.height)
deltaY = insetBounds.size.height;
}
if ([scrollView hasHorizontalScroller])
{
if (eventLocation.x < CGRectGetMinX(insetBounds))
deltaX = CGRectGetMinX(insetBounds) - eventLocation.x;
else if (eventLocation.x > CGRectGetMaxX(insetBounds))
deltaX = CGRectGetMaxX(insetBounds) - eventLocation.x;
if (deltaX < -insetBounds.size.width)
deltaX = -insetBounds.size.width;
if (deltaX > insetBounds.size.width)
deltaX = insetBounds.size.width;
}
[contentView scrollToPoint:CGPointMake(bounds.origin.x - deltaX, bounds.origin.y - deltaY)];
}
}
}
return dragOperation; return dragOperation;
} }
- (void)_sendPeriodicDraggingUpdate:(CPTimer)aTimer
{
var userInfo = [aTimer userInfo];
_dragOperation = [self draggingUpdatedInPlatformWindow:[userInfo objectForKey:@"platformWindow"]
location:[userInfo objectForKey:@"location"]];
}
- (void)draggingEndedInPlatformWindow:(CPPlatformWindow)aPlatformWindow globalLocation:(CGPoint)aLocation operation:(CPDragOperation)anOperation - (void)draggingEndedInPlatformWindow:(CPPlatformWindow)aPlatformWindow globalLocation:(CGPoint)aLocation operation:(CPDragOperation)anOperation
{ {
[_draggingUpdateTimer invalidate];
_draggingUpdateTimer = nil;
[_draggedView removeFromSuperview]; [_draggedView removeFromSuperview];
if (![CPPlatform supportsDragAndDrop]) if (![CPPlatform supportsDragAndDrop])
@@ -327,8 +277,8 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
- (void)performDragOperationInPlatformWindow:(CPPlatformWindow)aPlatformWindow - (void)performDragOperationInPlatformWindow:(CPPlatformWindow)aPlatformWindow
{ {
if (_draggingDestination && if (_draggingDestination &&
(![_draggingDestination respondsToSelector:@selector(prepareForDragOperation:)] || [_draggingDestination prepareForDragOperation:CPDragServerDraggingInfo]) && (![_draggingDestination respondsToSelector:@selector(prepareForDragOperation:)] || [_draggingDestination prepareForDragOperation:CPDragServerDraggingInfo]) &&
(![_draggingDestination respondsToSelector:@selector(performDragOperation:)] || [_draggingDestination performDragOperation:CPDragServerDraggingInfo]) && (![_draggingDestination respondsToSelector:@selector(performDragOperation:)] || [_draggingDestination performDragOperation:CPDragServerDraggingInfo]) &&
[_draggingDestination respondsToSelector:@selector(concludeDragOperation:)]) [_draggingDestination respondsToSelector:@selector(concludeDragOperation:)])
[_draggingDestination concludeDragOperation:CPDragServerDraggingInfo]; [_draggingDestination concludeDragOperation:CPDragServerDraggingInfo];
@@ -454,25 +404,13 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
// Stop tracking events. // Stop tracking events.
return; return;
} }
else if (type === CPKeyDown)
{ [self draggingSourceUpdatedWithGlobalLocation:platformWindowLocation];
var keyCode = [anEvent keyCode]; _dragOperation = [self draggingUpdatedInPlatformWindow:platformWindow location:platformWindowLocation];
if (keyCode === CPEscapeKeyCode)
{
_dragOperation = CPDragOperationNone;
[self draggingEndedInPlatformWindow:platformWindow globalLocation:CGPointMakeZero() operation:_dragOperation];
return;
}
}
else
{
[self draggingSourceUpdatedWithGlobalLocation:platformWindowLocation];
_dragOperation = [self draggingUpdatedInPlatformWindow:platformWindow location:platformWindowLocation];
}
// If we're not a mouse up, then we're going to want to grab the next event. // If we're not a mouse up, then we're going to want to grab the next event.
[CPApp setTarget:self selector:@selector(trackDragging:) [CPApp setTarget:self selector:@selector(trackDragging:)
forNextEventMatchingMask:CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPKeyDownMask forNextEventMatchingMask:CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask
untilDate:nil inMode:0 dequeue:NO]; untilDate:nil inMode:0 dequeue:NO];
} }
+38 -165
View File
@@ -21,7 +21,8 @@
*/ */
@import <Foundation/CPObject.j> @import <Foundation/CPObject.j>
@import "CPText.j"
#include "CoreGraphics/CGGeometry.h"
CPLeftMouseDown = 1; CPLeftMouseDown = 1;
@@ -40,7 +41,7 @@ CPAppKitDefined = 13;
CPSystemDefined = 14; CPSystemDefined = 14;
CPApplicationDefined = 15; CPApplicationDefined = 15;
CPPeriodic = 16; CPPeriodic = 16;
CPCursorUpdate = 17; CPCursorUpdate = 17;
CPScrollWheel = 22; CPScrollWheel = 22;
CPOtherMouseDown = 25; CPOtherMouseDown = 25;
CPOtherMouseUp = 26; CPOtherMouseUp = 26;
@@ -51,7 +52,8 @@ CPTouchStart = 28;
CPTouchMove = 29; CPTouchMove = 29;
CPTouchEnd = 30; CPTouchEnd = 30;
CPTouchCancel = 31; CPTouchCancel = 31;
CPAlphaShiftKeyMask = 1 << 16; CPAlphaShiftKeyMask = 1 << 16;
CPShiftKeyMask = 1 << 17; CPShiftKeyMask = 1 << 17;
CPControlKeyMask = 1 << 18; CPControlKeyMask = 1 << 18;
@@ -85,102 +87,26 @@ CPPeriodicMask = 1 << CPPeriodic;
CPScrollWheelMask = 1 << CPScrollWheel; CPScrollWheelMask = 1 << CPScrollWheel;
CPAnyEventMask = 0xffffffff; CPAnyEventMask = 0xffffffff;
CPUpArrowFunctionKey = "\uF700"; CPDOMEventDoubleClick = "dblclick",
CPDownArrowFunctionKey = "\uF701"; CPDOMEventMouseDown = "mousedown",
CPLeftArrowFunctionKey = "\uF702"; CPDOMEventMouseUp = "mouseup",
CPRightArrowFunctionKey = "\uF703"; CPDOMEventMouseMoved = "mousemove",
CPF1FunctionKey = "\uF704"; CPDOMEventMouseDragged = "mousedrag",
CPF2FunctionKey = "\uF705"; CPDOMEventKeyUp = "keyup",
CPF3FunctionKey = "\uF706"; CPDOMEventKeyDown = "keydown",
CPF4FunctionKey = "\uF707"; CPDOMEventKeyPress = "keypress";
CPF5FunctionKey = "\uF708"; CPDOMEventCopy = "copy";
CPF6FunctionKey = "\uF709"; CPDOMEventPaste = "paste";
CPF7FunctionKey = "\uF70A"; CPDOMEventScrollWheel = "mousewheel";
CPF8FunctionKey = "\uF70B"; CPDOMEventTouchStart = "touchstart";
CPF9FunctionKey = "\uF70C"; CPDOMEventTouchMove = "touchmove";
CPF10FunctionKey = "\uF70D"; CPDOMEventTouchEnd = "touchend";
CPF11FunctionKey = "\uF70E"; CPDOMEventTouchCancel = "touchcancel";
CPF12FunctionKey = "\uF70F";
CPF13FunctionKey = "\uF710";
CPF14FunctionKey = "\uF711";
CPF15FunctionKey = "\uF712";
CPF16FunctionKey = "\uF713";
CPF17FunctionKey = "\uF714";
CPF18FunctionKey = "\uF715";
CPF19FunctionKey = "\uF716";
CPF20FunctionKey = "\uF717";
CPF21FunctionKey = "\uF718";
CPF22FunctionKey = "\uF719";
CPF23FunctionKey = "\uF71A";
CPF24FunctionKey = "\uF71B";
CPF25FunctionKey = "\uF71C";
CPF26FunctionKey = "\uF71D";
CPF27FunctionKey = "\uF71E";
CPF28FunctionKey = "\uF71F";
CPF29FunctionKey = "\uF720";
CPF30FunctionKey = "\uF721";
CPF31FunctionKey = "\uF722";
CPF32FunctionKey = "\uF723";
CPF33FunctionKey = "\uF724";
CPF34FunctionKey = "\uF725";
CPF35FunctionKey = "\uF726";
CPInsertFunctionKey = "\uF727";
CPDeleteFunctionKey = "\uF728";
CPHomeFunctionKey = "\uF729";
CPBeginFunctionKey = "\uF72A";
CPEndFunctionKey = "\uF72B";
CPPageUpFunctionKey = "\uF72C";
CPPageDownFunctionKey = "\uF72D";
CPPrintScreenFunctionKey = "\uF72E";
CPScrollLockFunctionKey = "\uF72F";
CPPauseFunctionKey = "\uF730";
CPSysReqFunctionKey = "\uF731";
CPBreakFunctionKey = "\uF732";
CPResetFunctionKey = "\uF733";
CPStopFunctionKey = "\uF734";
CPMenuFunctionKey = "\uF735";
CPUserFunctionKey = "\uF736";
CPSystemFunctionKey = "\uF737";
CPPrintFunctionKey = "\uF738";
CPClearLineFunctionKey = "\uF739";
CPClearDisplayFunctionKey = "\uF73A";
CPInsertLineFunctionKey = "\uF73B";
CPDeleteLineFunctionKey = "\uF73C";
CPInsertCharFunctionKey = "\uF73D";
CPDeleteCharFunctionKey = "\uF73E";
CPPrevFunctionKey = "\uF73F";
CPNextFunctionKey = "\uF740";
CPSelectFunctionKey = "\uF741";
CPExecuteFunctionKey = "\uF742";
CPUndoFunctionKey = "\uF743";
CPRedoFunctionKey = "\uF744";
CPFindFunctionKey = "\uF745";
CPHelpFunctionKey = "\uF746";
CPModeSwitchFunctionKey = "\uF747";
CPEscapeFunctionKey = "\u001B";
CPDOMEventDoubleClick = "dblclick",
CPDOMEventMouseDown = "mousedown",
CPDOMEventMouseUp = "mouseup",
CPDOMEventMouseMoved = "mousemove",
CPDOMEventMouseDragged = "mousedrag",
CPDOMEventKeyUp = "keyup",
CPDOMEventKeyDown = "keydown",
CPDOMEventKeyPress = "keypress";
CPDOMEventCopy = "copy";
CPDOMEventPaste = "paste";
CPDOMEventScrollWheel = "mousewheel";
CPDOMEventTouchStart = "touchstart";
CPDOMEventTouchMove = "touchmove";
CPDOMEventTouchEnd = "touchend";
CPDOMEventTouchCancel = "touchcancel";
var _CPEventPeriodicEventPeriod = 0, var _CPEventPeriodicEventPeriod = 0,
_CPEventPeriodicEventTimer = nil, _CPEventPeriodicEventTimer = nil;
_CPEventUpperCaseRegex = new RegExp("[A-Z]");
/*! /*!
@ingroup appkit @ingroup appkit
@class CPEvent @class CPEvent
CPEvent encapsulates the details of a Cappuccino keyboard or mouse event. CPEvent encapsulates the details of a Cappuccino keyboard or mouse event.
@@ -229,7 +155,7 @@ var _CPEventPeriodicEventPeriod = 0,
characters:(CPString)characters charactersIgnoringModifiers:(CPString)unmodCharacters isARepeat:(BOOL)repeatKey keyCode:(unsigned short)code characters:(CPString)characters charactersIgnoringModifiers:(CPString)unmodCharacters isARepeat:(BOOL)repeatKey keyCode:(unsigned short)code
{ {
return [[self alloc] _initKeyEventWithType:anEventType location:aPoint modifierFlags:modifierFlags return [[self alloc] _initKeyEventWithType:anEventType location:aPoint modifierFlags:modifierFlags
timestamp:aTimestamp windowNumber:aWindowNumber context:aGraphicsContext timestamp:aTimestamp windowNumber:aWindowNumber context:aGraphicsContext
characters:characters charactersIgnoringModifiers:unmodCharacters isARepeat:repeatKey keyCode:code]; characters:characters charactersIgnoringModifiers:unmodCharacters isARepeat:repeatKey keyCode:code];
} }
@@ -247,7 +173,7 @@ var _CPEventPeriodicEventPeriod = 0,
@throws CPInternalInconsistencyException if an invalid event type is provided @throws CPInternalInconsistencyException if an invalid event type is provided
@return the new mouse event @return the new mouse event
*/ */
+ (id)mouseEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned)modifierFlags + (id)mouseEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned)modifierFlags
timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
eventNumber:(int)anEventNumber clickCount:(int)aClickCount pressure:(float)aPressure eventNumber:(int)anEventNumber clickCount:(int)aClickCount pressure:(float)aPressure
{ {
@@ -278,12 +204,12 @@ var _CPEventPeriodicEventPeriod = 0,
} }
/* @ignore */ /* @ignore */
- (id)_initMouseEventWithType:(CPEventType)anEventType location:(CPPoint)aPoint modifierFlags:(unsigned)modifierFlags - (id)_initMouseEventWithType:(CPEventType)anEventType location:(CPPoint)aPoint modifierFlags:(unsigned)modifierFlags
timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
eventNumber:(int)anEventNumber clickCount:(int)aClickCount pressure:(float)aPressure eventNumber:(int)anEventNumber clickCount:(int)aClickCount pressure:(float)aPressure
{ {
self = [super init]; self = [super init];
if (self) if (self)
{ {
_type = anEventType; _type = anEventType;
@@ -296,7 +222,7 @@ var _CPEventPeriodicEventPeriod = 0,
_pressure = aPressure; _pressure = aPressure;
_window = [CPApp windowWithWindowNumber:aWindowNumber]; _window = [CPApp windowWithWindowNumber:aWindowNumber];
} }
return self; return self;
} }
@@ -306,7 +232,7 @@ var _CPEventPeriodicEventPeriod = 0,
characters:(CPString)characters charactersIgnoringModifiers:(CPString)unmodCharacters isARepeat:(BOOL)isARepeat keyCode:(unsigned short)code characters:(CPString)characters charactersIgnoringModifiers:(CPString)unmodCharacters isARepeat:(BOOL)isARepeat keyCode:(unsigned short)code
{ {
self = [super init]; self = [super init];
if (self) if (self)
{ {
_type = anEventType; _type = anEventType;
@@ -320,7 +246,7 @@ var _CPEventPeriodicEventPeriod = 0,
_keyCode = code; _keyCode = code;
_windowNumber = aWindowNumber; _windowNumber = aWindowNumber;
} }
return self; return self;
} }
@@ -330,7 +256,7 @@ var _CPEventPeriodicEventPeriod = 0,
subtype:(short)aSubtype data1:(int)aData1 data2:(int)aData2 subtype:(short)aSubtype data1:(int)aData1 data2:(int)aData2
{ {
self = [super init]; self = [super init];
if (self) if (self)
{ {
_type = anEventType; _type = anEventType;
@@ -341,7 +267,7 @@ var _CPEventPeriodicEventPeriod = 0,
_subtype = aSubtype; _subtype = aSubtype;
_data1 = aData1; _data1 = aData1;
_data2 = aData2; _data2 = aData2;
} }
return self; return self;
} }
@@ -519,76 +445,23 @@ var _CPEventPeriodicEventPeriod = 0,
return _deltaZ; return _deltaZ;
} }
- (BOOL)_triggersKeyEquivalent:(CPString)aKeyEquivalent withModifierMask:aKeyEquivalentModifierMask
{
if (!aKeyEquivalent)
return NO;
if (_CPEventUpperCaseRegex.test(aKeyEquivalent))
aKeyEquivalentModifierMask |= CPShiftKeyMask;
if (CPBrowserIsOperatingSystem(CPWindowsOperatingSystem) && (aKeyEquivalentModifierMask & CPCommandKeyMask))
{
aKeyEquivalentModifierMask |= CPControlKeyMask;
aKeyEquivalentModifierMask &= ~CPCommandKeyMask;
}
if ((_modifierFlags & (CPShiftKeyMask | CPAlternateKeyMask | CPCommandKeyMask | CPControlKeyMask)) !== aKeyEquivalentModifierMask)
return NO;
// 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 - (BOOL)_couldBeKeyEquivalent
{ {
if (_type !== CPKeyDown)
return NO;
var characterCount = _characters.length;
if (!characterCount)
return NO;
if (_modifierFlags & (CPCommandKeyMask | CPControlKeyMask))
return YES;
for(var i=0; i<characterCount; i++)
{
switch(_characters.charAt(i))
{
case CPBackspaceCharacter:
case CPDeleteCharacter:
case CPDeleteFunctionKey:
case CPTabCharacter:
case CPCarriageReturnCharacter:
case CPNewlineCharacter:
case CPEscapeFunctionKey:
case CPPageUpFunctionKey:
case CPPageDownFunctionKey:
case CPLeftArrowFunctionKey:
case CPUpArrowFunctionKey:
case CPRightArrowFunctionKey:
case CPDownArrowFunctionKey:
return YES;
}
}
// FIXME: More cases? Space? // FIXME: More cases? Space?
return NO; return _type === CPKeyDown &&
_modifierFlags & (CPCommandKeyMask | CPControlKeyMask) &&
[_characters length] > 0;
} }
/*! /*!
Gene rates periodic events every \c aPeriod seconds. Generates periodic events every \c aPeriod seconds.
@param aDelay the number of seconds before the first event @param aDelay the number of seconds before the first event
@param aPeriod the length of time in seconds between successive events @param aPeriod the length of time in seconds between successive events
*/ */
+ (void)startPeriodicEventsAfterDelay:(CPTimeInterval)aDelay withPeriod:(CPTimeInterval)aPeriod + (void)startPeriodicEventsAfterDelay:(CPTimeInterval)aDelay withPeriod:(CPTimeInterval)aPeriod
{ {
_CPEventPeriodicEventPeriod = aPeriod; _CPEventPeriodicEventPeriod = aPeriod;
// FIXME: OH TIMERS!!! // FIXME: OH TIMERS!!!
_CPEventPeriodicEventTimer = window.setTimeout(function() { _CPEventPeriodicEventTimer = window.setInterval(_CPEventFirePeriodEvent, aPeriod * 1000.0); }, aDelay * 1000.0); _CPEventPeriodicEventTimer = window.setTimeout(function() { _CPEventPeriodicEventTimer = window.setInterval(_CPEventFirePeriodEvent, aPeriod * 1000.0); }, aDelay * 1000.0);
} }
@@ -600,9 +473,9 @@ var _CPEventPeriodicEventPeriod = 0,
{ {
if (_CPEventPeriodicEventTimer === nil) if (_CPEventPeriodicEventTimer === nil)
return; return;
window.clearTimeout(_CPEventPeriodicEventTimer); window.clearTimeout(_CPEventPeriodicEventTimer);
_CPEventPeriodicEventTimer = nil; _CPEventPeriodicEventTimer = nil;
} }
-1
View File
@@ -22,7 +22,6 @@
@import <Foundation/CPObject.j> @import <Foundation/CPObject.j>
/*! /*!
@ingroup appkit @ingroup appkit
@class CPFlashMovie @class CPFlashMovie
+1
View File
@@ -23,6 +23,7 @@
@import "CPFlashMovie.j" @import "CPFlashMovie.j"
@import "CPView.j" @import "CPView.j"
#include "Platform/Platform.h"
var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"; var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
+8 -73
View File
@@ -20,12 +20,6 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
@import <Foundation/CPObject.j>
@import <Foundation/CPBundle.j>
@import "CPView.j"
var _CPFonts = {}, var _CPFonts = {},
_CPFontSystemFontFace = @"Arial, sans-serif", _CPFontSystemFontFace = @"Arial, sans-serif",
_CPWrapRegExp = new RegExp("\\s*,\\s*", "g"); _CPWrapRegExp = new RegExp("\\s*,\\s*", "g");
@@ -34,7 +28,7 @@ var _CPFonts = {},
#define _CPCreateCSSString(aName, aSize, isBold) (isBold ? @"bold " : @"") + ROUND(aSize) + @"px " + ((aName === _CPFontSystemFontFace) ? aName : (@"\"" + aName.replace(_CPWrapRegExp, '", "') + @"\", " + _CPFontSystemFontFace)) #define _CPCreateCSSString(aName, aSize, isBold) (isBold ? @"bold " : @"") + ROUND(aSize) + @"px " + ((aName === _CPFontSystemFontFace) ? aName : (@"\"" + aName.replace(_CPWrapRegExp, '", "') + @"\", " + _CPFontSystemFontFace))
#define _CPCachedFont(aName, aSize, isBold) _CPFonts[_CPCreateCSSString(aName, aSize, isBold)] #define _CPCachedFont(aName, aSize, isBold) _CPFonts[_CPCreateCSSString(aName, aSize, isBold)]
/*! /*!
@ingroup appkit @ingroup appkit
@class CPFont @class CPFont
@@ -44,22 +38,11 @@ var _CPFonts = {},
{ {
CPString _name; CPString _name;
float _size; float _size;
float _ascender;
float _descender;
float _lineHeight;
BOOL _isBold; BOOL _isBold;
CPString _cssString; 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. Returns a font with the specified name and size.
@param aName the name of the font @param aName the name of the font
@@ -106,64 +89,25 @@ var _CPFonts = {},
@ignore @ignore
*/ */
- (id)_initWithName:(CPString)aName size:(float)aSize bold:(BOOL)isBold - (id)_initWithName:(CPString)aName size:(float)aSize bold:(BOOL)isBold
{ {
self = [super init]; self = [super init];
if (self) if (self)
{ {
_name = aName; _name = aName;
_size = aSize; _size = aSize;
_ascender = 0;
_descender = 0;
_lineHeight = 0;
_isBold = isBold; _isBold = isBold;
_cssString = _CPCreateCSSString(_name, _size, _isBold); _cssString = _CPCreateCSSString(_name, _size, _isBold);
_CPFonts[_cssString] = self; _CPFonts[_cssString] = self;
} }
return self; return self;
} }
/*! /*!
Returns the distance of the longest ascender's top y-coordinate from the baseline (in CSS px) Returns the font size (in points)
*/
- (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 - (float)size
{ {
@@ -196,15 +140,6 @@ var _CPFonts = {},
return [CPString stringWithFormat:@"%@ %@ %f pt.", [super description], [self familyName], [self size]]; 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 @end
var CPFontNameKey = @"CPFontNameKey", var CPFontNameKey = @"CPFontNameKey",
+1 -1
View File
@@ -22,7 +22,7 @@
@import <Foundation/CPObject.j> @import <Foundation/CPObject.j>
@import "CPFont.j" @import <AppKit/CPFont.j>
var CPSharedFontManager = nil, var CPSharedFontManager = nil,
+15 -29
View File
@@ -70,7 +70,7 @@ function CPPointMake(x, y)
*/ */
function CPRectInset(aRect, dX, dY) 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); aRect.size.width - 2 * dX, aRect.size.height - 2*dY);
} }
@@ -96,13 +96,13 @@ function CPRectIntegral(aRect)
function CPRectIntersection(lhsRect, rhsRect) function CPRectIntersection(lhsRect, rhsRect)
{ {
var intersection = CPRectMake( var intersection = CPRectMake(
Math.max(CPRectGetMinX(lhsRect), CPRectGetMinX(rhsRect)), Math.max(CPRectGetMinX(lhsRect), CPRectGetMinX(rhsRect)),
Math.max(CPRectGetMinY(lhsRect), CPRectGetMinY(rhsRect)), Math.max(CPRectGetMinY(lhsRect), CPRectGetMinY(rhsRect)),
0, 0); 0, 0);
intersection.size.width = Math.min(CPRectGetMaxX(lhsRect), CPRectGetMaxX(rhsRect)) - CPRectGetMinX(intersection); intersection.size.width = Math.min(CPRectGetMaxX(lhsRect), CPRectGetMaxX(rhsRect)) - CPRectGetMinX(intersection);
intersection.size.height = Math.min(CPRectGetMaxY(lhsRect), CPRectGetMaxY(rhsRect)) - CPRectGetMinY(intersection); intersection.size.height = Math.min(CPRectGetMaxY(lhsRect), CPRectGetMaxY(rhsRect)) - CPRectGetMinY(intersection);
return CPRectIsEmpty(intersection) ? CPRectMakeZero() : intersection; return CPRectIsEmpty(intersection) ? CPRectMakeZero() : intersection;
} }
@@ -160,13 +160,13 @@ function CPRectStandardize(aRect)
standardized.origin.x += width; standardized.origin.x += width;
standardized.size.width = -width; standardized.size.width = -width;
} }
if (height < 0.0) if (height < 0.0)
{ {
standardized.origin.y += height; standardized.origin.y += height;
standardized.size.height = -height; standardized.size.height = -height;
} }
return standardized; return standardized;
} }
@@ -183,7 +183,7 @@ function CPRectUnion(lhsRect, rhsRect)
minY = Math.min(CPRectGetMinY(lhsRect), CPRectGetMinY(rhsRect)), minY = Math.min(CPRectGetMinY(lhsRect), CPRectGetMinY(rhsRect)),
maxX = Math.max(CPRectGetMaxX(lhsRect), CPRectGetMaxX(rhsRect)), maxX = Math.max(CPRectGetMaxX(lhsRect), CPRectGetMaxX(rhsRect)),
maxY = Math.max(CPRectGetMaxY(lhsRect), CPRectGetMaxY(rhsRect)); maxY = Math.max(CPRectGetMaxY(lhsRect), CPRectGetMaxY(rhsRect));
return CPRectMake(minX, minY, maxX - minX, maxY - minY); return CPRectMake(minX, minY, maxX - minX, maxY - minY);
} }
@@ -222,8 +222,8 @@ function CPRectContainsPoint(aRect, aPoint)
{ {
return aPoint.x >= CPRectGetMinX(aRect) && return aPoint.x >= CPRectGetMinX(aRect) &&
aPoint.y >= CPRectGetMinY(aRect) && aPoint.y >= CPRectGetMinY(aRect) &&
aPoint.x < CPRectGetMaxX(aRect) && aPoint.x < CPRectGetMaxX(aRect) &&
aPoint.y < CPRectGetMaxY(aRect); aPoint.y < CPRectGetMaxY(aRect);
} }
/*! /*!
@@ -261,7 +261,7 @@ function CPPointEqualToPoint(lhsPoint, rhsPoint)
*/ */
function CPRectEqualToRect(lhsRect, rhsRect) function CPRectEqualToRect(lhsRect, rhsRect)
{ {
return CPPointEqualToPoint(lhsRect.origin, rhsRect.origin) && return CPPointEqualToPoint(lhsRect.origin, rhsRect.origin) &&
CPSizeEqualToSize(lhsRect.size, rhsRect.size); CPSizeEqualToSize(lhsRect.size, rhsRect.size);
} }
@@ -380,20 +380,6 @@ function CPRectIsNull(aRect)
return aRect.size.width <= 0.0 || aRect.size.height <= 0.0; 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. Returns \c YES if the two CGSizes are identical.
@group CGSize @group CGSize
@@ -448,7 +434,7 @@ function CPStringFromRect(aRect)
function CPPointFromString(aString) function CPPointFromString(aString)
{ {
var comma = aString.indexOf(','); var comma = aString.indexOf(',');
return { x:parseFloat(aString.substr(1, comma - 1), 10), y:parseFloat(aString.substring(comma + 1, aString.length), 10) }; return { x:parseFloat(aString.substr(1, comma - 1), 10), y:parseFloat(aString.substring(comma + 1, aString.length), 10) };
} }
@@ -461,7 +447,7 @@ function CPPointFromString(aString)
function CPSizeFromString(aString) function CPSizeFromString(aString)
{ {
var comma = aString.indexOf(','); var comma = aString.indexOf(',');
return { width:parseFloat(aString.substr(1, comma - 1), 10), height:parseFloat(aString.substring(comma + 1, aString.length), 10) }; return { width:parseFloat(aString.substr(1, comma - 1), 10), height:parseFloat(aString.substring(comma + 1, aString.length), 10) };
} }
@@ -474,7 +460,7 @@ function CPSizeFromString(aString)
function CPRectFromString(aString) function CPRectFromString(aString)
{ {
var comma = aString.indexOf(',', aString.indexOf(',') + 1); var comma = aString.indexOf(',', aString.indexOf(',') + 1);
return { origin:CPPointFromString(aString.substr(1, comma - 1)), size:CPSizeFromString(aString.substring(comma + 2, aString.length)) }; return { origin:CPPointFromString(aString.substr(1, comma - 1)), size:CPSizeFromString(aString.substring(comma + 2, aString.length)) };
} }
@@ -518,6 +504,6 @@ function CPPointMakeZero()
return CPPointMake(0, 0, 0); return CPPointMake(0, 0, 0);
} }
/*! /*!
@} @}
*/ */
-108
View File
@@ -1,108 +0,0 @@
/*
* 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"
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;
}
-5
View File
@@ -20,11 +20,6 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
@import <Foundation/CPObject.j>
@import "CGContext.j"
var CPGraphicsContextCurrent = nil; var CPGraphicsContextCurrent = nil;
/*! /*!
+6 -9
View File
@@ -28,6 +28,8 @@
@import "CPGeometry.j" @import "CPGeometry.j"
#include "Platform/Platform.h"
CPImageLoadStatusInitialized = 0; CPImageLoadStatusInitialized = 0;
CPImageLoadStatusLoading = 1; CPImageLoadStatusLoading = 1;
@@ -191,9 +193,6 @@ function CPAppKitImage(aFilename, aSize)
var imageOrSize = AppKitImageForNames[aName]; var imageOrSize = AppKitImageForNames[aName];
if (!imageOrSize)
return nil;
if (!imageOrSize.isa) if (!imageOrSize.isa)
{ {
imageOrSize = CPAppKitImage("CPImage/" + aName + ".png", imageOrSize); imageOrSize = CPAppKitImage("CPImage/" + aName + ".png", imageOrSize);
@@ -206,19 +205,17 @@ function CPAppKitImage(aFilename, aSize)
return imageOrSize; return imageOrSize;
} }
- (BOOL)setName:(CPString)aName - (void)setName:(CPString)aName
{ {
if (_name === aName) if (_name === aName)
return YES; return;
if (imagesForNames[aName]) if (imagesForNames[aName] === self)
return NO; imagesForNames[aName] = nil;
_name = aName; _name = aName;
imagesForNames[aName] = self; imagesForNames[aName] = self;
return YES;
} }
- (CPString)name - (CPString)name
+18 -99
View File
@@ -26,23 +26,16 @@
@import "CPImage.j" @import "CPImage.j"
@import "CPShadowView.j" @import "CPShadowView.j"
#include "Platform/Platform.h"
#include "Platform/DOM/CPDOMDisplayServer.h"
#include "CoreGraphics/CGGeometry.h"
CPScaleProportionally = 0; CPScaleProportionally = 0;
CPScaleToFit = 1; CPScaleToFit = 1;
CPScaleNone = 2; CPScaleNone = 2;
CPImageAlignCenter = 0; var CPImageViewShadowBackgroundColor = nil;
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, var LEFT_SHADOW_INSET = 3.0,
RIGHT_SHADOW_INSET = 3.0, RIGHT_SHADOW_INSET = 3.0,
@@ -59,22 +52,14 @@ var LEFT_SHADOW_INSET = 3.0,
*/ */
@implementation CPImageView : CPControl @implementation CPImageView : CPControl
{ {
DOMElement _DOMImageElement; DOMElement _DOMImageElement;
BOOL _hasShadow; BOOL _hasShadow;
CPView _shadowView; 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 - (id)initWithFrame:(CGRect)aFrame
@@ -135,7 +120,7 @@ var LEFT_SHADOW_INSET = 3.0,
var newImage = [self objectValue]; var newImage = [self objectValue];
#if PLATFORM(DOM) #if PLATFORM(DOM)
_DOMImageElement.src = newImage ? [newImage filename] : [CPImageViewEmptyPlaceholderImage filename]; _DOMImageElement.src = newImage ? [newImage filename] : "";
#endif #endif
var size = [newImage size]; var size = [newImage size];
@@ -206,30 +191,6 @@ var LEFT_SHADOW_INSET = 3.0,
[self hideOrDisplayContents]; [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 Sets the type of image scaling that should be used to
render the image. render the image.
@@ -357,45 +318,8 @@ var LEFT_SHADOW_INSET = 3.0,
#endif #endif
} }
var x, y; var x = (boundsWidth - width) / 2.0,
y = (boundsHeight - height) / 2.0;
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) #if PLATFORM(DOM)
CPDOMDisplayServerSetStyleLeftTop(_DOMImageElement, NULL, x, y); CPDOMDisplayServerSetStyleLeftTop(_DOMImageElement, NULL, x, y);
@@ -441,7 +365,7 @@ var LEFT_SHADOW_INSET = 3.0,
return _isEditable; return _isEditable;
} }
- (BOOL)performDragOperation:(CPDraggingInfo)aSender - (void)performDragOperation:(CPDraggingInfo)aSender
{ {
var images = [CPKeyedUnarchiver unarchiveObjectWithData:[[aSender draggingPasteboard] dataForType:CPImagesPboardType]]; var images = [CPKeyedUnarchiver unarchiveObjectWithData:[[aSender draggingPasteboard] dataForType:CPImagesPboardType]];
@@ -450,17 +374,14 @@ var LEFT_SHADOW_INSET = 3.0,
[self setImage:images[0]]; [self setImage:images[0]];
[self sendAction:[self action] to:[self target]]; [self sendAction:[self action] to:[self target]];
} }
return YES;
} }
@end @end
var CPImageViewImageKey = @"CPImageViewImageKey", var CPImageViewImageKey = @"CPImageViewImageKey",
CPImageViewImageScalingKey = @"CPImageViewImageScalingKey", CPImageViewImageScalingKey = @"CPImageViewImageScalingKey",
CPImageViewImageAlignmentKey = @"CPImageViewImageAlignmentKey", CPImageViewHasShadowKey = @"CPImageViewHasShadowKey",
CPImageViewHasShadowKey = @"CPImageViewHasShadowKey", CPImageViewIsEditableKey = @"CPImageViewIsEditableKey";
CPImageViewIsEditableKey = @"CPImageViewIsEditableKey";
@implementation CPImageView (CPCoding) @implementation CPImageView (CPCoding)
@@ -493,7 +414,6 @@ var CPImageViewImageKey = @"CPImageViewImageKey",
#endif #endif
[self setHasShadow:[aCoder decodeBoolForKey:CPImageViewHasShadowKey]]; [self setHasShadow:[aCoder decodeBoolForKey:CPImageViewHasShadowKey]];
[self setImageAlignment:[aCoder decodeIntForKey:CPImageViewImageAlignmentKey]];
if ([aCoder decodeBoolForKey:CPImageViewIsEditableKey] || NO) if ([aCoder decodeBoolForKey:CPImageViewIsEditableKey] || NO)
[self setEditable:YES]; [self setEditable:YES];
@@ -528,7 +448,6 @@ var CPImageViewImageKey = @"CPImageViewImageKey",
_subviews = actualSubviews; _subviews = actualSubviews;
[aCoder encodeBool:_hasShadow forKey:CPImageViewHasShadowKey]; [aCoder encodeBool:_hasShadow forKey:CPImageViewHasShadowKey];
[aCoder encodeInt:_imageAlignment forKey:CPImageViewImageAlignmentKey];
if (_isEditable) if (_isEditable)
[aCoder encodeBool:_isEditable forKey:CPImageViewIsEditableKey]; [aCoder encodeBool:_isEditable forKey:CPImageViewIsEditableKey];
-263
View File
@@ -1,263 +0,0 @@
/*
* 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>
@import "CPEvent.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)
[self cacheKeyBinding:[[CPKeyBinding alloc] initWithPhysicalKeyString:binding selectors:anObject[binding]]];
}
+ (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)initWithPhysicalKeyString:(CPString)binding selectors:(CPArray)selectors
{
var components = binding.split(@""),
modifierFlags = ([components containsObject:@"$"] ? CPShiftKeyMask : 0) |
([components containsObject:@"^"] ? CPControlKeyMask : 0) |
([components containsObject:@"~"] ? CPAlternateKeyMask : 0) |
([components containsObject:@"@"] ? CPCommandKeyMask : 0);
if (![selectors isKindOfClass:CPArray])
selectors = [selectors];
return [self initWithKey:[components lastObject] modifierFlags:modifierFlags selectors: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];
}
- (CPString)description
{
return [CPString stringWithFormat:@"<KeyBinding string: '%@' modifierFlags: 0x%lx selectors: %@>", _key, _modifierFlags, _selectors];
}
@end
-472
View File
@@ -1,472 +0,0 @@
/*
* CPKeyValueBinding.j
* AppKit
*
* Created by Ross Boucher 1/13/09
* Copyright 280 North, Inc.
*
* Adapted from GNUStep
* Released under the LGPL.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPObject.j>
@import <Foundation/CPArray.j>
@import <Foundation/CPDictionary.j>
@import <Foundation/CPValueTransformer.j>
var exposedBindingsMap = [CPDictionary new],
bindingsMap = [CPDictionary new];
var CPBindingOperationAnd = 0,
CPBindingOperationOr = 1;
@implementation CPKeyValueBinding : CPObject
{
CPDictionary _info;
id _source;
}
+ (void)exposeBinding:(CPString)aBinding forClass:(Class)aClass
{
var bindings = [exposedBindingsMap objectForKey:[aClass hash]];
if (!bindings)
{
bindings = [];
[exposedBindingsMap setObject:bindings forKey:[aClass hash]];
}
bindings.push(aBinding);
}
+ (CPArray)exposedBindingsForClass:(Class)aClass
{
return [[exposedBindingsMap objectForKey:[aClass hash]] copy];
}
+ (CPKeyValueBinding)getBinding:(CPString)aBinding forObject:(id)anObject
{
return [[bindingsMap objectForKey:[anObject hash]] objectForKey:aBinding];
}
+ (CPDictionary)infoForBinding:(CPString)aBinding forObject:(id)anObject
{
var theBinding = [self getBinding:aBinding forObject:anObject];
if (theBinding)
return theBinding._info;
return nil;
}
+ (CPDictionary)allBindingsForObject:(id)anObject
{
return [bindingsMap objectForKey:[anObject hash]];
}
+ (void)unbind:(CPString)aBinding forObject:(id)anObject
{
var bindings = [bindingsMap objectForKey:[anObject hash]];
if (!bindings)
return;
var theBinding = [bindings objectForKey:aBinding];
if (!theBinding)
return;
var infoDictionary = theBinding._info,
observedObject = [infoDictionary objectForKey:CPObservedObjectKey],
keyPath = [infoDictionary objectForKey:CPObservedKeyPathKey];
[observedObject removeObserver:theBinding forKeyPath:keyPath];
[bindings removeObjectForKey:aBinding];
}
+ (void)unbindAllForObject:(id)anObject
{
var bindings = [bindingsMap objectForKey:[anObject hash]];
if (!bindings)
return;
var allKeys = [bindings allKeys],
count = allKeys.length;
while (count--)
[anObject unbind:[bindings objectForKey:allKeys[count]]];
[bindingsMap removeObjectForKey:[anObject hash]];
}
- (id)initWithBinding:(CPString)aBinding name:(CPString)aName to:(id)aDestination keyPath:(CPString)aKeyPath options:(CPDictionary)options from:(id)aSource
{
self = [super init];
if (self)
{
_source = aSource;
_info = [CPDictionary dictionaryWithObjects:[aDestination, aKeyPath] forKeys:[CPObservedObjectKey, CPObservedKeyPathKey]];
if (options)
[_info setObject:options forKey:CPOptionsKey];
[aDestination addObserver:self forKeyPath:aKeyPath options:CPKeyValueObservingOptionNew context:aBinding];
var bindings = [bindingsMap objectForKey:[_source hash]];
if (!bindings)
{
bindings = [CPDictionary new];
[bindingsMap setObject:bindings forKey:[_source hash]];
}
[bindings setObject:self forKey:aName];
[self setValueFor:aBinding];
}
return self;
}
- (void)setValueFor:(CPString)aBinding
{
var destination = [_info objectForKey:CPObservedObjectKey],
keyPath = [_info objectForKey:CPObservedKeyPathKey],
options = [_info objectForKey:CPOptionsKey],
newValue = [destination valueForKeyPath:keyPath],
isPlaceholder = CPIsControllerMarker(newValue);
if (isPlaceholder)
{
switch (newValue)
{
case CPMultipleValuesMarker:
newValue = [options objectForKey:CPMultipleValuesPlaceholderBindingOption] || @"Multiple Values";
break;
case CPNoSelectionMarker:
newValue = [options objectForKey:CPNoSelectionPlaceholderBindingOption] || @"No Selection";
break;
case CPNotApplicableMarker:
if ([options objectForKey:CPRaisesForNotApplicableKeysBindingOption])
[CPException raise:CPGenericException reason:@"can't transform non applicable key on: "+_source+" value: "+newValue];
newValue = [options objectForKey:CPNotApplicablePlaceholderBindingOption] || @"Not Applicable";
break;
}
}
else
{
// Only transform the value if the current value is not a placeholder
newValue = [self transformValue:newValue withOptions:options];
}
[_source setValue:newValue forKey:aBinding];
if ([_source respondsToSelector:@selector(_setCurrentValueIsPlaceholder:)])
[_source _setCurrentValueIsPlaceholder:isPlaceholder];
}
- (void)reverseSetValueFor:(CPString)aBinding
{
var destination = [_info objectForKey:CPObservedObjectKey],
keyPath = [_info objectForKey:CPObservedKeyPathKey],
options = [_info objectForKey:CPOptionsKey],
newValue = [_source valueForKeyPath:aBinding];
newValue = [self reverseTransformValue:newValue withOptions:options];
[destination setValue:newValue forKeyPath:keyPath];
}
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)changes context:(id)context
{
if (!changes)
return;
[self setValueFor:context];
}
- (id)transformValue:(id)aValue withOptions:(CPDictionary)options
{
var valueTransformerName,
valueTransformer,
placeholder;
var valueTransformerName = [options objectForKey:CPValueTransformerNameBindingOption],
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];
if (valueTransformer)
aValue = [valueTransformer transformedValue:aValue];
if (aValue === undefined || aValue === nil)
aValue = [options objectForKey:CPNullPlaceholderBindingOption] || nil;
return aValue;
}
- (id)reverseTransformValue:(id)aValue withOptions: (CPDictionary)options
{
var valueTransformerName = [options objectForKey:CPValueTransformerNameBindingOption],
valueTransformer;
if (valueTransformerName)
valueTransformer = [CPValueTransformer valueTransformerForName:valueTransformerName];
else
valueTransformer = [options objectForKey:CPValueTransformerBindingOption];
if (valueTransformer && [[valueTransformer class] allowsReverseTransformation])
aValue = [valueTransformer reverseTransformedValue:aValue];
return aValue;
}
@end
@implementation CPObject (KeyValueBindingCreation)
+ (void)exposeBinding:(CPString)aBinding
{
[CPKeyValueBinding exposeBinding:aBinding forClass:[self class]];
}
- (CPArray)exposedBindings
{
var exposedBindings = [],
theClass = [self class];
while (theClass)
{
var temp = [CPKeyValueBinding exposedBindingsForClass:theClass];
if (temp)
[exposedBindings addObjectsFromArray:temp];
theClass = [theClass superclass];
}
return exposedBindings;
}
- (Class)valueClassForBinding:(CPString)binding
{
return [CPString class];
}
- (void)bind:(CPString)aBinding toObject:(id)anObject withKeyPath:(CPString)aKeyPath options:(CPDictionary)options
{
if (!anObject || !aKeyPath)
return CPLog.error("Invalid object or path on "+self+" for "+aBinding);
//if (![[self exposedBindings] containsObject:aBinding])
// CPLog.warn("No binding exposed on "+self+" for "+aBinding);
[self unbind:aBinding];
[[CPKeyValueBinding alloc] initWithBinding:[self _replacementKeyPathForBinding:aBinding] name:aBinding to:anObject keyPath:aKeyPath options:options from:self];
}
- (CPDictionary)infoForBinding:(CPString)aBinding
{
return [CPKeyValueBinding infoForBinding:aBinding forObject:self];
}
- (void)unbind:(CPString)aBinding
{
[CPKeyValueBinding unbind:aBinding forObject:self];
}
- (id)_replacementKeyPathForBinding:(CPString)binding
{
return binding;
}
@end
@implementation _CPKeyValueOrBinding : CPKeyValueBinding
{
}
- (void)setValueFor:(CPString)aBinding
{
var bindings = [bindingsMap valueForKey:[_source hash]];
if (!bindings)
return;
[_source setValue:resolveMultipleValues(aBinding, bindings, CPBindingOperationOr) forKey:aBinding];
}
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)changes context:(id)context
{
[self setValueFor:context];
}
@end
@implementation _CPKeyValueAndBinding : CPKeyValueBinding
{
}
- (void)setValueFor:(CPString)aBinding
{
var bindings = [bindingsMap objectForKey:[_source hash]];
if (!bindings)
return;
[_source setValue:resolveMultipleValues(aBinding, bindings, CPBindingOperationAnd) forKey:aBinding];
}
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObejct change:(CPDictionary)changes context:(id)context
{
[self setValueFor:context];
}
@end
var resolveMultipleValues = function resolveMultipleValues(/*CPString*/key, /*CPDictionary*/bindings, /*GSBindingOperationKind*/operation)
{
var bindingName = key,
theBinding,
count = 1;
while (theBinding = [bindings objectForKey:bindingName])
{
var infoDictionary = theBinding._info,
object = [infoDictionary objectForKey:CPObservedObjectKey],
keyPath = [infoDictionary objectForKey:CPObservedKeyPathKey],
options = [infoDictionary objectForKey:CPOptionsKey];
var value = [theBinding transformValue:[object valueForKeyPath:keyPath] withOptions:options];
if (value == operation)
return operation;
bindingName = [CPString stringWithFormat:@"%@%i", key, ++count];
}
return !operation;
}
var invokeAction = function invokeAction(/*CPString*/targetKey, /*CPString*/argumentKey, /*CPDictionary*/bindings)
{
var theBinding = [bindings objectForKey:targetKey],
infoDictionary = theBinding._info,
object = [infoDictionary objectForKey:CPObservedObjectKey],
keyPath = [infoDictionary objectForKey:CPObservedKeyPathKey],
options = [infoDictionary objectForKey:CPOptionsKey],
target = [object valueForKeyPath:keyPath],
selector = [options objectForKey:CPSelectorNameBindingOption];
if (!target || !selector)
return;
var invocation = [CPInvocation invocationWithMethodSignature:[target methodSignatureForSelector:selector]];
[invocation setSelector:selector];
var bindingName = argumentKey,
count = 1;
while (theBinding = [bindings objectForKey:bindingName])
{
infoDictionary = theBinding._info;
keyPath = [infoDictionary objectForKey:CPObserverKeyPathKey];
object = [[infoDictionary objectForKey:CPObservedObjectKey] valueForKeyPath:keyPath];
if (object)
[invocation setArgument:object atIndex:++count];
bindingName = [CPString stringWithFormat:@"%@%i", argumentKey, count];
}
[invocation invoke];
}
// Keys in options dictionary
// Keys in dictionary returned by infoForBinding
CPObservedObjectKey = @"CPObservedObjectKey";
CPObservedKeyPathKey = @"CPObservedKeyPathKey";
CPOptionsKey = @"CPOptionsKey";
// special markers
CPMultipleValuesMarker = @"CPMultipleValuesMarker";
CPNoSelectionMarker = @"CPNoSelectionMarker";
CPNotApplicableMarker = @"CPNotApplicableMarker";
// Binding name constants
CPAlignmentBinding = @"CPAlignmentBinding";
CPEditableBinding = @"CPEditableBinding";
CPEnabledBinding = @"CPEnabledBinding";
CPFontBinding = @"CPFontBinding";
CPHiddenBinding = @"CPHiddenBinding";
CPSelectedIndexBinding = @"CPSelectedIndexBinding";
CPTextColorBinding = @"CPTextColorBinding";
CPToolTipBinding = @"CPToolTipBinding";
CPValueBinding = @"value";
//Binding options constants
CPAllowsEditingMultipleValuesSelectionBindingOption = @"CPAllowsEditingMultipleValuesSelectionBindingOption";
CPAllowsNullArgumentBindingOption = @"CPAllowsNullArgumentBindingOption";
CPConditionallySetsEditableBindingOption = @"CPConditionallySetsEditableBindingOption";
CPConditionallySetsEnabledBindingOption = @"CPConditionallySetsEnabledBindingOption";
CPConditionallySetsHiddenBindingOption = @"CPConditionallySetsHiddenBindingOption";
CPContinuouslyUpdatesValueBindingOption = @"CPContinuouslyUpdatesValueBindingOption";
CPCreatesSortDescriptorBindingOption = @"CPCreatesSortDescriptorBindingOption";
CPDeletesObjectsOnRemoveBindingsOption = @"CPDeletesObjectsOnRemoveBindingsOption";
CPDisplayNameBindingOption = @"CPDisplayNameBindingOption";
CPDisplayPatternBindingOption = @"CPDisplayPatternBindingOption";
CPHandlesContentAsCompoundValueBindingOption = @"CPHandlesContentAsCompoundValueBindingOption";
CPInsertsNullPlaceholderBindingOption = @"CPInsertsNullPlaceholderBindingOption";
CPInvokesSeparatelyWithArrayObjectsBindingOption = @"CPInvokesSeparatelyWithArrayObjectsBindingOption";
CPMultipleValuesPlaceholderBindingOption = @"CPMultipleValuesPlaceholderBindingOption";
CPNoSelectionPlaceholderBindingOption = @"CPNoSelectionPlaceholderBindingOption";
CPNotApplicablePlaceholderBindingOption = @"CPNotApplicablePlaceholderBindingOption";
CPNullPlaceholderBindingOption = @"CPNullPlaceholderBindingOption";
CPPredicateFormatBindingOption = @"CPPredicateFormatBindingOption";
CPRaisesForNotApplicableKeysBindingOption = @"CPRaisesForNotApplicableKeysBindingOption";
CPSelectorNameBindingOption = @"CPSelectorNameBindingOption";
CPSelectsAllWhenSettingContentBindingOption = @"CPSelectsAllWhenSettingContentBindingOption";
CPValidatesImmediatelyBindingOption = @"CPValidatesImmediatelyBindingOption";
CPValueTransformerNameBindingOption = @"CPValueTransformerNameBindingOption";
CPValueTransformerBindingOption = @"CPValueTransformerBindingOption";
CPIsControllerMarker = function(/*id*/anObject)
{
return anObject === CPMultipleValuesMarker || anObject === CPNoSelectionMarker || anObject === CPNotApplicableMarker;
}
+65 -58
View File
@@ -31,6 +31,9 @@
@import "CPMenuItem.j" @import "CPMenuItem.j"
@import "CPPanel.j" @import "CPPanel.j"
#include "../CoreGraphics/CGGeometry.h"
#include "../Platform/Platform.h"
CPMenuDidAddItemNotification = @"CPMenuDidAddItemNotification"; CPMenuDidAddItemNotification = @"CPMenuDidAddItemNotification";
CPMenuDidChangeItemNotification = @"CPMenuDidChangeItemNotification"; CPMenuDidChangeItemNotification = @"CPMenuDidChangeItemNotification";
@@ -47,11 +50,11 @@ var _CPMenuBarVisible = NO,
_CPMenuBarAttributes = nil, _CPMenuBarAttributes = nil,
_CPMenuBarSharedWindow = nil; _CPMenuBarSharedWindow = nil;
/*! /*!
@ingroup appkit @ingroup appkit
@class CPMenu @class CPMenu
Menus provide the user with a list of actions and/or submenus. Submenus themselves are full fledged menus Menus provide the user with a list of actions and/or submenus. Submenus themselves are full fledged menus
and so a heirarchical structure appears. and so a heirarchical structure appears.
*/ */
@implementation CPMenu : CPObject @implementation CPMenu : CPObject
@@ -66,13 +69,13 @@ var _CPMenuBarVisible = NO,
float _minimumWidth; float _minimumWidth;
CPMutableArray _items; CPMutableArray _items;
BOOL _autoenablesItems; BOOL _autoenablesItems;
BOOL _showsStateColumn; BOOL _showsStateColumn;
id _delegate; id _delegate;
int _highlightedIndex; CPMenuItem _highlightedIndex;
_CPMenuWindow _menuWindow; _CPMenuWindow _menuWindow;
} }
@@ -92,7 +95,7 @@ var _CPMenuBarVisible = NO,
{ {
if (_CPMenuBarVisible === menuBarShouldBeVisible) if (_CPMenuBarVisible === menuBarShouldBeVisible)
return; return;
_CPMenuBarVisible = menuBarShouldBeVisible; _CPMenuBarVisible = menuBarShouldBeVisible;
if ([CPPlatform supportsNativeMainMenu]) if ([CPPlatform supportsNativeMainMenu])
@@ -102,13 +105,13 @@ var _CPMenuBarVisible = NO,
{ {
if (!_CPMenuBarSharedWindow) if (!_CPMenuBarSharedWindow)
_CPMenuBarSharedWindow = [[_CPMenuBarWindow alloc] init]; _CPMenuBarSharedWindow = [[_CPMenuBarWindow alloc] init];
[_CPMenuBarSharedWindow setMenu:[CPApp mainMenu]]; [_CPMenuBarSharedWindow setMenu:[CPApp mainMenu]];
[_CPMenuBarSharedWindow setTitle:_CPMenuBarTitle]; [_CPMenuBarSharedWindow setTitle:_CPMenuBarTitle];
[_CPMenuBarSharedWindow setIconImage:_CPMenuBarIconImage]; [_CPMenuBarSharedWindow setIconImage:_CPMenuBarIconImage];
[_CPMenuBarSharedWindow setIconImageAlphaValue:_CPMenuBarIconImageAlphaValue]; [_CPMenuBarSharedWindow setIconImageAlphaValue:_CPMenuBarIconImageAlphaValue];
[_CPMenuBarSharedWindow setColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarBackgroundColor"]]; [_CPMenuBarSharedWindow setColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarBackgroundColor"]];
[_CPMenuBarSharedWindow setTextColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTextColor"]]; [_CPMenuBarSharedWindow setTextColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTextColor"]];
[_CPMenuBarSharedWindow setTitleColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTitleColor"]]; [_CPMenuBarSharedWindow setTitleColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTitleColor"]];
@@ -117,12 +120,12 @@ var _CPMenuBarVisible = NO,
[_CPMenuBarSharedWindow setHighlightColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightColor"]]; [_CPMenuBarSharedWindow setHighlightColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightColor"]];
[_CPMenuBarSharedWindow setHighlightTextColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightTextColor"]]; [_CPMenuBarSharedWindow setHighlightTextColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightTextColor"]];
[_CPMenuBarSharedWindow setHighlightTextShadowColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightTextShadowColor"]]; [_CPMenuBarSharedWindow setHighlightTextShadowColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightTextShadowColor"]];
[_CPMenuBarSharedWindow orderFront:self]; [_CPMenuBarSharedWindow orderFront:self];
} }
else else
[_CPMenuBarSharedWindow orderOut:self]; [_CPMenuBarSharedWindow orderOut:self];
// FIXME: There must be a better way to do this. // FIXME: There must be a better way to do this.
#if PLATFORM(DOM) #if PLATFORM(DOM)
[[CPPlatformWindow primaryPlatformWindow] resizeEvent:nil]; [[CPPlatformWindow primaryPlatformWindow] resizeEvent:nil];
@@ -156,9 +159,9 @@ var _CPMenuBarVisible = NO,
{ {
if (_CPMenuBarAttributes == attributes) if (_CPMenuBarAttributes == attributes)
return; return;
_CPMenuBarAttributes = [attributes copy]; _CPMenuBarAttributes = [attributes copy];
var textColor = [attributes objectForKey:@"CPMenuBarTextColor"], var textColor = [attributes objectForKey:@"CPMenuBarTextColor"],
titleColor = [attributes objectForKey:@"CPMenuBarTitleColor"], titleColor = [attributes objectForKey:@"CPMenuBarTitleColor"],
textShadowColor = [attributes objectForKey:@"CPMenuBarTextShadowColor"], textShadowColor = [attributes objectForKey:@"CPMenuBarTextShadowColor"],
@@ -166,40 +169,40 @@ var _CPMenuBarVisible = NO,
highlightColor = [attributes objectForKey:@"CPMenuBarHighlightColor"], highlightColor = [attributes objectForKey:@"CPMenuBarHighlightColor"],
highlightTextColor = [attributes objectForKey:@"CPMenuBarHighlightTextColor"], highlightTextColor = [attributes objectForKey:@"CPMenuBarHighlightTextColor"],
highlightTextShadowColor = [attributes objectForKey:@"CPMenuBarHighlightTextShadowColor"]; highlightTextShadowColor = [attributes objectForKey:@"CPMenuBarHighlightTextShadowColor"];
if (!textColor && titleColor) if (!textColor && titleColor)
[_CPMenuBarAttributes setObject:titleColor forKey:@"CPMenuBarTextColor"]; [_CPMenuBarAttributes setObject:titleColor forKey:@"CPMenuBarTextColor"];
else if (textColor && !titleColor) else if (textColor && !titleColor)
[_CPMenuBarAttributes setObject:textColor forKey:@"CPMenuBarTitleColor"]; [_CPMenuBarAttributes setObject:textColor forKey:@"CPMenuBarTitleColor"];
else if (!textColor && !titleColor) else if (!textColor && !titleColor)
{ {
[_CPMenuBarAttributes setObject:[CPColor colorWithRed:0.051 green:0.2 blue:0.275 alpha:1.0] forKey:@"CPMenuBarTextColor"]; [_CPMenuBarAttributes setObject:[CPColor colorWithRed:0.051 green:0.2 blue:0.275 alpha:1.0] forKey:@"CPMenuBarTextColor"];
[_CPMenuBarAttributes setObject:[CPColor colorWithRed:0.051 green:0.2 blue:0.275 alpha:1.0] forKey:@"CPMenuBarTitleColor"]; [_CPMenuBarAttributes setObject:[CPColor colorWithRed:0.051 green:0.2 blue:0.275 alpha:1.0] forKey:@"CPMenuBarTitleColor"];
} }
if (!textShadowColor && titleShadowColor) if (!textShadowColor && titleShadowColor)
[_CPMenuBarAttributes setObject:titleShadowColor forKey:@"CPMenuBarTextShadowColor"]; [_CPMenuBarAttributes setObject:titleShadowColor forKey:@"CPMenuBarTextShadowColor"];
else if (textShadowColor && !titleShadowColor) else if (textShadowColor && !titleShadowColor)
[_CPMenuBarAttributes setObject:textShadowColor forKey:@"CPMenuBarTitleShadowColor"]; [_CPMenuBarAttributes setObject:textShadowColor forKey:@"CPMenuBarTitleShadowColor"];
else if (!textShadowColor && !titleShadowColor) else if (!textShadowColor && !titleShadowColor)
{ {
[_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarTextShadowColor"]; [_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarTextShadowColor"];
[_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarTitleShadowColor"]; [_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarTitleShadowColor"];
} }
if (!highlightColor) if (!highlightColor)
[_CPMenuBarAttributes setObject:[CPColor colorWithCalibratedRed:94.0/255.0 green:130.0/255.0 blue:186.0/255.0 alpha:1.0] forKey:@"CPMenuBarHighlightColor"]; [_CPMenuBarAttributes setObject:[CPColor colorWithCalibratedRed:94.0/255.0 green:130.0/255.0 blue:186.0/255.0 alpha:1.0] forKey:@"CPMenuBarHighlightColor"];
if (!highlightTextColor) if (!highlightTextColor)
[_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarHighlightTextColor"]; [_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarHighlightTextColor"];
if (!highlightTextShadowColor) if (!highlightTextShadowColor)
[_CPMenuBarAttributes setObject:[CPColor blackColor] forKey:@"CPMenuBarHighlightTextShadowColor"]; [_CPMenuBarAttributes setObject:[CPColor blackColor] forKey:@"CPMenuBarHighlightTextShadowColor"];
if (_CPMenuBarSharedWindow) if (_CPMenuBarSharedWindow)
{ {
[_CPMenuBarSharedWindow setColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarBackgroundColor"]]; [_CPMenuBarSharedWindow setColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarBackgroundColor"]];
@@ -228,7 +231,7 @@ var _CPMenuBarVisible = NO,
{ {
if (self === [CPApp mainMenu]) if (self === [CPApp mainMenu])
return MENUBAR_HEIGHT; return MENUBAR_HEIGHT;
return 0.0; return 0.0;
} }
@@ -246,18 +249,18 @@ var _CPMenuBarVisible = NO,
- (id)initWithTitle:(CPString)aTitle - (id)initWithTitle:(CPString)aTitle
{ {
self = [super init]; self = [super init];
if (self) if (self)
{ {
_title = aTitle; _title = aTitle;
_items = []; _items = [];
_autoenablesItems = YES; _autoenablesItems = YES;
_showsStateColumn = YES; _showsStateColumn = YES;
[self setMinimumWidth:0]; [self setMinimumWidth:0];
} }
return self; return self;
} }
@@ -284,7 +287,7 @@ var _CPMenuBarVisible = NO,
[aMenuItem setMenu:self]; [aMenuItem setMenu:self];
[_items insertObject:aMenuItem atIndex:anIndex]; [_items insertObject:aMenuItem atIndex:anIndex];
[[CPNotificationCenter defaultCenter] [[CPNotificationCenter defaultCenter]
postNotificationName:CPMenuDidAddItemNotification postNotificationName:CPMenuDidAddItemNotification
object:self object:self
@@ -303,7 +306,7 @@ var _CPMenuBarVisible = NO,
- (CPMenuItem)insertItemWithTitle:(CPString)aTitle action:(SEL)anAction keyEquivalent:(CPString)aKeyEquivalent atIndex:(unsigned)anIndex - (CPMenuItem)insertItemWithTitle:(CPString)aTitle action:(SEL)anAction keyEquivalent:(CPString)aKeyEquivalent atIndex:(unsigned)anIndex
{ {
var item = [[CPMenuItem alloc] initWithTitle:aTitle action:anAction keyEquivalent:aKeyEquivalent]; var item = [[CPMenuItem alloc] initWithTitle:aTitle action:anAction keyEquivalent:aKeyEquivalent];
[self insertItem:item atIndex:anIndex]; [self insertItem:item atIndex:anIndex];
return item; return item;
@@ -348,10 +351,10 @@ var _CPMenuBarVisible = NO,
{ {
if (anIndex < 0 || anIndex >= _items.length) if (anIndex < 0 || anIndex >= _items.length)
return; return;
[_items[anIndex] setMenu:nil]; [_items[anIndex] setMenu:nil];
[_items removeObjectAtIndex:anIndex]; [_items removeObjectAtIndex:anIndex];
[[CPNotificationCenter defaultCenter] [[CPNotificationCenter defaultCenter]
postNotificationName:CPMenuDidRemoveItemNotification postNotificationName:CPMenuDidRemoveItemNotification
object:self object:self
@@ -366,7 +369,7 @@ var _CPMenuBarVisible = NO,
{ {
if ([aMenuItem menu] != self) if ([aMenuItem menu] != self)
return; return;
[[CPNotificationCenter defaultCenter] [[CPNotificationCenter defaultCenter]
postNotificationName:CPMenuDidChangeItemNotification postNotificationName:CPMenuDidChangeItemNotification
object:self object:self
@@ -382,10 +385,10 @@ var _CPMenuBarVisible = NO,
- (CPMenuItem)itemWithTag:(int)aTag - (CPMenuItem)itemWithTag:(int)aTag
{ {
var index = [self indexOfItemWithTag:aTag]; var index = [self indexOfItemWithTag:aTag];
if (index == CPNotFound) if (index == CPNotFound)
return nil; return nil;
return _items[index]; return _items[index];
} }
@@ -397,10 +400,10 @@ var _CPMenuBarVisible = NO,
- (CPMenuItem)itemWithTitle:(CPString)aTitle - (CPMenuItem)itemWithTitle:(CPString)aTitle
{ {
var index = [self indexOfItemWithTitle:aTitle]; var index = [self indexOfItemWithTitle:aTitle];
if (index == CPNotFound) if (index == CPNotFound)
return nil; return nil;
return _items[index]; return _items[index];
} }
@@ -439,7 +442,7 @@ var _CPMenuBarVisible = NO,
{ {
if ([aMenuItem menu] !== self) if ([aMenuItem menu] !== self)
return CPNotFound; return CPNotFound;
return [_items indexOfObjectIdenticalTo:aMenuItem]; return [_items indexOfObjectIdenticalTo:aMenuItem];
} }
@@ -452,7 +455,7 @@ var _CPMenuBarVisible = NO,
{ {
var index = 0, var index = 0,
count = _items.length; count = _items.length;
for (; index < count; ++index) for (; index < count; ++index)
if ([_items[index] title] === aTitle) if ([_items[index] title] === aTitle)
return index; return index;
@@ -469,7 +472,7 @@ var _CPMenuBarVisible = NO,
{ {
var index = 0, var index = 0,
count = _items.length; count = _items.length;
for (; index < count; ++index) for (; index < count; ++index)
if ([_items[index] tag] == aTag) if ([_items[index] tag] == aTag)
return index; return index;
@@ -487,11 +490,11 @@ var _CPMenuBarVisible = NO,
{ {
var index = 0, var index = 0,
count = _items.length; count = _items.length;
for (; index < count; ++index) for (; index < count; ++index)
{ {
var item = _items[index]; var item = _items[index];
if ([item target] == aTarget && (!anAction || [item action] == anAction)) if ([item target] == aTarget && (!anAction || [item action] == anAction))
return index; return index;
} }
@@ -508,7 +511,7 @@ var _CPMenuBarVisible = NO,
{ {
var index = 0, var index = 0,
count = _items.length; count = _items.length;
for (; index < count; ++index) for (; index < count; ++index)
if ([[_items[index] representedObject] isEqual:anObject]) if ([[_items[index] representedObject] isEqual:anObject])
return index; return index;
@@ -525,7 +528,7 @@ var _CPMenuBarVisible = NO,
{ {
var index = 0, var index = 0,
count = _items.length; count = _items.length;
for (; index < count; ++index) for (; index < count; ++index)
if ([_items[index] submenu] == aMenu) if ([_items[index] submenu] == aMenu)
return index; return index;
@@ -543,7 +546,7 @@ var _CPMenuBarVisible = NO,
{ {
[aMenuItem setTarget:aMenuItem]; [aMenuItem setTarget:aMenuItem];
[aMenuItem setAction:@selector(submenuAction:)]; [aMenuItem setAction:@selector(submenuAction:)];
[aMenuItem setSubmenu:aMenu]; [aMenuItem setSubmenu:aMenu];
} }
@@ -680,7 +683,7 @@ var _CPMenuBarVisible = NO,
itemIndex = [self indexOfItem:anItem]; itemIndex = [self indexOfItem:anItem];
if (itemIndex === CPNotFound) if (itemIndex === CPNotFound)
throw "In call to popUpMenuPositioningItem:atLocation:inView:callback:, menu item " + throw "In call to popUpMenuPositioningItem:atLocation:inView:callback:, menu item " +
anItem + " is not present in menu " + self; anItem + " is not present in menu " + self;
} }
@@ -744,9 +747,6 @@ var _CPMenuBarVisible = NO,
} }
// Show it. // Show it.
if ([CPPlatform isBrowser])
[menuWindow setPlatformWindow:[[aView window] platformWindow]];
[menuWindow orderFront:self]; [menuWindow orderFront:self];
// Track it. // Track it.
@@ -781,10 +781,10 @@ var _CPMenuBarVisible = NO,
+ (void)popUpContextMenu:(CPMenu)aMenu withEvent:(CPEvent)anEvent forView:(CPView)aView withFont:(CPFont)aFont + (void)popUpContextMenu:(CPMenu)aMenu withEvent:(CPEvent)anEvent forView:(CPView)aView withFont:(CPFont)aFont
{ {
var delegate = [aMenu delegate]; var delegate = [aMenu delegate];
if ([delegate respondsToSelector:@selector(menuWillOpen:)]) if ([delegate respondsToSelector:@selector(menuWillOpen:)])
[delegate menuWillOpen:aMenu]; [delegate menuWillOpen:aMenu];
if (!aFont) if (!aFont)
aFont = [CPFont systemFontOfSize:12.0]; aFont = [CPFont systemFontOfSize:12.0];
@@ -816,9 +816,6 @@ var _CPMenuBarVisible = NO,
[menuWindow setFrameOrigin:CGRectIntersection(unconstrainedFrame, constraintRect).origin]; [menuWindow setFrameOrigin:CGRectIntersection(unconstrainedFrame, constraintRect).origin];
} }
if ([CPPlatform isBrowser])
[menuWindow setPlatformWindow:[[aView window] platformWindow]];
[menuWindow orderFront:self]; [menuWindow orderFront:self];
[[_CPMenuManager sharedMenuManager] [[_CPMenuManager sharedMenuManager]
@@ -935,7 +932,17 @@ var _CPMenuBarVisible = NO,
var item = _items[index], var item = _items[index],
modifierMask = [item keyEquivalentModifierMask]; modifierMask = [item keyEquivalentModifierMask];
if ([anEvent _triggersKeyEquivalent:[item keyEquivalent] withModifierMask:[item keyEquivalentModifierMask]]) if ([item keyEquivalent] === [[item keyEquivalent] uppercaseString])
modifierMask |= CPShiftKeyMask;
if (CPBrowserIsOperatingSystem(CPWindowsOperatingSystem) && (modifierMask & CPCommandKeyMask))
{
modifierMask |= CPControlKeyMask;
modifierMask &= ~CPCommandKeyMask;
}
if ((modifierFlags & (CPShiftKeyMask | CPAlternateKeyMask | CPCommandKeyMask | CPControlKeyMask)) == modifierMask &&
[characters caseInsensitiveCompare:[item keyEquivalent]] == CPOrderedSame)
{ {
if ([item isEnabled]) if ([item isEnabled])
[self performActionForItemAtIndex:index]; [self performActionForItemAtIndex:index];
@@ -943,7 +950,7 @@ var _CPMenuBarVisible = NO,
{ {
//beep? //beep?
} }
return YES; return YES;
} }
@@ -962,7 +969,7 @@ var _CPMenuBarVisible = NO,
- (void)performActionForItemAtIndex:(unsigned)anIndex - (void)performActionForItemAtIndex:(unsigned)anIndex
{ {
var item = _items[anIndex]; var item = _items[anIndex];
[CPApp sendAction:[item action] to:[item target] from:item]; [CPApp sendAction:[item action] to:[item target] from:item];
} }
@@ -1051,7 +1058,7 @@ var CPMenuTitleKey = @"CPMenuTitleKey",
- (id)initWithCoder:(CPCoder)aCoder - (id)initWithCoder:(CPCoder)aCoder
{ {
self = [super init]; self = [super init];
if (self) if (self)
{ {
_title = [aCoder decodeObjectForKey:CPMenuTitleKey]; _title = [aCoder decodeObjectForKey:CPMenuTitleKey];
@@ -1063,7 +1070,7 @@ var CPMenuTitleKey = @"CPMenuTitleKey",
[self setMinimumWidth:0]; [self setMinimumWidth:0];
} }
return self; return self;
} }
+4 -1
View File
@@ -1,4 +1,7 @@
@import "CPPanel.j"
#include "../CoreGraphics/CGGeometry.h"
#include "../Platform/Platform.h"
@import "_CPMenuWindow.j" @import "_CPMenuWindow.j"
+4 -1
View File
@@ -1,3 +1,6 @@
#include "../CoreGraphics/CGGeometry.h"
@import <Foundation/CPObject.j> @import <Foundation/CPObject.j>
@@ -93,7 +96,7 @@ var SharedMenuManager = nil;
// Close Menu Event. // Close Menu Event.
if (type === CPAppKitDefined) 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]; [CPApp setTarget:self selector:@selector(trackEvent:) forNextEventMatchingMask:CPPeriodicMask | CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPAppKitDefinedMask untilDate:nil inMode:nil dequeue:YES];
+2 -1
View File
@@ -1,4 +1,5 @@
@import "CPWindow.j"
#include "../CoreGraphics/CGGeometry.h"
var _CPMenuWindowPool = [], var _CPMenuWindowPool = [],
+49 -91
View File
@@ -29,8 +29,7 @@
@import "CPView.j" @import "CPView.j"
@import "_CPMenuItemView.j" @import "_CPMenuItemView.j"
/*!
/*!
@ingroup appkit @ingroup appkit
@class CPMenuItem @class CPMenuItem
@@ -44,39 +43,39 @@
CPString _title; CPString _title;
//CPAttributedString _attributedTitle; //CPAttributedString _attributedTitle;
CPFont _font; CPFont _font;
id _target; id _target;
SEL _action; SEL _action;
BOOL _isEnabled; BOOL _isEnabled;
BOOL _isHidden; BOOL _isHidden;
int _tag; int _tag;
int _state; int _state;
CPImage _image; CPImage _image;
CPImage _alternateImage; CPImage _alternateImage;
CPImage _onStateImage; CPImage _onStateImage;
CPImage _offStateImage; CPImage _offStateImage;
CPImage _mixedStateImage; CPImage _mixedStateImage;
CPMenu _submenu; CPMenu _submenu;
CPMenu _menu; CPMenu _menu;
CPString _keyEquivalent; CPString _keyEquivalent;
unsigned _keyEquivalentModifierMask; unsigned _keyEquivalentModifierMask;
int _mnemonicLocation; int _mnemonicLocation;
BOOL _isAlternate; BOOL _isAlternate;
int _indentationLevel; int _indentationLevel;
CPString _toolTip; CPString _toolTip;
id _representedObject; id _representedObject;
CPView _view; CPView _view;
_CPMenuItemView _menuItemView; _CPMenuItemView _menuItemView;
} }
@@ -95,19 +94,19 @@
- (id)initWithTitle:(CPString)aTitle action:(SEL)anAction keyEquivalent:(CPString)aKeyEquivalent - (id)initWithTitle:(CPString)aTitle action:(SEL)anAction keyEquivalent:(CPString)aKeyEquivalent
{ {
self = [super init]; self = [super init];
if (self) if (self)
{ {
_isSeparator = NO; _isSeparator = NO;
_title = aTitle; _title = aTitle;
_action = anAction; _action = anAction;
_isEnabled = YES; _isEnabled = YES;
_tag = 0; _tag = 0;
_state = CPOffState; _state = CPOffState;
_keyEquivalent = aKeyEquivalent || @""; _keyEquivalent = aKeyEquivalent || @"";
_keyEquivalentModifierMask = CPPlatformActionKeyMask; _keyEquivalentModifierMask = CPPlatformActionKeyMask;
@@ -115,7 +114,7 @@
_mnemonicLocation = CPNotFound; _mnemonicLocation = CPNotFound;
} }
return self; return self;
} }
@@ -153,7 +152,7 @@
{ {
if (_isHidden == isHidden) if (_isHidden == isHidden)
return; return;
_isHidden = isHidden; _isHidden = isHidden;
[_menu itemChanged:self]; [_menu itemChanged:self];
@@ -174,9 +173,9 @@
{ {
if (_isHidden) if (_isHidden)
return YES; return YES;
var supermenu = [_menu supermenu]; var supermenu = [_menu supermenu];
if ([[supermenu itemAtIndex:[supermenu indexOfItemWithSubmenu:_menu]] isHiddenOrHasHiddenAncestor]) if ([[supermenu itemAtIndex:[supermenu indexOfItemWithSubmenu:_menu]] isHiddenOrHasHiddenAncestor])
return YES; return YES;
@@ -229,11 +228,11 @@
if (_title == aTitle) if (_title == aTitle)
return; return;
_title = aTitle; _title = aTitle;
[_menuItemView setDirty]; [_menuItemView setDirty];
[_menu itemChanged:self]; [_menu itemChanged:self];
} }
@@ -261,11 +260,11 @@
{ {
if (_font == aFont) if (_font == aFont)
return; return;
_font = aFont; _font = aFont;
[_menu itemChanged:self]; [_menu itemChanged:self];
[_menuItemView setDirty]; [_menuItemView setDirty];
} }
@@ -317,9 +316,9 @@ CPOffState
{ {
if (_state == aState) if (_state == aState)
return; return;
_state = aState; _state = aState;
[_menu itemChanged:self]; [_menu itemChanged:self];
[_menuItemView setDirty]; [_menuItemView setDirty];
@@ -347,11 +346,11 @@ CPOffState
{ {
if (_image == anImage) if (_image == anImage)
return; return;
_image = anImage; _image = anImage;
[_menuItemView setDirty]; [_menuItemView setDirty];
[_menu itemChanged:self]; [_menu itemChanged:self];
} }
@@ -389,7 +388,7 @@ CPOffState
{ {
if (_onStateImage == anImage) if (_onStateImage == anImage)
return; return;
_onStateImage = anImage; _onStateImage = anImage;
[_menu itemChanged:self]; [_menu itemChanged:self];
} }
@@ -410,7 +409,7 @@ CPOffState
{ {
if (_offStateImage == anImage) if (_offStateImage == anImage)
return; return;
_offStateImage = anImage; _offStateImage = anImage;
[_menu itemChanged:self]; [_menu itemChanged:self];
} }
@@ -431,7 +430,7 @@ CPOffState
{ {
if (_mixedStateImage == anImage) if (_mixedStateImage == anImage)
return; return;
_mixedStateImage = anImage; _mixedStateImage = anImage;
[_menu itemChanged:self]; [_menu itemChanged:self];
} }
@@ -592,8 +591,7 @@ CPControlKeyMask
return @""; return @"";
var string = _keyEquivalent.toUpperCase(), var string = _keyEquivalent.toUpperCase(),
needsShift = _keyEquivalentModifierMask & CPShiftKeyMask || needsShift = _keyEquivalentModifierMask & CPShiftKeyMask || string === _keyEquivalent;
(string === _keyEquivalent && _keyEquivalent.toLowerCase() !== _keyEquivalent.toUpperCase());
if (CPBrowserIsOperatingSystem(CPMacOperatingSystem)) if (CPBrowserIsOperatingSystem(CPMacOperatingSystem))
{ {
@@ -650,14 +648,14 @@ CPControlKeyMask
- (void)setTitleWithMnemonicLocation:(CPString)aTitle - (void)setTitleWithMnemonicLocation:(CPString)aTitle
{ {
var location = [aTitle rangeOfString:@"&"].location; var location = [aTitle rangeOfString:@"&"].location;
if (location == CPNotFound) if (location == CPNotFound)
[self setTitle:aTitle]; [self setTitle:aTitle];
else else
{ {
[self setTitle:[aTitle substringToIndex:location] + [aTitle substringFromIndex:location + 1]]; [self setTitle:[aTitle substringToIndex:location] + [aTitle substringFromIndex:location + 1]];
[self setMnemonicLocation:location]; [self setMnemonicLocation:location];
} }
} }
/*! /*!
@@ -698,7 +696,7 @@ CPControlKeyMask
{ {
if (aLevel < 0) if (aLevel < 0)
[CPException raise:CPInvalidArgumentException reason:"setIndentationLevel: argument must be greater than or equal to 0."]; [CPException raise:CPInvalidArgumentException reason:"setIndentationLevel: argument must be greater than or equal to 0."];
_indentationLevel = MIN(15, aLevel); _indentationLevel = MIN(15, aLevel);
} }
@@ -757,11 +755,11 @@ CPControlKeyMask
{ {
if (_view === aView) if (_view === aView)
return; return;
_view = aView; _view = aView;
[_menuItemView setDirty]; [_menuItemView setDirty];
[_menu itemChanged:self]; [_menu itemChanged:self];
} }
@@ -783,48 +781,7 @@ CPControlKeyMask
return [[self menu] highlightedItem] == self; 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 @ignore
@@ -833,7 +790,7 @@ CPControlKeyMask
{ {
if (!_menuItemView) if (!_menuItemView)
_menuItemView = [[_CPMenuItemView alloc] initWithFrame:CGRectMakeZero() forMenuItem:self]; _menuItemView = [[_CPMenuItemView alloc] initWithFrame:CGRectMakeZero() forMenuItem:self];
return _menuItemView; return _menuItemView;
} }
@@ -887,15 +844,15 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
- (id)initWithCoder:(CPCoder)aCoder - (id)initWithCoder:(CPCoder)aCoder
{ {
self = [super init]; self = [super init];
if (self) if (self)
{ {
_isSeparator = [aCoder containsValueForKey:CPMenuItemIsSeparatorKey] && [aCoder decodeBoolForKey:CPMenuItemIsSeparatorKey]; _isSeparator = [aCoder containsValueForKey:CPMenuItemIsSeparatorKey] && [aCoder decodeBoolForKey:CPMenuItemIsSeparatorKey];
_title = [aCoder decodeObjectForKey:CPMenuItemTitleKey]; _title = [aCoder decodeObjectForKey:CPMenuItemTitleKey];
// _font; // _font;
_target = [aCoder decodeObjectForKey:CPMenuItemTargetKey]; _target = [aCoder decodeObjectForKey:CPMenuItemTargetKey];
_action = [aCoder decodeObjectForKey:CPMenuItemActionKey]; _action = [aCoder decodeObjectForKey:CPMenuItemActionKey];
@@ -903,6 +860,7 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
_isHidden = DEFAULT_VALUE(CPMenuItemIsHiddenKey, NO); _isHidden = DEFAULT_VALUE(CPMenuItemIsHiddenKey, NO);
_tag = DEFAULT_VALUE(CPMenuItemTagKey, 0); _tag = DEFAULT_VALUE(CPMenuItemTagKey, 0);
_state = DEFAULT_VALUE(CPMenuItemStateKey, CPOffState); _state = DEFAULT_VALUE(CPMenuItemStateKey, CPOffState);
// int _state;
_image = DEFAULT_VALUE(CPMenuItemImageKey, nil); _image = DEFAULT_VALUE(CPMenuItemImageKey, nil);
_alternateImage = DEFAULT_VALUE(CPMenuItemAlternateImageKey, nil); _alternateImage = DEFAULT_VALUE(CPMenuItemAlternateImageKey, nil);
@@ -929,7 +887,7 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
_representedObject = DEFAULT_VALUE(CPMenuItemRepresentedObjectKey, nil); _representedObject = DEFAULT_VALUE(CPMenuItemRepresentedObjectKey, nil);
_view = DEFAULT_VALUE(CPMenuItemViewKey, nil); _view = DEFAULT_VALUE(CPMenuItemViewKey, nil);
} }
return self; return self;
} }
@@ -943,11 +901,11 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
[aCoder encodeBool:_isSeparator forKey:CPMenuItemIsSeparatorKey]; [aCoder encodeBool:_isSeparator forKey:CPMenuItemIsSeparatorKey];
[aCoder encodeObject:_title forKey:CPMenuItemTitleKey]; [aCoder encodeObject:_title forKey:CPMenuItemTitleKey];
[aCoder encodeObject:_target forKey:CPMenuItemTargetKey]; [aCoder encodeObject:_target forKey:CPMenuItemTargetKey];
[aCoder encodeObject:_action forKey:CPMenuItemActionKey]; [aCoder encodeObject:_action forKey:CPMenuItemActionKey];
ENCODE_IFNOT(CPMenuItemIsEnabledKey, _isEnabled, YES); ENCODE_IFNOT(CPMenuItemIsEnabledKey, _isEnabled, YES);
ENCODE_IFNOT(CPMenuItemIsHiddenKey, _isHidden, NO); ENCODE_IFNOT(CPMenuItemIsHiddenKey, _isHidden, NO);
ENCODE_IFNOT(CPMenuItemTagKey, _tag, 0); ENCODE_IFNOT(CPMenuItemTagKey, _tag, 0);
@@ -955,7 +913,7 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
ENCODE_IFNOT(CPMenuItemImageKey, _image, nil); ENCODE_IFNOT(CPMenuItemImageKey, _image, nil);
ENCODE_IFNOT(CPMenuItemAlternateImageKey, _alternateImage, nil); ENCODE_IFNOT(CPMenuItemAlternateImageKey, _alternateImage, nil);
ENCODE_IFNOT(CPMenuItemSubmenuKey, _submenu, nil); ENCODE_IFNOT(CPMenuItemSubmenuKey, _submenu, nil);
ENCODE_IFNOT(CPMenuItemMenuKey, _menu, nil); ENCODE_IFNOT(CPMenuItemMenuKey, _menu, nil);
@@ -1,6 +1,3 @@
@import "CPView.j"
var HORIZONTAL_MARGIN = 8.0, var HORIZONTAL_MARGIN = 8.0,
SUBMENU_INDICATOR_MARGIN = 3.0, SUBMENU_INDICATOR_MARGIN = 3.0,
VERTICAL_MARGIN = 4.0; VERTICAL_MARGIN = 4.0;
@@ -65,7 +62,6 @@ var SelectionColor = nil,
_imageAndTextView = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(HORIZONTAL_MARGIN, 0.0, 0.0, 0.0)]; _imageAndTextView = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(HORIZONTAL_MARGIN, 0.0, 0.0, 0.0)];
[_imageAndTextView setImagePosition:CPImageLeft]; [_imageAndTextView setImagePosition:CPImageLeft];
[_imageAndTextView setImageOffset:3.0];
[_imageAndTextView setTextShadowOffset:CGSizeMake(0.0, 1.0)]; [_imageAndTextView setTextShadowOffset:CGSizeMake(0.0, 1.0)];
[_imageAndTextView setAutoresizingMask:CPViewMinYMargin | CPViewMaxYMargin]; [_imageAndTextView setAutoresizingMask:CPViewMinYMargin | CPViewMaxYMargin];
+1 -1
View File
@@ -1,5 +1,5 @@
@import "CPView.j" @import <AppKit/CPView.j>
@implementation _CPMenuItemSeparatorView : CPView @implementation _CPMenuItemSeparatorView : CPView
+5 -11
View File
@@ -1,6 +1,3 @@
@import "CPControl.j"
var LEFT_MARGIN = 3.0, var LEFT_MARGIN = 3.0,
RIGHT_MARGIN = 14.0 + 3.0, RIGHT_MARGIN = 14.0 + 3.0,
STATE_COLUMN_WIDTH = 14.0, STATE_COLUMN_WIDTH = 14.0,
@@ -42,7 +39,7 @@ var SUBMENU_INDICATOR_COLOR = nil,
SUBMENU_INDICATOR_COLOR = [CPColor grayColor]; 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]; _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]; var bundle = [CPBundle bundleForClass:self];
@@ -260,13 +257,10 @@ var SUBMENU_INDICATOR_COLOR = nil,
[_keyEquivalentView setTextShadowColor:[self textShadowColor]]; [_keyEquivalentView setTextShadowColor:[self textShadowColor]];
} }
if ([[_menuItem menu] showsStateColumn]) if (shouldHighlight)
{ [_stateView setImage:_CPMenuItemDefaultStateHighlightedImages[[_menuItem state]] || nil];
if (shouldHighlight) else
[_stateView setImage:_CPMenuItemDefaultStateHighlightedImages[[_menuItem state]] || nil]; [_stateView setImage:_CPMenuItemDefaultStateImages[[_menuItem state]] || nil];
else
[_stateView setImage:_CPMenuItemDefaultStateImages[[_menuItem state]] || nil];
}
} }
@end @end
+2 -4
View File
@@ -1,6 +1,4 @@
@import <AppKit/CPControl.j>
@import "_CPMenuItemSeparatorView.j" @import "_CPMenuItemSeparatorView.j"
@import "_CPMenuItemStandardView.j" @import "_CPMenuItemStandardView.j"
@import "_CPMenuItemMenuBarView.j" @import "_CPMenuItemMenuBarView.j"
@@ -45,7 +43,7 @@ var _CPMenuItemSelectionColor = nil,
return; return;
_CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0]; _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]; var bundle = [CPBundle bundleForClass:self];
@@ -254,4 +252,4 @@ var _CPMenuItemSelectionColor = nil,
CGContextFillPath(context); CGContextFillPath(context);
} }
@end @end
-625
View File
@@ -1,625 +0,0 @@
@import <Foundation/CPDictionary.j>
@import <Foundation/CPCountedSet.j>
@import "CPController.j"
@implementation CPObjectController : CPController
{
id _contentObject;
id _selection;
Class _objectClass;
BOOL _isEditable;
BOOL _automaticallyPreparesContent;
CPCountedSet _observedKeys;
}
+ (id)initialize
{
[self exposeBinding:@"editable"];
[self exposeBinding:@"contentObject"];
}
+ (CPSet)keyPathsForValuesAffectingContentObject
{
return [CPSet setWithObjects:"content"];
}
+ (BOOL)automaticallyNotifiesObserversForKey:(CPString)aKey
{
if (aKey === @"contentObject")
return NO;
return YES;
}
+ (CPSet)keyPathsForValuesAffectingCanAdd
{
return [CPSet setWithObject:"editable"];
}
+ (CPSet)keyPathsForValuesAffectingCanInsert
{
return [CPSet setWithObject:"editable"];
}
+ (CPSet)keyPathsForValuesAffectingCanRemove
{
return [CPSet setWithObjects:"editable", "selection"];
}
- (id)init
{
return [self initWithContent:nil];
}
- (id)initWithContent:(id)aContent
{
if (self = [super init])
{
[self setContent:aContent];
[self setEditable:YES];
[self setObjectClass:[CPMutableDictionary class]];
_observedKeys = [[CPCountedSet alloc] init];
}
return self;
}
- (id)content
{
return _contentObject;
}
- (void)setContent:(id)aContent
{
[self willChangeValueForKey:@"contentObject"];
[self _selectionWillChange];
_contentObject = aContent;
[self didChangeValueForKey:@"contentObject"];
[self _selectionDidChange];
}
- (void)_setContentObject:(id)aContent
{
[self setContent:aContent];
}
- (id)_contentObject
{
return [self content];
}
- (void)setAutomaticallyPreparesContent:(BOOL)shouldAutomaticallyPrepareContent
{
_automaticallyPreparesContent = shouldAutomaticallyPrepareContent;
}
- (BOOL)automaticallyPreparesContent
{
return _automaticallyPreparesContent;
}
- (void)prepareContent
{
[self setContent:[self newObject]];
}
- (void)setObjectClass:(Class)aClass
{
_objectClass = aClass;
}
- (Class)objectClass
{
return _objectClass;
}
- (id)newObject
{
return [[[self objectClass] alloc] init];
}
- (void)addObject:(id)anObject
{
[self setContent:anObject];
[[CPKeyValueBinding getBinding:@"contentObject" forObject:self] reverseSetValueFor:@"contentObject"];
}
- (void)removeObject:(id)anObject
{
if ([self content] === anObject)
[self setContent:nil];
[[CPKeyValueBinding getBinding:@"contentObject" forObject:self] reverseSetValueFor:@"contentObject"];
}
- (void)add:(id)aSender
{
// FIXME: This should happen on the next run loop?
[self addObject:[self newObject]];
}
- (BOOL)canAdd
{
return [self isEditable];
}
- (void)remove:(id)aSender
{
// FIXME: This should happen on the next run loop?
[self removeObject:[self content]];
}
- (BOOL)canRemove
{
return [self isEditable] && [[self selectedObjects] count];
}
- (void)setEditable:(BOOL)shouldBeEditable
{
_isEditable = shouldBeEditable;
}
- (BOOL)isEditable
{
return _isEditable;
}
- (CPArray)selectedObjects
{
return [[_CPObservableArray alloc] initWithObjects:[_contentObject] count:1];
}
- (id)selection
{
return _selection;
}
- (void)_selectionWillChange
{
[_selection controllerWillChange];
[self willChangeValueForKey:@"selection"];
}
- (void)_selectionDidChange
{
if (_selection === undefined || _selection === nil)
_selection = [[CPControllerSelectionProxy alloc] initWithController:self];
[_selection controllerDidChange];
[self didChangeValueForKey:@"selection"];
}
- (id)observedKeys
{
return _observedKeys;
}
- (void)addObserver:(id)anObserver forKeyPath:(CPString)aKeyPath options:(CPKeyValueObservingOptions)options context:(id)context
{
[_observedKeys addObject:aKeyPath];
[super addObserver:anObserver forKeyPath:aKeyPath options:options context:context];
}
- (void)removeObserver:(id)anObserver forKeyPath:(CPString)aKeyPath
{
[_observedKeys removeObject:aKeyPath];
[super removeObserver:anObserver forKeyPath:aKeyPath];
}
@end
var CPObjectControllerObjectClassNameKey = @"CPObjectControllerObjectClassNameKey",
CPObjectControllerIsEditableKey = @"CPObjectControllerIsEditableKey",
CPObjectControllerAutomaticallyPreparesContentKey = @"CPObjectControllerAutomaticallyPreparesContentKey";
@implementation CPObjectController (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
if (self)
{
var objectClassName = [aCoder decodeObjectForKey:CPObjectControllerObjectClassNameKey],
objectClass = CPClassFromString(objectClassName);
// FIXME: Error if objectClass === nil
[self setObjectClass:objectClass];
[self setEditable:[aCoder decodeBoolForKey:CPObjectControllerIsEditableKey]];
[self setAutomaticallyPreparesContent:[aCoder decodeBoolForKey:CPObjectControllerAutomaticallyPreparesContentKey] || NO];
_observedKeys = [[CPCountedSet alloc] init];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[aCoder encodeObject:CPStringFromClass(objectClass) forKey:CPObjectControllerObjectClassNameKey];
[aCoder encodeObject:[self isEditable] forKey:CPObjectControllerIsEditableKey];
if (![self automaticallyPreparesContent])
[aCoder encodeBOOL:YES forKey:CPObjectControllerAutomaticallyPreparesContentKey];
}
@end
@implementation _CPObservationProxy : CPObject
{
id _keyPath;
id _observer;
id _object;
BOOL _notifyObject;
id _context;
int _options;
}
- (id)initWithKeyPath:(id)aKeyPath observer:(id)anObserver object:(id)anObject
{
if (self=[super init])
{
_keyPath = aKeyPath;
_observer = anObserver;
_object = anObject;
}
return self;
}
- (id)observer
{
return _observer;
}
- (id)keyPath
{
return _keyPath;
}
- (id)context
{
return _context;
}
- (int)options
{
return _options;
}
- (void)setNotifyObject:(BOOL)notify
{
_notifyObject = notify;
}
- (BOOL)isEqual:(id)anObject
{
if ([anObject class] === [self class])
{
if (anObject._observer === _observer && [anObject._keyPath isEqual:_keyPath] && [anObject._object isEqual:_object])
return YES;
}
return NO;
}
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)change context:(id)context
{
if (_notifyObject)
[_object observeValueForKeyPath:_keyPath ofObject:_object change:change context:context];
[_observer observeValueForKeyPath:_keyPath ofObject:_object change:change context:context];
}
- (CPString)description
{
return [super description] + [CPString stringWithFormat:@"observation proxy for %@ on key path %@", _observer, _keyPath];
}
@end
@implementation _CPObservableArray : CPMutableArray
{
CPArray _observationProxies;
}
+ (id)alloc
{
var a = [];
a.isa = self;
var ivars = class_copyIvarList(self),
count = ivars.length;
while (count--)
a[ivar_getName(ivars[count])] = nil;
return a;
}
- (CPString)description
{
return "<_CPObservableArray: "+[super description]+" >";
}
- (id)initWithArray:(CPArray)anArray
{
if (self = [super initWithArray:anArray])
{
_observationProxies = [];
}
return self;
}
- (id)initWithObjects:(CPArray)objects count:(unsigned)count
{
if (self = [super initWithObjects:objects count:count])
{
_observationProxies = [];
}
return self;
}
-(void)addObserver:(id)anObserver forKeyPath:(CPString)aKeyPath options:(CPKeyValueObservingOptions)options context:(id)context
{
if (aKeyPath.indexOf("@") === 0)
{
var proxy = [[_CPObservationProxy alloc] initWithKeyPath:aKeyPath observer:anObserver object:self];
proxy._options = options;
proxy._context = context;
[_observationProxies addObject:proxy];
var dotIndex = aKeyPath.indexOf("."),
remaining = aKeyPath.substring(dotIndex+1),
indexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [self count])];
[self addObserver:proxy toObjectsAtIndexes:indexes forKeyPath:remaining options:options context:context];
}
else
{
var indexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [self count])];
[self addObserver:anObserver toObjectsAtIndexes:indexes forKeyPath:aKeyPath options:options context:context];
}
}
- (void)removeObserver:(id)anObserver forKeyPath:(CPString)aKeyPath
{
if (aKeyPath.indexOf("@") === 0)
{
var proxy = [[_CPObservationProxy alloc] initWithKeyPath:aKeyPath observer:anObserver object:self],
index = [_observationProxies indexOfObject:proxy];
proxy = [_observationProxies objectAtIndex:index];
var dotIndex = aKeyPath.indexOf("."),
remaining = aKeyPath.substring(dotIndex+1),
indexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [self count])];
[self removeObserver:proxy fromObjectsAtIndexes:indexes forKeyPath:remaining];
}
else
{
var indexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [self count])];
[self removeObserver:anObserver fromObjectsAtIndexes:indexes forKeyPath:aKeyPath];
}
}
- (void)insertObject:(id)anObject atIndex:(unsigned)anIndex
{
for (var i=0, count=[_observationProxies count]; i<count; i++)
{
var proxy = [_observationProxies objectAtIndex:i],
keyPath = [proxy keyPath],
operator = keyPath.indexOf(".") === 0;
if (operator)
[self willChangeValueForKey:keyPath];
[anObject addObserver:proxy forKeyPath:keyPath options:[proxy options] context:[proxy context]];
if (operator)
[self didChangeValueForKey:keyPath];
}
[super insertObject:anObject atIndex:anIndex];
}
- (void)removeObjectAtIndex:(unsigned)anIndex
{
for (var i=0, count=[_observationProxies count]; i<count; i++)
{
var proxy = [_observationProxies objectAtIndex:i],
keyPath = [proxy keyPath],
operator = keyPath.indexOf(".") === 0;
if (operator)
[self willChangeValueForKey:keyPath];
[anObject removeObserver:proxy forKeyPath:keyPath];
if (operator)
[self didChangeValueForKey:keyPath];
}
[super removeObjectAtIndex:anIndex];
}
- (_CPObservableArray)objectsAtIndexes:(CPIndexSet)theIndexes
{
return [_CPObservableArray arrayWithArray:[super objectsAtIndexes:theIndexes]];
}
- (void)addObject:(id)anObject
{
[self insertObject:anObject atIndex:[self count]];
}
- (void)removeLastObject
{
[self removeObjectAtIndex:[self count]];
}
- (void)replaceObjectAtIndex:(unsigned)anIndex withObject:(id)anObject
{
var currentObject = [self objectAtIndex:anIndex];
for (var i=0, count=[_observationProxies count]; i<count; i++)
{
var proxy = [_observationProxies objectAtIndex:i],
keyPath = [proxy keyPath],
operator = keyPath.indexOf(".") === 0;
if (operator)
[self willChangeValueForKey:keyPath];
[currentObject removeObserver:proxy forKeyPath:keyPath];
[anObject addObserver:proxy forKeyPath:keyPath options:[proxy options] context:[proxy context]];
if (operator)
[self didChangeValueForKey:keyPath];
}
[super replaceObjectAtIndex:anIndex withObject:anObject];
}
@end
@implementation CPControllerSelectionProxy : CPObject
{
id _controller;
id _keys;
CPDictionary _cachedValues;
CPArray _observationProxies;
}
- (id)initWithController:(id)aController
{
if (self = [super init])
{
_cachedValues = [CPDictionary dictionary];
_observationProxies = [CPArray array];
_controller = aController;
}
return self;
}
- (id)valueForKey:(CPString)aKey
{
var value = [_cachedValues objectForKey:aKey];
if (value !== undefined && value !== nil)
return value;
var allValues = [[_controller selectedObjects] valueForKeyPath:aKey],
count = [allValues count];
if (!count)
value = CPNoSelectionMarker;
else if (count === 1)
value = [allValues objectAtIndex:0];
else
{
if ([_controller alwaysUsesMultipleValuesMarker])
value = CPMultipleValuesMarker;
else
{
value = [allValues objectAtIndex:0];
for (var i=0, count=[allValues count]; i<count && value!=CPMultipleValuesMarker; i++)
{
if (![value isEqual:[allValues objectAtIndex:i]])
value = CPMultipleValuesMarker;
}
}
}
[_cachedValues setValue:value forKey:aKey];
return value;
}
- (unsigned)count
{
return [_cachedValues count];
}
- (id)keyEnumerator
{
return [_cachedValues keyEnumerator];
}
- (void)setValue:(id)aValue forKey:(CPString)aKey
{
[[_controller selectedObjects] setValue:aValue forKey:aKey];
}
-(void)controllerWillChange
{
_keys = [_cachedValues allKeys];
if (!_keys)
return;
for (var i=0, count=_keys.length; i<count; i++)
[self willChangeValueForKey:_keys[i]];
[_cachedValues removeAllObjects];
}
-(void)controllerDidChange
{
[_cachedValues removeAllObjects];
if (!_keys)
return;
for (var i=0, count=_keys.length; i<count; i++)
[self didChangeValueForKey:_keys[i]];
_keys = nil;
}
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)change context:(id)context
{
[_cachedValues removeObjectForKey:aKeyPath];
}
- (void)addObserver:(id)anObject forKeyPath:(CPString)aKeyPath options:(CPKeyValueObservingOptions)options context:(id)context
{
var proxy = [[_CPObservationProxy alloc] initWithKeyPath:aKeyPath observer:anObject object:self];
[proxy setNotifyObject:YES];
[_observationProxies addObject:proxy];
[[_controller selectedObjects] addObserver:proxy forKeyPath:aKeyPath options:options context:context];
}
- (void)removeObserver:(id)anObject forKeyPath:(CPString)aKeyPath
{
var proxy = [[_CPObservationProxy alloc] initWithKeyPath:aKeyPath observer:anObject object:self],
index = [_observationProxies indexOfObject:proxy];
[[_controller selectedObjects] removeObserver:[_observationProxies objectAtIndex:index] forKeyPath:aKeyPath];
[_observationProxies removeObjectAtIndex:index];
}
@end
+1 -1
View File
@@ -1,5 +1,5 @@
@import "CPPanel.j" @import <AppKit/CPPanel.j>
@implementation CPOpenPanel : CPPanel @implementation CPOpenPanel : CPPanel
+125 -371
View File
@@ -23,6 +23,8 @@
@import "CPTableColumn.j" @import "CPTableColumn.j"
@import "CPTableView.j" @import "CPTableView.j"
#include "CoreGraphics/CGGeometry.h"
CPOutlineViewColumnDidMoveNotification = @"CPOutlineViewColumnDidMoveNotification"; CPOutlineViewColumnDidMoveNotification = @"CPOutlineViewColumnDidMoveNotification";
CPOutlineViewColumnDidResizeNotification = @"CPOutlineViewColumnDidResizeNotification"; CPOutlineViewColumnDidResizeNotification = @"CPOutlineViewColumnDidResizeNotification";
@@ -48,30 +50,12 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_
CPOutlineViewDataSource_outlineView_sortDescriptorsDidChange_ = 1 << 10; CPOutlineViewDataSource_outlineView_sortDescriptorsDidChange_ = 1 << 10;
var CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_ = 1 << 1, var CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_ = 1 << 1,
CPOutlineViewDelegate_outlineView_didClickTableColumn_ = 1 << 2, CPOutlineViewDelegate_outlineView_shouldSelectItem_ = 1 << 2,
CPOutlineViewDelegate_outlineView_didDragTableColumn_ = 1 << 3, CPOutlineViewDelegate_outlineView_heightOfRowByItem_ = 1 << 3,
CPOutlineViewDelegate_outlineView_heightOfRowByItem_ = 1 << 4, CPOutlineViewDelegate_outlineView_willDisplayView_forTableColumn_item_ = 1 << 4,
CPOutlineViewDelegate_outlineView_isGroupItem_ = 1 << 5, CPOutlineViewDelegate_outlineView_isGroupItem_ = 1 << 5;
CPOutlineViewDelegate_outlineView_mouseDownInHeaderOfTableColumn_ = 1 << 6,
CPOutlineViewDelegate_outlineView_nextTypeSelectMatchFromItem_toItem_forString_ = 1 << 7,
CPOutlineViewDelegate_outlineView_selectionIndexesForProposedSelection_ = 1 << 8,
CPOutlineViewDelegate_outlineView_shouldCollapseItem_ = 1 << 9,
CPOutlineViewDelegate_outlineView_shouldEditTableColumn_item_ = 1 << 10,
CPOutlineViewDelegate_outlineView_shouldExpandItem_ = 1 << 11,
CPOutlineViewDelegate_outlineView_shouldReorderColumn_toColumn_ = 1 << 12,
CPOutlineViewDelegate_outlineView_shouldSelectItem_ = 1 << 13,
CPOutlineViewDelegate_outlineView_shouldSelectTableColumn_ = 1 << 14,
CPOutlineViewDelegate_outlineView_shouldShowOutlineViewForItem_ = 1 << 15,
CPOutlineViewDelegate_outlineView_shouldShowViewExpansionForTableColumn_item_ = 1 << 16,
CPOutlineViewDelegate_outlineView_shouldTrackView_forTableColumn_item_ = 1 << 17,
CPOutlineViewDelegate_outlineView_shouldTypeSelectForEvent_withCurrentSearchString_ = 1 << 18,
CPOutlineViewDelegate_outlineView_sizeToFitWidthOfColumn_ = 1 << 19,
CPOutlineViewDelegate_outlineView_toolTipForView_rect_tableColumn_item_mouseLocation_ = 1 << 20,
CPOutlineViewDelegate_outlineView_typeSelectStringForTableColumn_item_ = 1 << 21,
CPOutlineViewDelegate_outlineView_willDisplayOutlineView_forTableColumn_item_ = 1 << 22,
CPOutlineViewDelegate_outlineView_willDisplayView_forTableColumn_item_ = 1 << 23,
CPOutlineViewDelegate_selectionShouldChangeInOutlineView_ = 1 << 24;
CPOutlineViewDropOnItemIndex = -1; CPOutlineViewDropOnItemIndex = -1;
@@ -95,14 +79,12 @@ CPOutlineViewDropOnItemIndex = -1;
CPArray _disclosureControlsForRows; CPArray _disclosureControlsForRows;
CPData _disclosureControlData; CPData _disclosureControlData;
CPArray _disclosureControlQueue; CPArray _disclosureControlQueue;
BOOL _shouldRetargetItem; BOOL _shouldRetargetItem;
id _retargetedItem; id _retargetedItem;
BOOL _shouldRetargetChildIndex; BOOL _shouldRetargetChildIndex;
CPInteger _retargedChildIndex; CPInteger _retargedChildIndex;
CPTimer _dragHoverTimer;
id _dropItem;
} }
- (id)initWithFrame:(CGRect)aFrame - (id)initWithFrame:(CGRect)aFrame
@@ -123,10 +105,9 @@ CPOutlineViewDropOnItemIndex = -1;
_retargetedItem = nil; _retargetedItem = nil;
_shouldRetargetItem = NO; _shouldRetargetItem = NO;
_retargedChildIndex = nil; _retargedChildIndex = nil;
_shouldRetargetChildIndex = NO; _shouldRetargetChildIndex = NO;
_startHoverTime = nil;
[self setIndentationPerLevel:16.0]; [self setIndentationPerLevel:16.0];
[self setIndentationMarkerFollowsDataView:YES]; [self setIndentationMarkerFollowsDataView:YES];
@@ -232,7 +213,7 @@ CPOutlineViewDropOnItemIndex = -1;
- (void)expandItem:(id)anItem expandChildren:(BOOL)shouldExpandChildren - (void)expandItem:(id)anItem expandChildren:(BOOL)shouldExpandChildren
{ {
var itemInfo = null; var itemInfo = null;
if (!anItem) if (!anItem)
itemInfo = _rootItemInfo; itemInfo = _rootItemInfo;
else else
@@ -240,21 +221,15 @@ CPOutlineViewDropOnItemIndex = -1;
if (!itemInfo) if (!itemInfo)
return; return;
// to prevent items which are already expanded from firing notifications itemInfo.isExpanded = YES;
if (!itemInfo.isExpanded) [self reloadItem:anItem reloadChildren:YES];
{
[self _noteItemWillExpand:anItem];
itemInfo.isExpanded = YES;
[self _noteItemDidExpand:anItem];
[self reloadItem:anItem reloadChildren:YES];
}
if (shouldExpandChildren) if (shouldExpandChildren)
{ {
var children = itemInfo.children, var children = itemInfo.children,
childIndex = children.length; childIndex = children.length;
while (childIndex--) while (childIndex--)
[self expandItem:children[childIndex] expandChildren:YES]; [self expandItem:children[childIndex] expandChildren:YES];
} }
@@ -273,9 +248,7 @@ CPOutlineViewDropOnItemIndex = -1;
if (!itemInfo.isExpanded) if (!itemInfo.isExpanded)
return; return;
[self _noteItemWillCollapse:anItem];
itemInfo.isExpanded = NO; itemInfo.isExpanded = NO;
[self _noteItemDidCollapse:anItem];
[self reloadItem:anItem reloadChildren:YES]; [self reloadItem:anItem reloadChildren:YES];
} }
@@ -390,7 +363,7 @@ CPOutlineViewDropOnItemIndex = -1;
return nil; return nil;
var parent = itemInfo.parent; var parent = itemInfo.parent;
// Check if the parent is the root item because we never return the actual root item // Check if the parent is the root item because we never return the actual root item
if (itemInfo[[parent UID]] === _rootItemInfo) if (itemInfo[[parent UID]] === _rootItemInfo)
parent = nil; parent = nil;
@@ -409,14 +382,43 @@ CPOutlineViewDropOnItemIndex = -1;
return frame; return frame;
} }
- (void)_performSelection:(BOOL)select forRow:(CPInteger)rowIndex context:(id)context - (void)selectRowIndexes:(CPIndexSet)rows byExtendingSelection:(BOOL)shouldExtendSelection
{ {
[super _performSelection:select forRow:rowIndex context:context]; // First un highlight the old disclosure controls
var previousSelectedRows = [];
var control = _disclosureControlsForRows[rowIndex], [[self selectedRowIndexes] getIndexes:previousSelectedRows maxCount:-1 inIndexRange:nil];
selector = select ? @"setThemeState:" : @"unsetThemeState:";
var index = [previousSelectedRows count];
[control performSelector:CPSelectorFromString(selector) withObject:CPThemeStateSelected]; while (index--)
{
var rowIndex = previousSelectedRows[index],
item = [self itemAtRow:rowIndex];
if (![self isExpandable:item])
continue;
var control = _disclosureControlsForRows[rowIndex];
[control setHighlighted:NO];
}
[super selectRowIndexes:rows byExtendingSelection:shouldExtendSelection];
// Now highlight the new disclosure controls
var selectedRows = [];
[rows getIndexes:selectedRows maxCount:-1 inIndexRange:nil];
var index = [selectedRows count];
while (index--)
{
var rowIndex = selectedRows[index],
item = [self itemAtRow:rowIndex];
if (![self isExpandable:item])
continue;
var control = _disclosureControlsForRows[rowIndex];
[control setHighlighted:YES];
}
} }
- (void)setDelegate:(id)aDelegate - (void)setDelegate:(id)aDelegate
@@ -451,76 +453,25 @@ CPOutlineViewDropOnItemIndex = -1;
removeObserver:_outlineViewDelegate removeObserver:_outlineViewDelegate
name:CPOutlineViewSelectionIsChangingNotification name:CPOutlineViewSelectionIsChangingNotification
object:self]; object:self];
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewItemWillExpand:)])
[defaultCenter
removeObserver:_outlineViewDelegate
name:CPOutlineViewItemWillExpandNotification
object:self];
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewItemDidExpand:)])
[defaultCenter
removeObserver:_outlineViewDelegate
name:CPOutlineViewItemDidExpandNotification
object:self];
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewItemWillCollapse:)])
[defaultCenter
removeObserver:_outlineViewDelegate
name:CPOutlineViewItemWillCollapseNotification
object:self];
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewItemDidCollapse:)])
[defaultCenter
removeObserver:_outlineViewDelegate
name:CPOutlineViewItemDidCollapseNotification
object:self];
} }
_outlineViewDelegate = aDelegate; _outlineViewDelegate = aDelegate;
_implementedOutlineViewDelegateMethods = 0; _implementedOutlineViewDelegateMethods = 0;
var delegateMethods = [ if ([_outlineViewDelegate respondsToSelector:@selector(outlineView:dataViewForTableColumn:item:)])
CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_ , @selector(outlineView:dataViewForTableColumn:item:), _implementedOutlineViewDelegateMethods |= CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_;
CPOutlineViewDelegate_outlineView_didClickTableColumn_ , @selector(outlineView:didClickTableColumn:),
CPOutlineViewDelegate_outlineView_didDragTableColumn_ , @selector(outlineView:didDragTableColumn:), if ([_outlineViewDelegate respondsToSelector:@selector(outlineView:shouldSelectItem:)])
CPOutlineViewDelegate_outlineView_heightOfRowByItem_ , @selector(outlineView:heightOfRowByItem:), _implementedOutlineViewDelegateMethods |= CPOutlineViewDelegate_outlineView_shouldSelectItem_;
CPOutlineViewDelegate_outlineView_isGroupItem_ , @selector(outlineView:isGroupItem:),
CPOutlineViewDelegate_outlineView_mouseDownInHeaderOfTableColumn_ , @selector(outlineView:mouseDownInHeaderOfTableColumn:), if ([_outlineViewDelegate respondsToSelector:@selector(outlineView:heightOfRowByItem:)])
CPOutlineViewDelegate_outlineView_nextTypeSelectMatchFromItem_toItem_forString_ , @selector(outlineView:nextTypeSelectMatchFromItem:toItem:forString:), _implementedOutlineViewDelegateMethods |= CPOutlineViewDelegate_outlineView_heightOfRowByItem_;
CPOutlineViewDelegate_outlineView_selectionIndexesForProposedSelection_ , @selector(outlineView:selectionIndexesForProposedSelection:),
CPOutlineViewDelegate_outlineView_shouldCollapseItem_ , @selector(outlineView:shouldCollapseItem:),
CPOutlineViewDelegate_outlineView_shouldEditTableColumn_item_ , @selector(outlineView:shouldEditTableColumn:item:),
CPOutlineViewDelegate_outlineView_shouldExpandItem_ , @selector(outlineView:shouldExpandItem:),
CPOutlineViewDelegate_outlineView_shouldReorderColumn_toColumn_ , @selector(outlineView:shouldReorderColumn:toColumn:),
CPOutlineViewDelegate_outlineView_shouldSelectItem_ , @selector(outlineView:shouldSelectItem:),
CPOutlineViewDelegate_outlineView_shouldSelectTableColumn_ , @selector(outlineView:shouldSelectTableColumn:),
CPOutlineViewDelegate_outlineView_shouldShowOutlineViewForItem_ , @selector(outlineView:shouldShowOutlineViewForItem:),
CPOutlineViewDelegate_outlineView_shouldShowViewExpansionForTableColumn_item_ , @selector(outlineView:shouldShowViewExpansionForTableColumn:item:),
CPOutlineViewDelegate_outlineView_shouldTrackView_forTableColumn_item_ , @selector(outlineView:shouldTrackView:forTableColumn:item:),
CPOutlineViewDelegate_outlineView_shouldTypeSelectForEvent_withCurrentSearchString_ , @selector(outlineView:shouldTypeSelectForEvent:withCurrentSearchString:),
CPOutlineViewDelegate_outlineView_sizeToFitWidthOfColumn_ , @selector(outlineView:sizeToFitWidthOfColumn:),
CPOutlineViewDelegate_outlineView_toolTipForView_rect_tableColumn_item_mouseLocation_, @selector(outlineView:toolTipForView:rect:tableColumn:item:mouseLocation:),
CPOutlineViewDelegate_outlineView_typeSelectStringForTableColumn_item_ , @selector(outlineView:typeSelectStringForTableColumn:item:),
CPOutlineViewDelegate_outlineView_willDisplayOutlineView_forTableColumn_item_ , @selector(outlineView:willDisplayOutlineView:forTableColumn:item:),
CPOutlineViewDelegate_outlineView_willDisplayView_forTableColumn_item_ , @selector(outlineView:willDisplayView:forTableColumn:item:),
CPOutlineViewDelegate_selectionShouldChangeInOutlineView_ , @selector(selectionShouldChangeInOutlineView:)
],
delegateCount = [delegateMethods count];
for (var i=0; i < delegateCount; i += 2) if ([_outlineViewDelegate respondsToSelector:@selector(outlineView:willDisplayView:forTableColumn:item:)])
{ _implementedOutlineViewDelegateMethods |= CPOutlineViewDelegate_outlineView_willDisplayView_forTableColumn_item_;
var bitMask = delegateMethods[i],
selector = delegateMethods[i+1];
if ([_outlineViewDelegate respondsToSelector:selector]) if ([_outlineViewDelegate respondsToSelector:@selector(outlineView:isGroupItem:)])
_implementedOutlineViewDelegateMethods |= bitMask; _implementedOutlineViewDelegateMethods |= CPOutlineViewDelegate_outlineView_isGroupItem_;
}
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewColumnDidMove:)]) if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewColumnDidMove:)])
[defaultCenter [defaultCenter
@@ -549,36 +500,6 @@ CPOutlineViewDropOnItemIndex = -1;
selector:@selector(outlineViewSelectionIsChanging:) selector:@selector(outlineViewSelectionIsChanging:)
name:CPOutlineViewSelectionIsChangingNotification name:CPOutlineViewSelectionIsChangingNotification
object:self]; object:self];
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewItemWillExpand:)])
[defaultCenter
addObserver:_outlineViewDelegate
selector:@selector(outlineViewItemWillExpand:)
name:CPOutlineViewItemWillExpandNotification
object:self];
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewItemDidExpand:)])
[defaultCenter
addObserver:_outlineViewDelegate
selector:@selector(outlineViewItemDidExpand:)
name:CPOutlineViewItemDidExpandNotification
object:self];
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewItemWillCollapse:)])
[defaultCenter
addObserver:_outlineViewDelegate
selector:@selector(outlineViewItemWillCollapse:)
name:CPOutlineViewItemWillCollapseNotification
object:self];
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewItemDidCollapse:)])
[defaultCenter
addObserver:_outlineViewDelegate
selector:@selector(outlineViewItemDidCollapse:)
name:CPOutlineViewItemDidCollapseNotification
object:self];
} }
- (id)delegate - (id)delegate
@@ -613,63 +534,18 @@ CPOutlineViewDropOnItemIndex = -1;
- (void)setDropItem:(id)theItem dropChildIndex:(int)theIndex - (void)setDropItem:(id)theItem dropChildIndex:(int)theIndex
{ {
if (_dropItem !== theItem && theIndex < 0 && [self isExpandable:theItem] && ![self isItemExpanded:theItem])
{
if (_dragHoverTimer)
[_dragHoverTimer invalidate];
var autoExpandCallBack = function(){
if (_dropItem)
{
[_dropOperationFeedbackView blink];
[CPTimer scheduledTimerWithTimeInterval:.3 callback:objj_msgSend(self, "expandItem:", _dropItem) repeats:NO];
}
}
_dragHoverTimer = [CPTimer scheduledTimerWithTimeInterval:.8 callback:autoExpandCallBack repeats:NO];
}
if (theIndex >= 0)
{
[_dragHoverTimer invalidate];
_dragHoverTimer = nil;
}
_dropItem = theItem;
_retargetedItem = theItem; _retargetedItem = theItem;
_shouldRetargetItem = YES; _shouldRetargetItem = YES;
_retargedChildIndex = theIndex; _retargedChildIndex = theIndex;
_shouldRetargetChildIndex = YES; _shouldRetargetChildIndex = YES;
// set CPTableView's _retargetedDropRow based on retargetedItem and retargetedChildIndex
var retargetedItemInfo = (_retargetedItem !== nil) ? _itemInfosForItems[[_retargetedItem UID]] : _rootItemInfo;
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
{
[super _draggingEnded];
_dropItem = nil;
[_dragHoverTimer invalidate];
_dragHoverTimer = nil;
} }
- (id)_parentItemForUpperRow:(int)theUpperRowIndex andLowerRow:(int)theLowerRowIndex atMouseOffset:(CPPoint)theOffset - (id)_parentItemForUpperRow:(int)theUpperRowIndex andLowerRow:(int)theLowerRowIndex atMouseOffset:(CPPoint)theOffset
{ {
if (_shouldRetargetItem) if (_shouldRetargetItem)
return _retargetedItem; return _retargetedItem;
var lowerLevel = [self levelForRow:theLowerRowIndex] var lowerLevel = [self levelForRow:theLowerRowIndex]
upperItem = [self itemAtRow:theUpperRowIndex]; upperItem = [self itemAtRow:theUpperRowIndex];
upperLevel = [self levelForItem:upperItem]; upperLevel = [self levelForItem:upperItem];
@@ -688,7 +564,7 @@ CPOutlineViewDropOnItemIndex = -1;
// Check the next parent // Check the next parent
upperItem = [self parentForItem:upperItem]; upperItem = [self parentForItem:upperItem];
} }
return [self parentForItem:[self itemAtRow:theLowerRowIndex]]; return [self parentForItem:[self itemAtRow:theLowerRowIndex]];
} }
@@ -698,10 +574,10 @@ CPOutlineViewDropOnItemIndex = -1;
var rect = [super _rectForDropHighlightViewBetweenUpperRow:theUpperRowIndex andLowerRow:theLowerRowIndex offset:theOffset], var rect = [super _rectForDropHighlightViewBetweenUpperRow:theUpperRowIndex andLowerRow:theLowerRowIndex offset:theOffset],
parentItem = [self _parentItemForUpperRow:theUpperRowIndex andLowerRow:theLowerRowIndex atMouseOffset:theOffset], parentItem = [self _parentItemForUpperRow:theUpperRowIndex andLowerRow:theLowerRowIndex atMouseOffset:theOffset],
level = [self levelForItem:parentItem]; level = [self levelForItem:parentItem];
rect.origin.x = (level + 1) * [self indentationPerLevel]; rect.origin.x = (level + 1) * [self indentationPerLevel];
rect.size.width -= rect.origin.x; // This assumes that the x returned by super is zero rect.size.width -= rect.origin.x; // This assumes that the x returned by super is zero
return rect; return rect;
} }
@@ -743,8 +619,6 @@ CPOutlineViewDropOnItemIndex = -1;
_disclosureControlsForRows[row] = control; _disclosureControlsForRows[row] = control;
[control setState:[self isItemExpanded:item] ? CPOnState : CPOffState]; [control setState:[self isItemExpanded:item] ? CPOnState : CPOffState];
var selector = [self isRowSelected:row] ? @"setThemeState:" : @"unsetThemeState:";
[control performSelector:CPSelectorFromString(selector) withObject:CPThemeStateSelected];
[control setFrame:frame]; [control setFrame:frame];
[self addSubview:control]; [self addSubview:control];
@@ -835,41 +709,9 @@ CPOutlineViewDropOnItemIndex = -1;
userInfo:nil]; userInfo:nil];
} }
- (void)_noteItemWillExpand:(id)item
{
[[CPNotificationCenter defaultCenter]
postNotificationName:CPOutlineViewItemWillExpandNotification
object:self
userInfo:[CPDictionary dictionaryWithObject:item forKey:"CPObject"]];
}
- (void)_noteItemDidExpand:(id)item
{
[[CPNotificationCenter defaultCenter]
postNotificationName:CPOutlineViewItemDidExpandNotification
object:self
userInfo:[CPDictionary dictionaryWithObject:item forKey:"CPObject"]];
}
- (void)_noteItemWillCollapse:(id)item
{
[[CPNotificationCenter defaultCenter]
postNotificationName:CPOutlineViewItemWillCollapseNotification
object:self
userInfo:[CPDictionary dictionaryWithObject:item forKey:"CPObject"]];
}
- (void)_noteItemDidCollapse:(id)item
{
[[CPNotificationCenter defaultCenter]
postNotificationName:CPOutlineViewItemDidCollapseNotification
object:self
userInfo:[CPDictionary dictionaryWithObject:item forKey:"CPObject"]];
}
@end @end
// FIX ME: We're using with() here because Safari fails if we use anOutlineView._itemInfosForItems or whatever... // FIX ME: We're using with() here because Safari fails if we use anOutlineView._itemInfosForItems or whatever...
var _reloadItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anItem) var _reloadItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anItem)
{ {
if (!anItem) if (!anItem)
@@ -882,55 +724,55 @@ var _reloadItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anItem)
dataSource = _outlineViewDataSource, dataSource = _outlineViewDataSource,
itemUID = [anItem UID], itemUID = [anItem UID],
itemInfo = itemInfosForItems[itemUID]; itemInfo = itemInfosForItems[itemUID];
// If we're not in the tree, then just bail. // If we're not in the tree, then just bail.
if (!itemInfo) if (!itemInfo)
return []; return [];
// See if the item itself can be swapped out. // See if the item itself can be swapped out.
var parent = itemInfo.parent, var parent = itemInfo.parent,
parentItemInfo = parent ? itemInfosForItems[[parent UID]] : _rootItemInfo, parentItemInfo = parent ? itemInfosForItems[[parent UID]] : _rootItemInfo,
parentChildren = parentItemInfo.children, parentChildren = parentItemInfo.children,
index = [parentChildren indexOfObjectIdenticalTo:anItem], index = [parentChildren indexOfObjectIdenticalTo:anItem],
newItem = [dataSource outlineView:anOutlineView child:index ofItem:parent]; newItem = [dataSource outlineView:anOutlineView child:index ofItem:parent];
if (anItem !== newItem) if (anItem !== newItem)
{ {
itemInfosForItems[[anItem UID]] = nil; itemInfosForItems[[anItem UID]] = nil;
itemInfosForItems[[newItem UID]] = itemInfo; itemInfosForItems[[newItem UID]] = itemInfo;
parentChildren[index] = newItem; parentChildren[index] = newItem;
_itemsForRows[itemInfo.row] = newItem; _itemsForRows[itemInfo.row] = newItem;
} }
itemInfo.isExpandable = [dataSource outlineView:anOutlineView isItemExpandable:newItem]; itemInfo.isExpandable = [dataSource outlineView:anOutlineView isItemExpandable:newItem];
itemInfo.isExpanded = itemInfo.isExpandable && itemInfo.isExpanded; itemInfo.isExpanded = itemInfo.isExpandable && itemInfo.isExpanded;
} }
} }
// FIX ME: We're using with() here because Safari fails if we use anOutlineView._itemInfosForItems or whatever... // FIX ME: We're using with() here because Safari fails if we use anOutlineView._itemInfosForItems or whatever...
var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anItem, /*BOOL*/ isIntermediate) var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anItem, /*BOOL*/ isIntermediate)
{ {
with(anOutlineView) with(anOutlineView)
{ {
var itemInfosForItems = _itemInfosForItems, var itemInfosForItems = _itemInfosForItems,
dataSource = _outlineViewDataSource; dataSource = _outlineViewDataSource;
if (!anItem) if (!anItem)
var itemInfo = _rootItemInfo; var itemInfo = _rootItemInfo;
else else
{ {
// Get the existing info if it exists. // Get the existing info if it exists.
var itemUID = [anItem UID], var itemUID = [anItem UID],
itemInfo = itemInfosForItems[itemUID]; itemInfo = itemInfosForItems[itemUID];
// If we're not in the tree, then just bail. // If we're not in the tree, then just bail.
if (!itemInfo) if (!itemInfo)
return []; return [];
itemInfo.isExpandable = [dataSource outlineView:anOutlineView isItemExpandable:anItem]; itemInfo.isExpandable = [dataSource outlineView:anOutlineView isItemExpandable:anItem];
// If we were previously expanded, but now no longer expandable, "de-expand". // If we were previously expanded, but now no longer expandable, "de-expand".
// NOTE: we are *not* collapsing, thus no notification is posted. // NOTE: we are *not* collapsing, thus no notification is posted.
if (!itemInfo.isExpandable && itemInfo.isExpanded) if (!itemInfo.isExpandable && itemInfo.isExpanded)
@@ -939,72 +781,72 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
itemInfo.children = []; itemInfo.children = [];
} }
} }
// The root item does not count as a descendant. // The root item does not count as a descendant.
var weight = itemInfo.weight, var weight = itemInfo.weight,
descendants = anItem ? [anItem] : []; descendants = anItem ? [anItem] : [];
if (itemInfo.isExpanded && (!(_implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_shouldDeferDisplayingChildrenOfItem_) || if (itemInfo.isExpanded && (!(_implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_shouldDeferDisplayingChildrenOfItem_) ||
![dataSource outlineView:anOutlineView shouldDeferDisplayingChildrenOfItem:anItem])) ![dataSource outlineView:anOutlineView shouldDeferDisplayingChildrenOfItem:anItem]))
{ {
var index = 0, var index = 0,
count = [dataSource outlineView:anOutlineView numberOfChildrenOfItem:anItem], count = [dataSource outlineView:anOutlineView numberOfChildrenOfItem:anItem],
level = itemInfo.level + 1; level = itemInfo.level + 1;
itemInfo.children = []; itemInfo.children = [];
for (; index < count; ++index) for (; index < count; ++index)
{ {
var childItem = [dataSource outlineView:anOutlineView child:index ofItem:anItem], var childItem = [dataSource outlineView:anOutlineView child:index ofItem:anItem],
childItemInfo = itemInfosForItems[[childItem UID]]; childItemInfo = itemInfosForItems[[childItem UID]];
if (!childItemInfo) if (!childItemInfo)
{ {
childItemInfo = { isExpanded:NO, isExpandable:NO, children:[], weight:1 }; childItemInfo = { isExpanded:NO, isExpandable:NO, children:[], weight:1 };
itemInfosForItems[[childItem UID]] = childItemInfo; itemInfosForItems[[childItem UID]] = childItemInfo;
} }
itemInfo.children[index] = childItem; itemInfo.children[index] = childItem;
var childDescendants = _loadItemInfoForItem(anOutlineView, childItem, YES); var childDescendants = _loadItemInfoForItem(anOutlineView, childItem, YES);
childItemInfo.parent = anItem; childItemInfo.parent = anItem;
childItemInfo.level = level; childItemInfo.level = level;
descendants = descendants.concat(childDescendants); descendants = descendants.concat(childDescendants);
} }
} }
itemInfo.weight = descendants.length; itemInfo.weight = descendants.length;
if (!isIntermediate) if (!isIntermediate)
{ {
// row = -1 is the root item, so just go to row 0 since it is ignored. // row = -1 is the root item, so just go to row 0 since it is ignored.
var index = MAX(itemInfo.row, 0), var index = MAX(itemInfo.row, 0),
itemsForRows = _itemsForRows; itemsForRows = _itemsForRows;
descendants.unshift(index, weight); descendants.unshift(index, weight);
itemsForRows.splice.apply(itemsForRows, descendants); itemsForRows.splice.apply(itemsForRows, descendants);
var count = itemsForRows.length; var count = itemsForRows.length;
for (; index < count; ++index) for (; index < count; ++index)
itemInfosForItems[[itemsForRows[index] UID]].row = index; itemInfosForItems[[itemsForRows[index] UID]].row = index;
var deltaWeight = itemInfo.weight - weight; var deltaWeight = itemInfo.weight - weight;
if (deltaWeight !== 0) if (deltaWeight !== 0)
{ {
var parent = itemInfo.parent; var parent = itemInfo.parent;
while (parent) while (parent)
{ {
var parentItemInfo = itemInfosForItems[[parent UID]]; var parentItemInfo = itemInfosForItems[[parent UID]];
parentItemInfo.weight += deltaWeight; parentItemInfo.weight += deltaWeight;
parent = parentItemInfo.parent; parent = parentItemInfo.parent;
} }
if (anItem) if (anItem)
_rootItemInfo.weight += deltaWeight; _rootItemInfo.weight += deltaWeight;
} }
@@ -1038,27 +880,20 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
return [_outlineView._outlineViewDataSource outlineView:_outlineView objectValueForTableColumn:aTableColumn byItem:_outlineView._itemsForRows[aRow]]; return [_outlineView._outlineViewDataSource outlineView:_outlineView objectValueForTableColumn:aTableColumn byItem:_outlineView._itemsForRows[aRow]];
} }
- (void)tableView:(CPTableView)aTableView setObjectValue:(id)aValue forTableColumn:(CPTableColumn)aColumn row:(CPInteger)aRow
{
if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_))
return;
[_outlineView._outlineViewDataSource outlineView:_outlineView setObjectValue:aValue forTableColumn:aColumn byItem:_outlineView._itemsForRows[aRow]];
}
- (BOOL)tableView:(CPTableView)aTableColumn writeRowsWithIndexes:(CPIndexSet)theIndexes toPasteboard:(CPPasteboard)thePasteboard - (BOOL)tableView:(CPTableView)aTableColumn writeRowsWithIndexes:(CPIndexSet)theIndexes toPasteboard:(CPPasteboard)thePasteboard
{ {
if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_writeItems_toPasteboard_)) if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_writeItems_toPasteboard_))
return NO; return NO;
var rowIndexes = []; var rowIndexes = [];
[theIndexes getIndexes:rowIndexes maxCount:[theIndexes count] inIndexRange:nil]; [theIndexes getIndexes:rowIndexes maxCount:[theIndexes count] inIndexRange:nil];
var rowIndex = [rowIndexes count], var rowIndex = [rowIndexes count],
items = []; items = [];
while (rowIndex--) while (rowIndex--)
[items addObject:[_outlineView itemAtRow:[rowIndexes objectAtIndex:rowIndex]]]; [items addObject:[_outlineView itemAtRow:[rowIndexes objectAtIndex:rowIndex]]];
return [_outlineView._outlineViewDataSource outlineView:_outlineView writeItems:items toPasteboard:thePasteboard]; return [_outlineView._outlineViewDataSource outlineView:_outlineView writeItems:items toPasteboard:thePasteboard];
} }
@@ -1066,15 +901,15 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
{ {
if (_outlineView._shouldRetargetChildIndex) if (_outlineView._shouldRetargetChildIndex)
return _outlineView._retargedChildIndex; return _outlineView._retargedChildIndex;
var childIndex = CPNotFound; var childIndex = CPNotFound;
if (theDropOperation === CPTableViewDropAbove) if (theDropOperation === CPTableViewDropAbove)
{ {
var parentItem = [_outlineView _parentItemForUpperRow:theRow - 1 andLowerRow:theRow atMouseOffset:theOffset], var parentItem = [_outlineView _parentItemForUpperRow:theRow - 1 andLowerRow:theRow atMouseOffset:theOffset],
itemInfo = (parentItem !== nil) ? _outlineView._itemInfosForItems[[parentItem UID]] : _outlineView._rootItemInfo, itemInfo = (parentItem !== nil) ? _outlineView._itemInfosForItems[[parentItem UID]] : _outlineView._rootItemInfo,
children = itemInfo.children; children = itemInfo.children;
childIndex = [children indexOfObject:[_outlineView itemAtRow:theRow]]; childIndex = [children indexOfObject:[_outlineView itemAtRow:theRow]];
if (childIndex === CPNotFound) if (childIndex === CPNotFound)
@@ -1089,12 +924,12 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
- (void)_parentItemForDropOperation:(CPTableViewDropOperation)theDropOperation row:(int)theRow offset:(CPPoint)theOffset - (void)_parentItemForDropOperation:(CPTableViewDropOperation)theDropOperation row:(int)theRow offset:(CPPoint)theOffset
{ {
if (theDropOperation === CPTableViewDropAbove) if (theDropOperation === CPTableViewDropAbove)
return [_outlineView _parentItemForUpperRow:theRow - 1 andLowerRow:theRow atMouseOffset:theOffset] return [_outlineView _parentItemForUpperRow:theRow - 1 andLowerRow:theRow atMouseOffset:theOffset]
return [_outlineView itemAtRow:theRow]; return [_outlineView itemAtRow:theRow];
} }
- (CPDragOperation)tableView:(CPTableView)aTableView validateDrop:(id < CPDraggingInfo >)theInfo - (CPDragOperation)tableView:(CPTableView)aTableView validateDrop:(id < CPDraggingInfo >)theInfo
proposedRow:(int)theRow proposedDropOperation:(CPTableViewDropOperation)theOperation proposedRow:(int)theRow proposedDropOperation:(CPTableViewDropOperation)theOperation
{ {
if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_validateDrop_proposedItem_proposedChildIndex_)) if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_validateDrop_proposedItem_proposedChildIndex_))
@@ -1108,21 +943,21 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
_outlineView._shouldRetargetChildIndex = NO; _outlineView._shouldRetargetChildIndex = NO;
var location = [_outlineView convertPoint:[theInfo draggingLocation] fromView:nil], 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]; childIndex = [self _childIndexForDropOperation:theOperation row:theRow offset:location];
return [_outlineView._outlineViewDataSource outlineView:_outlineView validateDrop:theInfo proposedItem:parentItem proposedChildIndex:childIndex]; return [_outlineView._outlineViewDataSource outlineView:_outlineView validateDrop:theInfo proposedItem:parentItem proposedChildIndex:childIndex];
} }
- (BOOL)tableView:(CPTableView)aTableView acceptDrop:(id <CPDraggingInfo>)theInfo row:(int)theRow dropOperation:(CPTableViewDropOperation)theOperation - (BOOL)tableView:(CPTableView)aTableView acceptDrop:(id <CPDraggingInfo>)theInfo row:(int)theRow dropOperation:(CPTableViewDropOperation)theOperation
{ {
if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_acceptDrop_item_childIndex_)) if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_acceptDrop_item_childIndex_))
return NO; return NO;
var location = [_outlineView convertPoint:[theInfo draggingLocation] fromView:nil], 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]; childIndex = [self _childIndexForDropOperation:theOperation row:theRow offset:location];
_outlineView._retargetedItem = nil; _outlineView._retargetedItem = nil;
_outlineView._shouldRetargetItem = NO; _outlineView._shouldRetargetItem = NO;
@@ -1152,15 +987,15 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
- (CPView)tableView:(CPTableView)theTableView dataViewForTableColumn:(CPTableColumn)theTableColumn row:(int)theRow - (CPView)tableView:(CPTableView)theTableView dataViewForTableColumn:(CPTableColumn)theTableColumn row:(int)theRow
{ {
var dataView = nil; var dataView = nil;
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_)) if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_))
dataView = [_outlineView._outlineViewDelegate outlineView:_outlineView dataView = [_outlineView._outlineViewDelegate outlineView:_outlineView
dataViewForTableColumn:theTableColumn dataViewForTableColumn:theTableColumn
item:[_outlineView itemAtRow:theRow]]; item:[_outlineView itemAtRow:theRow]];
if (!dataView) if (!dataView)
dataView = [theTableColumn dataViewForRow:theRow]; dataView = [theTableColumn dataViewForRow:theRow];
return dataView; return dataView;
} }
@@ -1168,18 +1003,10 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
{ {
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_shouldSelectItem_)) if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_shouldSelectItem_))
return [_outlineView._outlineViewDelegate outlineView:_outlineView shouldSelectItem:[_outlineView itemAtRow:theRow]]; return [_outlineView._outlineViewDelegate outlineView:_outlineView shouldSelectItem:[_outlineView itemAtRow:theRow]];
return YES; return YES;
} }
- (BOOL)tableView:(CPTableView)aTableView shouldEditTableColumn:(CPTableColumn)aColumn row:(int)aRow
{
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_shouldEditTableColumn_item_))
return [_outlineView._outlineViewDelegate outlineView:_outlineView shouldEditTableColumn:aColumn item:[_outlineView itemAtRow:aRow]];
return NO;
}
- (float)tableView:(CPTableView)theTableView heightOfRow:(int)theRow - (float)tableView:(CPTableView)theTableView heightOfRow:(int)theRow
{ {
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_heightOfRowByItem_)) if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_heightOfRowByItem_))
@@ -1197,10 +1024,10 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
} }
} }
- (BOOL)tableView:(CPTableView)aTableView isGroupRow:(int)aRow - (BOOL)tableView:(CPTableView)aTableView isGroupRow:(int)row
{ {
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_isGroupItem_)) if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_isGroupItem_))
return [_outlineView._outlineViewDelegate outlineView:_outlineView isGroupItem:[_outlineView itemAtRow:aRow]]; return [_outlineView._outlineViewDelegate outlineView:_outlineView isGroupItem:[_outlineView itemAtRow:theRow]];
return NO; return NO;
} }
@@ -1253,82 +1080,9 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
CGContextAddLineToPoint(context, 0.0, 0.0); CGContextAddLineToPoint(context, 0.0, 0.0);
CGContextClosePath(context); CGContextClosePath(context);
CGContextSetFillColor(context,
colorForDisclosureTriangle([self hasThemeState:CPThemeStateSelected], CGContextSetFillColor(context, [self isHighlighted] ? [CPColor whiteColor] : [CPColor grayColor]);
[self hasThemeState:CPThemeStateHighlighted]));
CGContextFillPath(context); 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 @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]);
}
+2
View File
@@ -25,6 +25,8 @@
@import <Foundation/CPDictionary.j> @import <Foundation/CPDictionary.j>
@import <Foundation/CPPropertyListSerialization.j> @import <Foundation/CPPropertyListSerialization.j>
#include "Platform/Platform.h"
CPGeneralPboard = @"CPGeneralPboard"; CPGeneralPboard = @"CPGeneralPboard";
CPFontPboard = @"CPFontPboard"; CPFontPboard = @"CPFontPboard";
+41 -65
View File
@@ -25,12 +25,14 @@
@import "CPMenu.j" @import "CPMenu.j"
@import "CPMenuItem.j" @import "CPMenuItem.j"
#include "CoreGraphics/CGGeometry.h"
var VISIBLE_MARGIN = 7.0; var VISIBLE_MARGIN = 7.0;
CPPopUpButtonStatePullsDown = CPThemeState("pulls-down"); CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
/*! /*!
@ingroup appkit @ingroup appkit
@class CPPopUpButton @class CPPopUpButton
@@ -40,11 +42,11 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
{ {
int _selectedIndex; int _selectedIndex;
CPRectEdge _preferredEdge; CPRectEdge _preferredEdge;
CPMenu _menu; CPMenu _menu;
} }
+ (CPString)defaultThemeClass + (CPString)themeClass
{ {
return "popup-button"; return "popup-button";
} }
@@ -58,21 +60,21 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
- (id)initWithFrame:(CGRect)aFrame pullsDown:(BOOL)shouldPullDown - (id)initWithFrame:(CGRect)aFrame pullsDown:(BOOL)shouldPullDown
{ {
self = [super initWithFrame:aFrame]; self = [super initWithFrame:aFrame];
if (self) if (self)
{ {
_selectedIndex = CPNotFound; _selectedIndex = CPNotFound;
_preferredEdge = CPMaxYEdge; _preferredEdge = CPMaxYEdge;
[self setValue:CPImageLeft forThemeAttribute:@"image-position"]; [self setValue:CPImageLeft forThemeAttribute:@"image-position"];
[self setValue:CPLeftTextAlignment forThemeAttribute:@"alignment"]; [self setValue:CPLeftTextAlignment forThemeAttribute:@"alignment"];
[self setValue:CPLineBreakByTruncatingTail forThemeAttribute:@"line-break-mode"]; [self setValue:CPLineBreakByTruncatingTail forThemeAttribute:@"line-break-mode"];
[self setMenu:[[CPMenu alloc] initWithTitle:@""]]; [self setMenu:[[CPMenu alloc] initWithTitle:@""]];
[self setPullsDown:shouldPullDown]; [self setPullsDown:shouldPullDown];
} }
return self; return self;
} }
@@ -143,7 +145,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
{ {
var index = 0, var index = 0,
count = [titles count]; count = [titles count];
for (; index < count; ++index) for (; index < count; ++index)
[self addItemWithTitle:titles[index]]; [self addItemWithTitle:titles[index]];
} }
@@ -157,11 +159,11 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
{ {
var items = [self itemArray], var items = [self itemArray],
count = [items count]; count = [items count];
while (count--) while (count--)
if ([items[count] title] == aTitle) if ([items[count] title] == aTitle)
[self removeItemAtIndex:count]; [self removeItemAtIndex:count];
[_menu insertItemWithTitle:aTitle action:NULL keyEquivalent:nil atIndex:anIndex]; [_menu insertItemWithTitle:aTitle action:NULL keyEquivalent:nil atIndex:anIndex];
} }
@@ -171,7 +173,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
- (void)removeAllItems - (void)removeAllItems
{ {
var count = [_menu numberOfItems]; var count = [_menu numberOfItems];
while (count--) while (count--)
[_menu removeItemAtIndex:0]; [_menu removeItemAtIndex:0];
} }
@@ -204,7 +206,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
{ {
if (_selectedIndex < 0 || _selectedIndex > [self numberOfItems] - 1) if (_selectedIndex < 0 || _selectedIndex > [self numberOfItems] - 1)
return nil; return nil;
return [_menu itemAtIndex:_selectedIndex]; return [_menu itemAtIndex:_selectedIndex];
} }
@@ -251,15 +253,15 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
{ {
if (_selectedIndex == anIndex) if (_selectedIndex == anIndex)
return; return;
if (_selectedIndex >= 0 && ![self pullsDown]) if (_selectedIndex >= 0 && ![self pullsDown])
[[self selectedItem] setState:CPOffState]; [[self selectedItem] setState:CPOffState];
_selectedIndex = anIndex; _selectedIndex = anIndex;
if (_selectedIndex >= 0 && ![self pullsDown]) if (_selectedIndex >= 0 && ![self pullsDown])
[[self selectedItem] setState:CPOnState]; [[self selectedItem] setState:CPOnState];
[self synchronizeTitleAndSelectedItem]; [self synchronizeTitleAndSelectedItem];
} }
@@ -308,7 +310,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
return; return;
var defaultCenter = [CPNotificationCenter defaultCenter]; var defaultCenter = [CPNotificationCenter defaultCenter];
if (_menu) if (_menu)
{ {
[defaultCenter [defaultCenter
@@ -328,7 +330,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
} }
_menu = aMenu; _menu = aMenu;
if (_menu) if (_menu)
{ {
[defaultCenter [defaultCenter
@@ -336,20 +338,20 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
selector:@selector(menuDidAddItem:) selector:@selector(menuDidAddItem:)
name:CPMenuDidAddItemNotification name:CPMenuDidAddItemNotification
object:_menu]; object:_menu];
[defaultCenter [defaultCenter
addObserver:self addObserver:self
selector:@selector(menuDidChangeItem:) selector:@selector(menuDidChangeItem:)
name:CPMenuDidChangeItemNotification name:CPMenuDidChangeItemNotification
object:_menu]; object:_menu];
[defaultCenter [defaultCenter
addObserver:self addObserver:self
selector:@selector(menuDidRemoveItem:) selector:@selector(menuDidRemoveItem:)
name:CPMenuDidRemoveItemNotification name:CPMenuDidRemoveItemNotification
object:_menu]; object:_menu];
} }
[self synchronizeTitleAndSelectedItem]; [self synchronizeTitleAndSelectedItem];
} }
@@ -394,13 +396,12 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
{ {
var titles = [], var titles = [],
items = [self itemArray], items = [self itemArray],
index = 0, index = 0,
count = [items count]; count = [items count];
for (; index < count; ++index) for (; index < count; ++index)
titles.push([items[index] title]); items.push([items[index] title]);
return titles;
} }
/*! /*!
@@ -518,14 +519,14 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
else else
{ {
var index = [self indexOfItemWithTitle:aTitle]; var index = [self indexOfItemWithTitle:aTitle];
if (index < 0) if (index < 0)
{ {
[self addItemWithTitle:aTitle]; [self addItemWithTitle:aTitle];
index = [self numberOfItems] - 1; index = [self numberOfItems] - 1;
} }
[self selectItemAtIndex:index]; [self selectItemAtIndex:index];
} }
} }
@@ -553,7 +554,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
if ([self pullsDown]) if ([self pullsDown])
{ {
var items = [_menu itemArray]; var items = [_menu itemArray];
if ([items count] > 0) if ([items count] > 0)
item = items[0]; item = items[0];
} }
@@ -572,22 +573,22 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
- (void)menuDidAddItem:(CPNotification)aNotification - (void)menuDidAddItem:(CPNotification)aNotification
{ {
var index = [[aNotification userInfo] objectForKey:@"CPMenuItemIndex"]; var index = [[aNotification userInfo] objectForKey:@"CPMenuItemIndex"];
if (_selectedIndex < 0) if (_selectedIndex < 0)
[self selectItemAtIndex:0]; [self selectItemAtIndex:0];
else if (index == _selectedIndex) else if (index == _selectedIndex)
[self synchronizeTitleAndSelectedItem]; [self synchronizeTitleAndSelectedItem];
else if (index < _selectedIndex) else if (index < _selectedIndex)
++_selectedIndex; ++_selectedIndex;
if (index == 0 && [self pullsDown]) if (index == 0 && [self pullsDown])
{ {
var items = [_menu itemArray]; var items = [_menu itemArray];
[items[0] setHidden:YES]; [items[0] setHidden:YES];
if (items.length > 0) if (items.length > 0)
[items[1] setHidden:NO]; [items[1] setHidden:NO];
} }
@@ -612,10 +613,10 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
if ([self pullsDown] && index != 0) if ([self pullsDown] && index != 0)
return; return;
if (![self pullsDown] && index != _selectedIndex) if (![self pullsDown] && index != _selectedIndex)
return; return;
[self synchronizeTitleAndSelectedItem]; [self synchronizeTitleAndSelectedItem];
} }
@@ -626,7 +627,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
- (void)menuDidRemoveItem:(CPNotification)aNotification - (void)menuDidRemoveItem:(CPNotification)aNotification
{ {
var numberOfItems = [self numberOfItems]; var numberOfItems = [self numberOfItems];
if (numberOfItems <= _selectedIndex && numberOfItems > 0) if (numberOfItems <= _selectedIndex && numberOfItems > 0)
[self selectItemAtIndex:numberOfItems - 1]; [self selectItemAtIndex:numberOfItems - 1];
else else
@@ -660,9 +661,6 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
location = CGPointMake(CGRectGetMinX(contentRect) - standardLeftMargin, 0.0); location = CGPointMake(CGRectGetMinX(contentRect) - standardLeftMargin, 0.0);
minimumWidth += standardLeftMargin; minimumWidth += standardLeftMargin;
// To ensure the selected item is highlighted correctly, unset the highlighted item
[menu _highlightItemAtIndex:CPNotFound];
} }
[menu setMinimumWidth:minimumWidth]; [menu setMinimumWidth:minimumWidth];
@@ -700,33 +698,11 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/ */
} }
- (void)rightMouseDown:(CPEvent)anEvent
{
// Disable standard CPView behaviour which incorrectly displays the menu as a 'context menu'.
}
- (void)_popUpItemAction:(id)aSender - (void)_popUpItemAction:(id)aSender
{ {
[self sendAction:[self action] to:[self target]]; [self sendAction:[self action] to:[self target]];
} }
- (void)takeValueFromKeyPath:(CPString)aKeyPath ofObjects:(CPArray)objects
{
var count = objects.length,
value = [objects[0] valueForKeyPath:aKeyPath];
[self selectItemWithTag:value];
[self setEnabled:YES];
while (count-- > 1)
{
if (value !== [objects[count] valueForKeyPath:aKeyPath])
{
[[self selectedItem] setState:CPOffState];
}
}
}
@end @end
var CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey", var CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey",
@@ -744,7 +720,7 @@ var CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey",
- (id)initWithCoder:(CPCoder)aCoder - (id)initWithCoder:(CPCoder)aCoder
{ {
self = [super initWithCoder:aCoder]; self = [super initWithCoder:aCoder];
if (self) if (self)
{ {
// Nothing is currently selected // Nothing is currently selected
@@ -753,7 +729,7 @@ var CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey",
[self setMenu:[aCoder decodeObjectForKey:CPPopUpButtonMenuKey]]; [self setMenu:[aCoder decodeObjectForKey:CPPopUpButtonMenuKey]];
[self selectItemAtIndex:[aCoder decodeObjectForKey:CPPopUpButtonSelectedIndexKey]]; [self selectItemAtIndex:[aCoder decodeObjectForKey:CPPopUpButtonSelectedIndexKey]];
} }
return self; return self;
} }
@@ -765,7 +741,7 @@ var CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey",
- (void)encodeWithCoder:(CPCoder)aCoder - (void)encodeWithCoder:(CPCoder)aCoder
{ {
[super encodeWithCoder:aCoder]; [super encodeWithCoder:aCoder];
[aCoder encodeObject:_menu forKey:CPPopUpButtonMenuKey]; [aCoder encodeObject:_menu forKey:CPPopUpButtonMenuKey];
[aCoder encodeInt:_selectedIndex forKey:CPPopUpButtonSelectedIndexKey]; [aCoder encodeInt:_selectedIndex forKey:CPPopUpButtonSelectedIndexKey];
} }
+5 -3
View File
@@ -20,9 +20,11 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
@import "CGGeometry.j" @import <AppKit/CGGeometry.j>
@import "CPImageView.j" @import <AppKit/CPImageView.j>
@import "CPView.j" @import <AppKit/CPView.j>
#include "CoreGraphics/CGGeometry.h"
/* /*
+15 -19
View File
@@ -25,29 +25,28 @@
@import "CPButton.j" @import "CPButton.j"
/*! /*!
@ingroup appkit @ingroup appkit
from this mailing list thread: 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: Creating a checkbox is easy enough:
checkbox = [[CPCheckBox alloc] initWithFrame:aFrame]; checkbox = [[CPCheckBox alloc] initWithFrame:aFrame];
That's basically all there is to it. Radio buttons are very similar, That's basically all there is to it. Radio buttons are very similar,
the key difference is the introduction of a new class CPRadioGroup, the key difference is the introduction of a new class CPRadioGroup,
which defines which radio buttons are part of the same group: which defines which radio buttons are part of the same group:
[myRadioButton setRadioGroup:aRadioGroup]; [myRadioButton setRadioGroup:aRadioGroup];
Every radio button receives a unique radio group by default (so if you Every radio button receives a unique radio group by default (so if you
do nothing further, they will all behave independently), but you can do nothing further, they will all behave independently), but you can
use an existing radio button's group with other buttons as so: use an existing radio button's group with other buttons as so:
button1 = [[CPRadio alloc] initWithFrame:aFrame]; button1 = [[CPRadio alloc] initWithFrame:aFrame];
... ...
button2 = [[CPRadio alloc] initWithFrame:aFrame radioGroup:[button1 button2 = [[CPRadio alloc] initWithFrame:aFrame radioGroup:[button1
@@ -56,16 +55,13 @@
button3 = [[CPRadio alloc] initWithFrame:aFrame radioGroup:[button1 button3 = [[CPRadio alloc] initWithFrame:aFrame radioGroup:[button1
radioGroup]]; radioGroup]];
...etc... ...etc...
Here, all the radio buttons will act "together". [[button1 radioGroup] Here, all the radio buttons will act "together". [[button1 radioGroup]
allRadios] returns every button that's part of this group, and allRadios] returns every button that's part of this group, and
[[button1 radioGroup] selectedRadio] returns the currently selected [[button1 radioGroup] selectedRadio] returns the currently selected
option. option.
*/ */
CPRadioImageOffset = 4.0;
@implementation CPRadio : CPButton @implementation CPRadio : CPButton
{ {
CPRadioGroup _radioGroup; CPRadioGroup _radioGroup;
@@ -90,7 +86,7 @@ CPRadioImageOffset = 4.0;
return button; return button;
} }
+ (CPString)defaultThemeClass + (CPString)themeClass
{ {
return @"radio"; return @"radio";
} }
@@ -99,7 +95,7 @@ CPRadioImageOffset = 4.0;
- (id)initWithFrame:(CGRect)aFrame radioGroup:(CPRadioGroup)aRadioGroup - (id)initWithFrame:(CGRect)aFrame radioGroup:(CPRadioGroup)aRadioGroup
{ {
self = [super initWithFrame:aFrame]; self = [super initWithFrame:aFrame];
if (self) if (self)
{ {
[self setRadioGroup:aRadioGroup]; [self setRadioGroup:aRadioGroup];
@@ -113,8 +109,8 @@ CPRadioImageOffset = 4.0;
[self setBordered:YES]; [self setBordered:YES];
} }
return self; return self;
} }
- (id)initWithFrame:(CGRect)aFrame - (id)initWithFrame:(CGRect)aFrame
@@ -145,7 +141,7 @@ CPRadioImageOffset = 4.0;
- (void)setObjectValue:(id)aValue - (void)setObjectValue:(id)aValue
{ {
[super setObjectValue:aValue]; [super setObjectValue:aValue];
if ([self state] === CPOnState) if ([self state] === CPOnState)
[_radioGroup _setSelectedRadio:self]; [_radioGroup _setSelectedRadio:self];
} }
+53 -47
View File
@@ -23,23 +23,22 @@
@import <Foundation/CPObject.j> @import <Foundation/CPObject.j>
CPDeleteKeyCode = 8; CPDeleteKeyCode = 8;
CPTabKeyCode = 9; CPTabKeyCode = 9;
CPReturnKeyCode = 13; CPReturnKeyCode = 13;
CPEscapeKeyCode = 27; CPEscapeKeyCode = 27;
CPSpaceKeyCode = 32; CPSpaceKeyCode = 32;
CPPageUpKeyCode = 33; CPPageUpKeyCode = 33;
CPPageDownKeyCode = 34; CPPageDownKeyCode = 34;
CPLeftArrowKeyCode = 37; CPLeftArrowKeyCode = 37;
CPUpArrowKeyCode = 38; CPUpArrowKeyCode = 38;
CPRightArrowKeyCode = 39; CPRightArrowKeyCode = 39;
CPDownArrowKeyCode = 40; CPDownArrowKeyCode = 40;
CPDeleteForwardKeyCode = 46;
/*! /*!
@ingroup appkit @ingroup appkit
@class CPResponder @class CPResponder
Subclasses of CPResonder can be part of the responder chain. Subclasses of CPResonder can be part of the responder chain.
*/ */
@implementation CPResponder : CPObject @implementation CPResponder : CPObject
@@ -105,24 +104,42 @@ CPDeleteForwardKeyCode = 46;
for (; index < count; ++index) for (; index < count; ++index)
{ {
var event = events[index], var event = events[index];
modifierFlags = [event modifierFlags],
character = [event charactersIgnoringModifiers],
selectorNames = [CPKeyBinding selectorsForKey:character modifierFlags:modifierFlags];
if (selectorNames) switch([event keyCode])
{ {
for (var s = 0, scount = selectorNames.length; s < scount; s++) case CPPageUpKeyCode: [self doCommandBySelector:@selector(pageUp:)];
{ break;
var selector = selectorNames[s]; case CPPageDownKeyCode: [self doCommandBySelector:@selector(pageDown:)];
if (!selector) break;
continue; 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;
[self doCommandBySelector:CPSelectorFromString(selector)]; case CPTabKeyCode: var shift = [event modifierFlags] & CPShiftKeyMask;
}
if (!shift)
[self doCommandBySelector:@selector(insertTab:)];
else
[self doCommandBySelector:@selector(insertBackTab:)];
break;
default: [self insertText:[event characters]];
} }
else if (!(modifierFlags & (CPCommandKeyMask | CPControlKeyMask)) && [self respondsToSelector:@selector(insertText:)])
[self insertText:[event characters]];
} }
} }
@@ -222,15 +239,6 @@ CPDeleteForwardKeyCode = 46;
[_nextResponder performSelector:_cmd withObject:anEvent]; [_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. FIXME This description is bad.
Based on \c anEvent, the receiver should simulate the event. Based on \c anEvent, the receiver should simulate the event.
@@ -261,6 +269,10 @@ CPDeleteForwardKeyCode = 46;
[[self nextResponder] insertNewline:aSender]; [[self nextResponder] insertNewline:aSender];
} }
- (void)cancel:(id)sender
{
}
- (void)insertTab:(id)sender - (void)insertTab:(id)sender
{ {
} }
@@ -300,10 +312,10 @@ CPDeleteForwardKeyCode = 46;
*/ */
- (BOOL)tryToPerform:(SEL)aSelector with:(id)anObject - (BOOL)tryToPerform:(SEL)aSelector with:(id)anObject
{ {
if ([self respondsToSelector:aSelector]) if([self respondsToSelector:aSelector])
{ {
[self performSelector:aSelector withObject:anObject]; [self performSelector:aSelector withObject:anObject];
return YES; return YES;
} }
@@ -342,8 +354,7 @@ CPDeleteForwardKeyCode = 46;
@end @end
var CPResponderNextResponderKey = @"CPResponderNextResponderKey", var CPResponderNextResponderKey = @"CPResponderNextResponderKey";
CPResponderMenuKey = @"CPResponderMenuKey";
@implementation CPResponder (CPCoding) @implementation CPResponder (CPCoding)
@@ -355,13 +366,10 @@ var CPResponderNextResponderKey = @"CPResponderNextResponderKey",
- (id)initWithCoder:(CPCoder)aCoder - (id)initWithCoder:(CPCoder)aCoder
{ {
self = [super init]; self = [super init];
if (self) if (self)
{
_nextResponder = [aCoder decodeObjectForKey:CPResponderNextResponderKey]; _nextResponder = [aCoder decodeObjectForKey:CPResponderNextResponderKey];
_menu = [aCoder decodeObjectForKey:CPResponderMenuKey];
}
return self; return self;
} }
@@ -374,8 +382,6 @@ var CPResponderNextResponderKey = @"CPResponderNextResponderKey",
// This will come out nil on the other side with decodeObjectForKey: // This will come out nil on the other side with decodeObjectForKey:
if (_nextResponder !== nil) if (_nextResponder !== nil)
[aCoder encodeConditionalObject:_nextResponder forKey:CPResponderNextResponderKey]; [aCoder encodeConditionalObject:_nextResponder forKey:CPResponderNextResponderKey];
[aCoder encodeObject:_menu forKey:CPResponderMenuKey];
} }
@end @end
+1 -1
View File
@@ -1,5 +1,5 @@
@import "CPPanel.j" @import <AppKit/CPPanel.j>
@implementation CPSavePanel : CPPanel @implementation CPSavePanel : CPPanel
+2
View File
@@ -1,6 +1,8 @@
@import <Foundation/CPObject.j> @import <Foundation/CPObject.j>
#import "CoreGraphics/CGGeometry.h"
#import "Platform/Platform.h"
@implementation CPScreen : CPObject @implementation CPScreen : CPObject
{ {
+96 -386
View File
@@ -20,13 +20,14 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
@import "CPBox.j" @import "CPView.j"
@import "CPClipView.j" @import "CPClipView.j"
@import "CPScroller.j" @import "CPScroller.j"
@import "CPView.j"
#include "CoreGraphics/CGGeometry.h"
/*! /*!
@ingroup appkit @ingroup appkit
@class CPScrollView @class CPScrollView
@@ -36,39 +37,23 @@
*/ */
@implementation CPScrollView : CPView @implementation CPScrollView : CPView
{ {
CPClipView _contentView; CPClipView _contentView;
CPClipView _headerClipView; CPClipView _headerClipView;
CPView _cornerView; CPView _cornerView;
CPView _bottomCornerView;
BOOL _hasVerticalScroller; BOOL _hasVerticalScroller;
BOOL _hasHorizontalScroller; BOOL _hasHorizontalScroller;
BOOL _autohidesScrollers; BOOL _autohidesScrollers;
CPScroller _verticalScroller; CPScroller _verticalScroller;
CPScroller _horizontalScroller; CPScroller _horizontalScroller;
int _recursionCount; int _recursionCount;
float _verticalLineScroll; float _verticalLineScroll;
float _verticalPageScroll; float _verticalPageScroll;
float _horizontalLineScroll; float _horizontalLineScroll;
float _horizontalPageScroll; float _horizontalPageScroll;
CPBorderType _borderType;
}
+ (CPString)defaultThemeClass
{
return @"scrollview"
}
+ (CPDictionary)themeAttributes
{
return [CPDictionary dictionaryWithJSObject:{
@"bottom-corner-color": [CPColor whiteColor],
@"border-color": [CPColor blackColor]
}];
} }
- (id)initWithFrame:(CGRect)aFrame - (id)initWithFrame:(CGRect)aFrame
@@ -83,17 +68,13 @@
_horizontalLineScroll = 10.0; _horizontalLineScroll = 10.0;
_horizontalPageScroll = 10.0; _horizontalPageScroll = 10.0;
_borderType = CPNoBorder; _contentView = [[CPClipView alloc] initWithFrame:[self bounds]];
_contentView = [[CPClipView alloc] initWithFrame:[self _insetBounds]];
[self addSubview:_contentView]; [self addSubview:_contentView];
_headerClipView = [[CPClipView alloc] init]; _headerClipView = [[CPClipView alloc] init];
[self addSubview:_headerClipView];
_bottomCornerView = [[CPView alloc] init]; [self addSubview:_headerClipView];
[self addSubview:_bottomCornerView];
[self setHasVerticalScroller:YES]; [self setHasVerticalScroller:YES];
[self setHasHorizontalScroller:YES]; [self setHasHorizontalScroller:YES];
@@ -102,70 +83,11 @@
return self; 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 // Determining component sizes
/*! /*!
Returns the size of the scroll view's content view. Returns the size of the scroll view's content view.
*/ */
- (CGSize)contentSize - (CGRect)contentSize
{ {
return [_contentView frame].size; return [_contentView frame].size;
} }
@@ -184,7 +106,7 @@
*/ */
- (void)setContentView:(CPClipView)aContentView - (void)setContentView:(CPClipView)aContentView
{ {
if (_contentView === aContentView || !aContentView) if (_contentView !== aContentView || !aContentView)
return; return;
var documentView = [aContentView documentView]; var documentView = [aContentView documentView];
@@ -231,16 +153,16 @@
*/ */
- (void)reflectScrolledClipView:(CPClipView)aClipView - (void)reflectScrolledClipView:(CPClipView)aClipView
{ {
if (_contentView !== aClipView) if(_contentView !== aClipView)
return; return;
if (_recursionCount > 5) if (_recursionCount > 5)
return; return;
++_recursionCount; ++_recursionCount;
var documentView = [self documentView]; var documentView = [self documentView];
if (!documentView) if (!documentView)
{ {
if (_autohidesScrollers) if (_autohidesScrollers)
@@ -254,7 +176,7 @@
// [_horizontalScroller setEnabled:NO]; // [_horizontalScroller setEnabled:NO];
} }
[_contentView setFrame:[self _insetBounds]]; [_contentView setFrame:[self bounds]];
[_headerClipView setFrame:_CGRectMakeZero()]; [_headerClipView setFrame:_CGRectMakeZero()];
--_recursionCount; --_recursionCount;
@@ -263,7 +185,7 @@
} }
var documentFrame = [documentView frame], // the size of the whole document var documentFrame = [documentView frame], // the size of the whole document
contentFrame = [self _insetBounds], // assume it takes up the entire size of the scrollview (no scrollers) contentFrame = [self bounds], // assume it takes up the entire size of the scrollview (no scrollers)
headerClipViewFrame = [self _headerClipViewFrame], headerClipViewFrame = [self _headerClipViewFrame],
headerClipViewHeight = _CGRectGetHeight(headerClipViewFrame); headerClipViewHeight = _CGRectGetHeight(headerClipViewFrame);
@@ -313,10 +235,11 @@
if (shouldShowVerticalScroller) if (shouldShowVerticalScroller)
{ {
var verticalScrollerY = var verticalScrollerY = MAX(_CGRectGetHeight([self _cornerViewFrame]), headerClipViewHeight),
MAX(_CGRectGetMinY(contentFrame), MAX(_CGRectGetMaxY([self _cornerViewFrame]), _CGRectGetMaxY(headerClipViewFrame))); verticalScrollerHeight = _CGRectGetHeight([self bounds]) - verticalScrollerY;
var verticalScrollerHeight = _CGRectGetMaxY(contentFrame) - verticalScrollerY; if (shouldShowHorizontalScroller)
verticalScrollerHeight -= horizontalScrollerHeight;
[_verticalScroller setFloatValue:(difference.height <= 0.0) ? 0.0 : scrollPoint.y / difference.height]; [_verticalScroller setFloatValue:(difference.height <= 0.0) ? 0.0 : scrollPoint.y / difference.height];
[_verticalScroller setKnobProportion:_CGRectGetHeight(contentFrame) / _CGRectGetHeight(documentFrame)]; [_verticalScroller setKnobProportion:_CGRectGetHeight(contentFrame) / _CGRectGetHeight(documentFrame)];
@@ -327,12 +250,12 @@
[_verticalScroller setFloatValue:0.0]; [_verticalScroller setFloatValue:0.0];
[_verticalScroller setKnobProportion:1.0]; [_verticalScroller setKnobProportion:1.0];
} }
if (shouldShowHorizontalScroller) if (shouldShowHorizontalScroller)
{ {
[_horizontalScroller setFloatValue:(difference.width <= 0.0) ? 0.0 : scrollPoint.x / difference.width]; [_horizontalScroller setFloatValue:(difference.width <= 0.0) ? 0.0 : scrollPoint.x / difference.width];
[_horizontalScroller setKnobProportion:_CGRectGetWidth(contentFrame) / _CGRectGetWidth(documentFrame)]; [_horizontalScroller setKnobProportion:_CGRectGetWidth(contentFrame) / _CGRectGetWidth(documentFrame)];
[_horizontalScroller setFrame:_CGRectMake(_CGRectGetMinX(contentFrame), _CGRectGetMaxY(contentFrame), _CGRectGetWidth(contentFrame), horizontalScrollerHeight)]; [_horizontalScroller setFrame:_CGRectMake(0.0, _CGRectGetMaxY(contentFrame), _CGRectGetWidth(contentFrame), horizontalScrollerHeight)];
} }
else if (wasShowingHorizontalScroller) else if (wasShowingHorizontalScroller)
{ {
@@ -344,36 +267,9 @@
[_headerClipView setFrame:headerClipViewFrame]; [_headerClipView setFrame:headerClipViewFrame];
[_cornerView setFrame:[self _cornerViewFrame]]; [_cornerView setFrame:[self _cornerViewFrame]];
[[self bottomCornerView] setFrame:[self _bottomCornerViewFrame]];
[[self bottomCornerView] setBackgroundColor:[self currentValueForThemeAttribute:@"bottom-corner-color"]];
--_recursionCount; --_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 // Managing Scrollers
/*! /*!
Sets the scroll view's horizontal scroller. Sets the scroll view's horizontal scroller.
@@ -383,13 +279,13 @@
{ {
if (_horizontalScroller === aScroller) if (_horizontalScroller === aScroller)
return; return;
[_horizontalScroller removeFromSuperview]; [_horizontalScroller removeFromSuperview];
[_horizontalScroller setTarget:nil]; [_horizontalScroller setTarget:nil];
[_horizontalScroller setAction:nil]; [_horizontalScroller setAction:nil];
_horizontalScroller = aScroller; _horizontalScroller = aScroller;
[_horizontalScroller setTarget:self]; [_horizontalScroller setTarget:self];
[_horizontalScroller setAction:@selector(_horizontalScrollerDidScroll:)]; [_horizontalScroller setAction:@selector(_horizontalScrollerDidScroll:)];
@@ -420,10 +316,8 @@
if (_hasHorizontalScroller && !_horizontalScroller) if (_hasHorizontalScroller && !_horizontalScroller)
{ {
var bounds = [self _insetBounds]; [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])];
[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]; [self reflectScrolledClipView:_contentView];
@@ -445,13 +339,13 @@
{ {
if (_verticalScroller === aScroller) if (_verticalScroller === aScroller)
return; return;
[_verticalScroller removeFromSuperview]; [_verticalScroller removeFromSuperview];
[_verticalScroller setTarget:nil]; [_verticalScroller setTarget:nil];
[_verticalScroller setAction:nil]; [_verticalScroller setAction:nil];
_verticalScroller = aScroller; _verticalScroller = aScroller;
[_verticalScroller setTarget:self]; [_verticalScroller setTarget:self];
[_verticalScroller setAction:@selector(_verticalScrollerDidScroll:)]; [_verticalScroller setAction:@selector(_verticalScrollerDidScroll:)];
@@ -483,10 +377,8 @@
if (_hasVerticalScroller && !_verticalScroller) if (_hasVerticalScroller && !_verticalScroller)
{ {
var bounds = [self _insetBounds]; [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]))];
[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]; [self reflectScrolledClipView:_contentView];
@@ -511,7 +403,7 @@
return; return;
_autohidesScrollers = autohidesScrollers; _autohidesScrollers = autohidesScrollers;
[self reflectScrolledClipView:_contentView]; [self reflectScrolledClipView:_contentView];
} }
@@ -553,7 +445,9 @@
- (CPView)_headerView - (CPView)_headerView
{ {
return [_headerClipView documentView]; var headerClipViewSubviews = [_headerClipView subviews];
return [headerClipViewSubviews count] ? headerClipViewSubviews[0] : nil;
} }
- (CGRect)_cornerViewFrame - (CGRect)_cornerViewFrame
@@ -561,11 +455,11 @@
if (!_cornerView) if (!_cornerView)
return _CGRectMakeZero(); return _CGRectMakeZero();
var bounds = [self _insetBounds], var bounds = [self bounds],
frame = [_cornerView frame]; frame = [_cornerView frame];
frame.origin.x = _CGRectGetMaxX(bounds) - _CGRectGetWidth(frame); frame.origin.x = _CGRectGetMaxX(bounds) - _CGRectGetWidth(frame);
frame.origin.y = _CGRectGetMinY(bounds); frame.origin.y = 0;
return frame; return frame;
} }
@@ -577,7 +471,7 @@
if (!headerView) if (!headerView)
return _CGRectMakeZero(); return _CGRectMakeZero();
var frame = [self _insetBounds]; var frame = [self bounds];
frame.size.height = _CGRectGetHeight([headerView frame]); frame.size.height = _CGRectGetHeight([headerView frame]);
frame.size.width -= _CGRectGetWidth([self _cornerViewFrame]); frame.size.width -= _CGRectGetWidth([self _cornerViewFrame]);
@@ -585,69 +479,33 @@
return frame; 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 */ /* @ignore */
- (void)_verticalScrollerDidScroll:(CPScroller)aScroller - (void)_verticalScrollerDidScroll:(CPScroller)aScroller
{ {
var value = [aScroller floatValue], var value = [aScroller floatValue],
documentFrame = [[_contentView documentView] frame], documentFrame = [[_contentView documentView] frame];
contentBounds = [_contentView bounds]; contentBounds = [_contentView bounds];
switch ([_verticalScroller hitPart]) switch ([_verticalScroller hitPart])
{ {
case CPScrollerDecrementLine: contentBounds.origin.y -= _verticalLineScroll; case CPScrollerDecrementLine: contentBounds.origin.y -= _verticalLineScroll;
break; break;
case CPScrollerIncrementLine: contentBounds.origin.y += _verticalLineScroll; case CPScrollerIncrementLine: contentBounds.origin.y += _verticalLineScroll;
break; break;
case CPScrollerDecrementPage: contentBounds.origin.y -= _CGRectGetHeight(contentBounds) - _verticalPageScroll; case CPScrollerDecrementPage: contentBounds.origin.y -= _CGRectGetHeight(contentBounds) - _verticalPageScroll;
break; break;
case CPScrollerIncrementPage: contentBounds.origin.y += _CGRectGetHeight(contentBounds) - _verticalPageScroll; case CPScrollerIncrementPage: contentBounds.origin.y += _CGRectGetHeight(contentBounds) - _verticalPageScroll;
break; break;
case CPScrollerKnobSlot: case CPScrollerKnobSlot:
case CPScrollerKnob: case CPScrollerKnob:
// We want integral bounds! // We want integral bounds!
default: contentBounds.origin.y = ROUND(value * (_CGRectGetHeight(documentFrame) - _CGRectGetHeight(contentBounds))); default: contentBounds.origin.y = ROUND(value * (_CGRectGetHeight(documentFrame) - _CGRectGetHeight(contentBounds)));
} }
[_contentView scrollToPoint:contentBounds.origin]; [_contentView scrollToPoint:contentBounds.origin];
} }
@@ -657,21 +515,21 @@
var value = [aScroller floatValue], var value = [aScroller floatValue],
documentFrame = [[self documentView] frame], documentFrame = [[self documentView] frame],
contentBounds = [_contentView bounds]; contentBounds = [_contentView bounds];
switch ([_horizontalScroller hitPart]) switch ([_horizontalScroller hitPart])
{ {
case CPScrollerDecrementLine: contentBounds.origin.x -= _horizontalLineScroll; case CPScrollerDecrementLine: contentBounds.origin.x -= _horizontalLineScroll;
break; break;
case CPScrollerIncrementLine: contentBounds.origin.x += _horizontalLineScroll; case CPScrollerIncrementLine: contentBounds.origin.x += _horizontalLineScroll;
break; break;
case CPScrollerDecrementPage: contentBounds.origin.x -= _CGRectGetWidth(contentBounds) - _horizontalPageScroll; case CPScrollerDecrementPage: contentBounds.origin.x -= _CGRectGetWidth(contentBounds) - _horizontalPageScroll;
break; break;
case CPScrollerIncrementPage: contentBounds.origin.x += _CGRectGetWidth(contentBounds) - _horizontalPageScroll; case CPScrollerIncrementPage: contentBounds.origin.x += _CGRectGetWidth(contentBounds) - _horizontalPageScroll;
break; break;
case CPScrollerKnobSlot: case CPScrollerKnobSlot:
case CPScrollerKnob: case CPScrollerKnob:
// We want integral bounds! // We want integral bounds!
@@ -696,7 +554,7 @@
/* /*
@ignore @ignore
*/ */
- (void)resizeSubviewsWithOldSize:(CGSize)aSize -(void)resizeSubviewsWithOldSize:(CGSize)aSize
{ {
[self reflectScrolledClipView:_contentView]; [self reflectScrolledClipView:_contentView];
} }
@@ -806,169 +664,35 @@
return _verticalPageScroll; 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. Handles a scroll wheel event from the user.
@param anEvent the scroll wheel event @param anEvent the scroll wheel event
*/ */
- (void)scrollWheel:(CPEvent)anEvent - (void)scrollWheel:(CPEvent)anEvent
{ {
[self _respondToScrollWheelEventWithDeltaX:[anEvent deltaX] deltaY:[anEvent deltaY]]; var documentFrame = [[self documentView] frame],
} contentBounds = [_contentView bounds];
- (void)_respondToScrollWheelEventWithDeltaX:(float)deltaX deltaY:(float)deltaY
{
var documentFrame = [[self documentView] frame],
contentBounds = [_contentView bounds],
contentFrame = [_contentView frame],
enclosingScrollView = [self enclosingScrollView];
// We want integral bounds! // We want integral bounds!
contentBounds.origin.x = ROUND(contentBounds.origin.x + deltaX); contentBounds.origin.x = ROUND(contentBounds.origin.x + [anEvent deltaX] * _horizontalLineScroll);
contentBounds.origin.y = ROUND(contentBounds.origin.y + deltaY); contentBounds.origin.y = ROUND(contentBounds.origin.y + [anEvent deltaY] * _verticalLineScroll);
var constrainedOrigin = [_contentView constrainScrollPoint:CGPointCreateCopy(contentBounds.origin)], [_contentView scrollToPoint:contentBounds.origin];
extraX = contentBounds.origin.x - constrainedOrigin.x, [_headerClipView scrollToPoint:CGPointMake(contentBounds.origin.x, 0.0)];
extraY = contentBounds.origin.y - constrainedOrigin.y;
[_contentView scrollToPoint:constrainedOrigin];
[_headerClipView scrollToPoint:CGPointMake(constrainedOrigin.x, 0.0)];
if (extraX || extraY)
[enclosingScrollView _respondToScrollWheelEventWithDeltaX:extraX deltaY:extraY];
} }
- (void)scrollPageUp:(id)sender - (void)keyDown:(CPEvent)anEvent
{
[self interpretKeyEvents:[anEvent]];
}
- (void)pageUp:(id)sender
{ {
var contentBounds = [_contentView bounds]; var contentBounds = [_contentView bounds];
[self moveByOffset:CGSizeMake(0.0, -(_CGRectGetHeight(contentBounds) - _verticalPageScroll))]; [self moveByOffset:CGSizeMake(0.0, -(_CGRectGetHeight(contentBounds) - _verticalPageScroll))];
} }
- (void)scrollPageDown:(id)sender - (void)pageDown:(id)sender
{ {
var contentBounds = [_contentView bounds]; var contentBounds = [_contentView bounds];
[self moveByOffset:CGSizeMake(0.0, _CGRectGetHeight(contentBounds) - _verticalPageScroll)]; [self moveByOffset:CGSizeMake(0.0, _CGRectGetHeight(contentBounds) - _verticalPageScroll)];
@@ -1008,20 +732,18 @@
@end @end
var CPScrollViewContentViewKey = @"CPScrollViewContentView", var CPScrollViewContentViewKey = "CPScrollViewContentView",
CPScrollViewHeaderClipViewKey = @"CPScrollViewHeaderClipViewKey", CPScrollViewHeaderClipViewKey = "CPScrollViewHeaderClipViewKey",
CPScrollViewVLineScrollKey = @"CPScrollViewVLineScroll", CPScrollViewVLineScrollKey = "CPScrollViewVLineScroll",
CPScrollViewHLineScrollKey = @"CPScrollViewHLineScroll", CPScrollViewHLineScrollKey = "CPScrollViewHLineScroll",
CPScrollViewVPageScrollKey = @"CPScrollViewVPageScroll", CPScrollViewVPageScrollKey = "CPScrollViewVPageScroll",
CPScrollViewHPageScrollKey = @"CPScrollViewHPageScroll", CPScrollViewHPageScrollKey = "CPScrollViewHPageScroll",
CPScrollViewHasVScrollerKey = @"CPScrollViewHasVScroller", CPScrollViewHasVScrollerKey = "CPScrollViewHasVScroller",
CPScrollViewHasHScrollerKey = @"CPScrollViewHasHScroller", CPScrollViewHasHScrollerKey = "CPScrollViewHasHScroller",
CPScrollViewVScrollerKey = @"CPScrollViewVScroller", CPScrollViewVScrollerKey = "CPScrollViewVScroller",
CPScrollViewHScrollerKey = @"CPScrollViewHScroller", CPScrollViewHScrollerKey = "CPScrollViewHScroller",
CPScrollViewAutohidesScrollerKey = @"CPScrollViewAutohidesScroller", CPScrollViewAutohidesScrollerKey = "CPScrollViewAutohidesScroller",
CPScrollViewCornerViewKey = @"CPScrollViewCornerViewKey", CPScrollViewCornerViewKey = "CPScrollViewCornerViewKey";
CPScrollViewBottomCornerViewKey = @"CPScrollViewBottomCornerViewKey",
CPScrollViewBorderTypeKey = @"CPScrollViewBorderTypeKey";
@implementation CPScrollView (CPCoding) @implementation CPScrollView (CPCoding)
@@ -1034,16 +756,10 @@ var CPScrollViewContentViewKey = @"CPScrollViewContentView",
_horizontalLineScroll = [aCoder decodeFloatForKey:CPScrollViewHLineScrollKey]; _horizontalLineScroll = [aCoder decodeFloatForKey:CPScrollViewHLineScrollKey];
_horizontalPageScroll = [aCoder decodeFloatForKey:CPScrollViewHPageScrollKey]; _horizontalPageScroll = [aCoder decodeFloatForKey:CPScrollViewHPageScrollKey];
_contentView = [aCoder decodeObjectForKey:CPScrollViewContentViewKey]; _contentView = [aCoder decodeObjectForKey:CPScrollViewContentViewKey];
_headerClipView = [aCoder decodeObjectForKey:CPScrollViewHeaderClipViewKey]; _headerClipView = [aCoder decodeObjectForKey:CPScrollViewHeaderClipViewKey];
if (!_headerClipView)
{
_headerClipView = [[CPClipView alloc] init];
[self addSubview:_headerClipView];
}
_verticalScroller = [aCoder decodeObjectForKey:CPScrollViewVScrollerKey]; _verticalScroller = [aCoder decodeObjectForKey:CPScrollViewVScrollerKey];
_horizontalScroller = [aCoder decodeObjectForKey:CPScrollViewHScrollerKey]; _horizontalScroller = [aCoder decodeObjectForKey:CPScrollViewHScrollerKey];
@@ -1051,41 +767,35 @@ var CPScrollViewContentViewKey = @"CPScrollViewContentView",
_hasHorizontalScroller = [aCoder decodeBoolForKey:CPScrollViewHasHScrollerKey]; _hasHorizontalScroller = [aCoder decodeBoolForKey:CPScrollViewHasHScrollerKey];
_autohidesScrollers = [aCoder decodeBoolForKey:CPScrollViewAutohidesScrollerKey]; _autohidesScrollers = [aCoder decodeBoolForKey:CPScrollViewAutohidesScrollerKey];
_borderType = [aCoder decodeIntForKey:CPScrollViewBorderTypeKey];
_cornerView = [aCoder decodeObjectForKey:CPScrollViewCornerViewKey]; _cornerView = [aCoder decodeObjectForKey:CPScrollViewCornerViewKey];
_bottomCornerView = [aCoder decodeObjectForKey:CPScrollViewBottomCornerViewKey];
// 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. // 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.
[[CPRunLoop currentRunLoop] performSelector:@selector(reflectScrolledClipView:) target:self argument:_contentView order:0 modes:[CPDefaultRunLoopMode]]; [[CPRunLoop currentRunLoop] performSelector:@selector(reflectScrolledClipView:) target:self argument:_contentView order:0 modes:[CPDefaultRunLoopMode]];
} }
return self; return self;
} }
- (void)encodeWithCoder:(CPCoder)aCoder - (void)encodeWithCoder:(CPCoder)aCoder
{ {
[super encodeWithCoder:aCoder]; [super encodeWithCoder:aCoder];
[aCoder encodeObject:_contentView forKey:CPScrollViewContentViewKey]; [aCoder encodeObject:_contentView forKey:CPScrollViewContentViewKey];
[aCoder encodeObject:_headerClipView forKey:CPScrollViewHeaderClipViewKey]; [aCoder encodeObject:_headerClipView forKey:CPScrollViewHeaderClipViewKey];
[aCoder encodeObject:_verticalScroller forKey:CPScrollViewVScrollerKey]; [aCoder encodeObject:_verticalScroller forKey:CPScrollViewVScrollerKey];
[aCoder encodeObject:_horizontalScroller forKey:CPScrollViewHScrollerKey]; [aCoder encodeObject:_horizontalScroller forKey:CPScrollViewHScrollerKey];
[aCoder encodeFloat:_verticalLineScroll forKey:CPScrollViewVLineScrollKey]; [aCoder encodeFloat:_verticalLineScroll forKey:CPScrollViewVLineScrollKey];
[aCoder encodeFloat:_verticalPageScroll forKey:CPScrollViewVPageScrollKey]; [aCoder encodeFloat:_verticalPageScroll forKey:CPScrollViewVPageScrollKey];
[aCoder encodeFloat:_horizontalLineScroll forKey:CPScrollViewHLineScrollKey]; [aCoder encodeFloat:_horizontalLineScroll forKey:CPScrollViewHLineScrollKey];
[aCoder encodeFloat:_horizontalPageScroll forKey:CPScrollViewHPageScrollKey]; [aCoder encodeFloat:_horizontalPageScroll forKey:CPScrollViewHPageScrollKey];
[aCoder encodeBool:_hasVerticalScroller forKey:CPScrollViewHasVScrollerKey]; [aCoder encodeBool:_hasVerticalScroller forKey:CPScrollViewHasVScrollerKey];
[aCoder encodeBool:_hasHorizontalScroller forKey:CPScrollViewHasHScrollerKey]; [aCoder encodeBool:_hasHorizontalScroller forKey:CPScrollViewHasHScrollerKey];
[aCoder encodeBool:_autohidesScrollers forKey:CPScrollViewAutohidesScrollerKey]; [aCoder encodeBool:_autohidesScrollers forKey:CPScrollViewAutohidesScrollerKey];
[aCoder encodeObject:_cornerView forKey:CPScrollViewCornerViewKey]; [aCoder encodeObject:_cornerView forKey:CPScrollViewCornerViewKey];
[aCoder encodeObject:_bottomCornerView forKey:CPScrollViewBottomCornerViewKey];
[aCoder encodeInt:_borderType forKey:CPScrollViewBorderTypeKey];
} }
@end @end
+81 -93
View File
@@ -22,6 +22,8 @@
@import "CPControl.j" @import "CPControl.j"
#include "CoreGraphics/CGGeometry.h"
// CPScroller Constants // CPScroller Constants
CPScrollerNoPart = 0; CPScrollerNoPart = 0;
@@ -39,9 +41,9 @@ CPNoScrollerParts = 0;
CPOnlyScrollerArrows = 1; CPOnlyScrollerArrows = 1;
CPAllScrollerParts = 2; CPAllScrollerParts = 2;
/*! /*!
@ingroup appkit @ingroup appkit
@class CPScroller @class CPScroller
*/ */
var PARTS_ARRANGEMENT = [CPScrollerKnobSlot, CPScrollerDecrementLine, CPScrollerIncrementLine, CPScrollerKnob], var PARTS_ARRANGEMENT = [CPScrollerKnobSlot, CPScrollerDecrementLine, CPScrollerIncrementLine, CPScrollerKnob],
@@ -70,25 +72,24 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
CGPoint _trackingStartPoint; CGPoint _trackingStartPoint;
} }
+ (CPString)defaultThemeClass + (CPString)themeClass
{ {
return "scroller"; return "scroller";
} }
+ (id)themeAttributes + (id)themeAttributes
{ {
return [CPDictionary dictionaryWithJSObject:{ return [CPDictionary dictionaryWithObjects:[ [CPNull null], [CPNull null], [CPNull null], [CPNull null],
@"scroller-width": 15.0, _CGSizeMakeZero(), _CGSizeMakeZero(), _CGInsetMakeZero(), _CGInsetMakeZero(), _CGSizeMakeZero()]
@"knob-slot-color": [CPColor lightGrayColor], forKeys:[ @"knob-slot-color",
@"decrement-line-color": [CPNull null], @"decrement-line-color",
@"increment-line-color": [CPNull null], @"increment-line-color",
@"knob-color": [CPColor grayColor], @"knob-color",
@"decrement-line-size":_CGSizeMakeZero(), @"decrement-line-size",
@"increment-line-size":_CGSizeMakeZero(), @"increment-line-size",
@"track-inset":_CGInsetMakeZero(), @"track-inset",
@"knob-inset": _CGInsetMakeZero(), @"knob-inset",
@"minimum-knob-length":21.0 @"minimum-knob-length"]];
}]
} }
@@ -97,7 +98,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
- (id)initWithFrame:(CGRect)aFrame - (id)initWithFrame:(CGRect)aFrame
{ {
self = [super initWithFrame:aFrame]; self = [super initWithFrame:aFrame];
if (self) if (self)
{ {
_controlSize = CPRegularControlSize; _controlSize = CPRegularControlSize;
@@ -105,7 +106,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
[self setFloatValue:0.0]; [self setFloatValue:0.0];
[self setKnobProportion:1.0]; [self setKnobProportion:1.0];
_hitPart = CPScrollerNoPart; _hitPart = CPScrollerNoPart;
[self _calculateIsVertical]; [self _calculateIsVertical];
@@ -120,7 +121,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
*/ */
+ (float)scrollerWidth + (float)scrollerWidth
{ {
return [[[CPScroller alloc] init] currentValueForThemeAttribute:@"scroller-width"]; return 15.0;//[self scrollerWidthForControlSize:CPRegularControlSize];
} }
/*! /*!
@@ -129,7 +130,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
*/ */
+ (float)scrollerWidthForControlSize:(CPControlSize)aControlSize + (float)scrollerWidthForControlSize:(CPControlSize)aControlSize
{ {
return [self scrollerWidth]; return 15.0;//_CPScrollerWidths[aControlSize];
} }
/*! /*!
@@ -179,10 +180,10 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
- (id)currentValueForThemeAttribute:(CPString)anAttributeName - (id)currentValueForThemeAttribute:(CPString)anAttributeName
{ {
var themeState = _themeState; var themeState = _themeState;
if (NAMES_FOR_PARTS[_hitPart] + "-color" !== anAttributeName) if (NAMES_FOR_PARTS[_hitPart] + "-color" !== anAttributeName)
themeState &= ~CPThemeStateHighlighted; themeState &= ~CPThemeStateHighlighted;
return [self valueForThemeAttribute:anAttributeName inState:themeState]; return [self valueForThemeAttribute:anAttributeName inState:themeState];
} }
@@ -204,25 +205,25 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
- (CPScrollerPart)testPart:(CGPoint)aPoint - (CPScrollerPart)testPart:(CGPoint)aPoint
{ {
aPoint = [self convertPoint:aPoint fromView:nil]; 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. // page rects first since they may overlap with the arrows.
if (CGRectContainsPoint([self rectForPart:CPScrollerKnob], aPoint)) if (CGRectContainsPoint([self rectForPart:CPScrollerKnob], aPoint))
return CPScrollerKnob; return CPScrollerKnob;
if (CGRectContainsPoint([self rectForPart:CPScrollerDecrementPage], aPoint)) if (CGRectContainsPoint([self rectForPart:CPScrollerDecrementPage], aPoint))
return CPScrollerDecrementPage; return CPScrollerDecrementPage;
if (CGRectContainsPoint([self rectForPart:CPScrollerIncrementPage], aPoint)) if (CGRectContainsPoint([self rectForPart:CPScrollerIncrementPage], aPoint))
return CPScrollerIncrementPage; return CPScrollerIncrementPage;
if (CGRectContainsPoint([self rectForPart:CPScrollerDecrementLine], aPoint)) if (CGRectContainsPoint([self rectForPart:CPScrollerDecrementLine], aPoint))
return CPScrollerDecrementLine; return CPScrollerDecrementLine;
if (CGRectContainsPoint([self rectForPart:CPScrollerIncrementLine], aPoint)) if (CGRectContainsPoint([self rectForPart:CPScrollerIncrementLine], aPoint))
return CPScrollerIncrementLine; return CPScrollerIncrementLine;
if (CGRectContainsPoint([self rectForPart:CPScrollerKnobSlot], aPoint)) if (CGRectContainsPoint([self rectForPart:CPScrollerKnobSlot], aPoint))
return CPScrollerKnobSlot; return CPScrollerKnobSlot;
@@ -240,7 +241,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
if (_knobProportion === 1.0) if (_knobProportion === 1.0)
{ {
_usableParts = CPNoScrollerParts; _usableParts = CPNoScrollerParts;
_partRects[CPScrollerDecrementPage] = CGRectMakeZero(); _partRects[CPScrollerDecrementPage] = CGRectMakeZero();
_partRects[CPScrollerKnob] = CGRectMakeZero(); _partRects[CPScrollerKnob] = CGRectMakeZero();
_partRects[CPScrollerIncrementPage] = CGRectMakeZero(); _partRects[CPScrollerIncrementPage] = CGRectMakeZero();
@@ -249,7 +250,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
// In this case, the slot is the entirety of the scroller. // In this case, the slot is the entirety of the scroller.
_partRects[CPScrollerKnobSlot] = CGRectMakeCopy(bounds); _partRects[CPScrollerKnobSlot] = CGRectMakeCopy(bounds);
return; return;
} }
@@ -259,8 +260,8 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
var knobInset = [self currentValueForThemeAttribute:@"knob-inset"], var knobInset = [self currentValueForThemeAttribute:@"knob-inset"],
trackInset = [self currentValueForThemeAttribute:@"track-inset"], trackInset = [self currentValueForThemeAttribute:@"track-inset"],
width = _CGRectGetWidth(bounds), width = _CGRectGetWidth(bounds),
height = _CGRectGetHeight(bounds); height = _CGRectGetHeight(bounds);
if ([self isVertical]) if ([self isVertical])
{ {
var decrementLineSize = [self currentValueForThemeAttribute:"decrement-line-size"], var decrementLineSize = [self currentValueForThemeAttribute:"decrement-line-size"],
@@ -279,11 +280,11 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
_partRects[CPScrollerKnobSlot] = _CGRectMake(trackInset.left, effectiveDecrementLineHeight, width - trackInset.left - trackInset.right, slotHeight); _partRects[CPScrollerKnobSlot] = _CGRectMake(trackInset.left, effectiveDecrementLineHeight, width - trackInset.left - trackInset.right, slotHeight);
_partRects[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height); _partRects[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
_partRects[CPScrollerIncrementLine] = _CGRectMake(0.0, height - incrementLineSize.height, incrementLineSize.width, incrementLineSize.height); _partRects[CPScrollerIncrementLine] = _CGRectMake(0.0, height - incrementLineSize.height, incrementLineSize.width, incrementLineSize.height);
if (height < knobHeight + decrementLineSize.height + incrementLineSize.height + trackInset.top + trackInset.bottom) if(height < knobHeight + decrementLineSize.height + incrementLineSize.height + trackInset.top + trackInset.bottom)
_partRects[CPScrollerKnob] = _CGRectMakeZero(); _partRects[CPScrollerKnob] = _CGRectMakeZero();
if (height < decrementLineSize.height + incrementLineSize.height - 2) if(height < decrementLineSize.height + incrementLineSize.height - 2)
{ {
_partRects[CPScrollerIncrementLine] = _CGRectMakeZero(); _partRects[CPScrollerIncrementLine] = _CGRectMakeZero();
_partRects[CPScrollerDecrementLine] = _CGRectMakeZero(); _partRects[CPScrollerDecrementLine] = _CGRectMakeZero();
@@ -295,7 +296,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
var decrementLineSize = [self currentValueForThemeAttribute:"decrement-line-size"], var decrementLineSize = [self currentValueForThemeAttribute:"decrement-line-size"],
incrementLineSize = [self currentValueForThemeAttribute:"increment-line-size"], incrementLineSize = [self currentValueForThemeAttribute:"increment-line-size"],
effectiveDecrementLineWidth = decrementLineSize.width + trackInset.left, effectiveDecrementLineWidth = decrementLineSize.width + trackInset.left,
effectiveIncrementLineWidth = incrementLineSize.width + trackInset.right, effectiveIncrementLineWidth = incrementLineSize.width + trackInset.right;
slotWidth = width - effectiveDecrementLineWidth - effectiveIncrementLineWidth, slotWidth = width - effectiveDecrementLineWidth - effectiveIncrementLineWidth,
minimumKnobLength = [self currentValueForThemeAttribute:"minimum-knob-length"], minimumKnobLength = [self currentValueForThemeAttribute:"minimum-knob-length"],
knobWidth = MAX(minimumKnobLength, (slotWidth * _knobProportion)), knobWidth = MAX(minimumKnobLength, (slotWidth * _knobProportion)),
@@ -308,11 +309,11 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
_partRects[CPScrollerKnobSlot] = _CGRectMake(effectiveDecrementLineWidth, trackInset.top, slotWidth, height - trackInset.top - trackInset.bottom); _partRects[CPScrollerKnobSlot] = _CGRectMake(effectiveDecrementLineWidth, trackInset.top, slotWidth, height - trackInset.top - trackInset.bottom);
_partRects[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height); _partRects[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
_partRects[CPScrollerIncrementLine] = _CGRectMake(width - incrementLineSize.width, 0.0, incrementLineSize.width, incrementLineSize.height); _partRects[CPScrollerIncrementLine] = _CGRectMake(width - incrementLineSize.width, 0.0, incrementLineSize.width, incrementLineSize.height);
if (width < knobWidth + decrementLineSize.width + incrementLineSize.width + trackInset.left + trackInset.right) if(width < knobWidth + decrementLineSize.width + incrementLineSize.width + trackInset.left + trackInset.right)
_partRects[CPScrollerKnob] = _CGRectMakeZero(); _partRects[CPScrollerKnob] = _CGRectMakeZero();
if (width < decrementLineSize.width + incrementLineSize.width - 2) if(width < decrementLineSize.width + incrementLineSize.width - 2)
{ {
_partRects[CPScrollerIncrementLine] = _CGRectMakeZero(); _partRects[CPScrollerIncrementLine] = _CGRectMakeZero();
_partRects[CPScrollerDecrementLine] = _CGRectMakeZero(); _partRects[CPScrollerDecrementLine] = _CGRectMakeZero();
@@ -357,9 +358,9 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
- (CPView)createViewForPart:(CPScrollerPart)aPart - (CPView)createViewForPart:(CPScrollerPart)aPart
{ {
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()]; var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
[view setHitTests:NO]; [view setHitTests:NO];
return view; return view;
} }
@@ -373,7 +374,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()]; var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
[view setHitTests:NO]; [view setHitTests:NO];
return view; return view;
} }
@@ -387,12 +388,12 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
for (; index < count; ++index) for (; index < count; ++index)
{ {
var part = PARTS_ARRANGEMENT[index]; var part = PARTS_ARRANGEMENT[index];
if (index === 0) if (index === 0)
view = [self layoutEphemeralSubviewNamed:part positioned:CPWindowBelow relativeToEphemeralSubviewNamed:PARTS_ARRANGEMENT[index + 1]]; view = [self layoutEphemeralSubviewNamed:part positioned:CPWindowBelow relativeToEphemeralSubviewNamed:PARTS_ARRANGEMENT[index + 1]];
else else
view = [self layoutEphemeralSubviewNamed:part positioned:CPWindowAbove relativeToEphemeralSubviewNamed:PARTS_ARRANGEMENT[index - 1]]; view = [self layoutEphemeralSubviewNamed:part positioned:CPWindowAbove relativeToEphemeralSubviewNamed:PARTS_ARRANGEMENT[index - 1]];
if (view) if (view)
[view setBackgroundColor:[self currentValueForThemeAttribute:NAMES_FOR_PARTS[part] + "-color"]]; [view setBackgroundColor:[self currentValueForThemeAttribute:NAMES_FOR_PARTS[part] + "-color"]];
} }
@@ -402,7 +403,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
Caches images for the scroll arrow and knob. Caches images for the scroll arrow and knob.
*/ */
- (void)drawParts - (void)drawParts
{ {
[self drawKnobSlot]; [self drawKnobSlot];
[self drawKnob]; [self drawKnob];
[self drawArrow:CPScrollerDecrementArrow highlight:NO]; [self drawArrow:CPScrollerDecrementArrow highlight:NO];
@@ -425,37 +426,37 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
- (void)trackKnob:(CPEvent)anEvent - (void)trackKnob:(CPEvent)anEvent
{ {
var type = [anEvent type]; var type = [anEvent type];
if (type === CPLeftMouseUp) if (type === CPLeftMouseUp)
{ {
_hitPart = CPScrollerNoPart; _hitPart = CPScrollerNoPart;
return; return;
} }
if (type === CPLeftMouseDown) if (type === CPLeftMouseDown)
{ {
_trackingFloatValue = [self floatValue]; _trackingFloatValue = [self floatValue];
_trackingStartPoint = [self convertPoint:[anEvent locationInWindow] fromView:nil]; _trackingStartPoint = [self convertPoint:[anEvent locationInWindow] fromView:nil];
} }
else if (type === CPLeftMouseDragged) else if (type === CPLeftMouseDragged)
{ {
var knobRect = [self rectForPart:CPScrollerKnob], var knobRect = [self rectForPart:CPScrollerKnob],
knobSlotRect = [self rectForPart:CPScrollerKnobSlot], knobSlotRect = [self rectForPart:CPScrollerKnobSlot],
remainder = ![self isVertical] ? (_CGRectGetWidth(knobSlotRect) - _CGRectGetWidth(knobRect)) : (_CGRectGetHeight(knobSlotRect) - _CGRectGetHeight(knobRect)); remainder = ![self isVertical] ? (_CGRectGetWidth(knobSlotRect) - _CGRectGetWidth(knobRect)) : (_CGRectGetHeight(knobSlotRect) - _CGRectGetHeight(knobRect));
if (remainder <= 0) if (remainder <= 0)
[self setFloatValue:0.0]; [self setFloatValue:0.0];
else 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; delta = ![self isVertical] ? location.x - _trackingStartPoint.x : location.y - _trackingStartPoint.y;
[self setFloatValue:_trackingFloatValue + delta / remainder]; [self setFloatValue:_trackingFloatValue + delta / remainder];
} }
} }
[CPApp setTarget:self selector:@selector(trackKnob:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES]; [CPApp setTarget:self selector:@selector(trackKnob:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
[self sendAction:[self action] to:[self target]]; [self sendAction:[self action] to:[self target]];
@@ -473,26 +474,26 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
{ {
[self highlight:NO]; [self highlight:NO];
[CPEvent stopPeriodicEvents]; [CPEvent stopPeriodicEvents];
_hitPart = CPScrollerNoPart; _hitPart = CPScrollerNoPart;
return; return;
} }
if (type === CPLeftMouseDown) if (type === CPLeftMouseDown)
{ {
_trackingPart = [self hitPart]; _trackingPart = [self hitPart];
_trackingStartPoint = [self convertPoint:[anEvent locationInWindow] fromView:nil]; _trackingStartPoint = [self convertPoint:[anEvent locationInWindow] fromView:nil];
if ([anEvent modifierFlags] & CPAlternateKeyMask) if ([anEvent modifierFlags] & CPAlternateKeyMask)
{ {
if (_trackingPart == CPScrollerDecrementLine) if (_trackingPart == CPScrollerDecrementLine)
_hitPart = CPScrollerDecrementPage; _hitPart = CPScrollerDecrementPage;
else if (_trackingPart == CPScrollerIncrementLine) else if (_trackingPart == CPScrollerIncrementLine)
_hitPart = CPScrollerIncrementPage; _hitPart = CPScrollerIncrementPage;
else if (_trackingPart == CPScrollerDecrementPage || _trackingPart == CPScrollerIncrementPage) else if (_trackingPart == CPScrollerDecrementPage || _trackingPart == CPScrollerIncrementPage)
{ {
var knobRect = [self rectForPart:CPScrollerKnob], var knobRect = [self rectForPart:CPScrollerKnob],
@@ -501,42 +502,42 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
remainder = (![self isVertical] ? _CGRectGetWidth(knobSlotRect) : _CGRectGetHeight(knobSlotRect)) - knobWidth; remainder = (![self isVertical] ? _CGRectGetWidth(knobSlotRect) : _CGRectGetHeight(knobSlotRect)) - knobWidth;
[self setFloatValue:((![self isVertical] ? _trackingStartPoint.x - _CGRectGetMinX(knobSlotRect) : _trackingStartPoint.y - _CGRectGetMinY(knobSlotRect)) - knobWidth / 2.0) / remainder]; [self setFloatValue:((![self isVertical] ? _trackingStartPoint.x - _CGRectGetMinX(knobSlotRect) : _trackingStartPoint.y - _CGRectGetMinY(knobSlotRect)) - knobWidth / 2.0) / remainder];
_hitPart = CPScrollerKnob; _hitPart = CPScrollerKnob;
[self sendAction:[self action] to:[self target]]; [self sendAction:[self action] to:[self target]];
// Now just track the knob. // Now just track the knob.
return [self trackKnob:anEvent]; return [self trackKnob:anEvent];
} }
} }
[self highlight:YES]; [self highlight:YES];
[self sendAction:[self action] to:[self target]]; [self sendAction:[self action] to:[self target]];
[CPEvent startPeriodicEventsAfterDelay:0.5 withPeriod:0.04]; [CPEvent startPeriodicEventsAfterDelay:0.5 withPeriod:0.04];
} }
else if (type === CPLeftMouseDragged) else if (type === CPLeftMouseDragged)
{ {
_trackingStartPoint = [self convertPoint:[anEvent locationInWindow] fromView:nil]; _trackingStartPoint = [self convertPoint:[anEvent locationInWindow] fromView:nil];
if (_trackingPart == CPScrollerDecrementPage || _trackingPart == CPScrollerIncrementPage) if (_trackingPart == CPScrollerDecrementPage || _trackingPart == CPScrollerIncrementPage)
{ {
var hitPart = [self testPart:[anEvent locationInWindow]]; var hitPart = [self testPart:[anEvent locationInWindow]];
if (hitPart == CPScrollerDecrementPage || hitPart == CPScrollerIncrementPage) if (hitPart == CPScrollerDecrementPage || hitPart == CPScrollerIncrementPage)
{ {
_trackingPart = hitPart; _trackingPart = hitPart;
_hitPart = hitPart; _hitPart = hitPart;
} }
} }
[self highlight:CGRectContainsPoint([self rectForPart:_trackingPart], _trackingStartPoint)]; [self highlight:CGRectContainsPoint([self rectForPart:_trackingPart], _trackingStartPoint)];
} }
else if (type == CPPeriodic && CGRectContainsPoint([self rectForPart:_trackingPart], _trackingStartPoint)) else if (type == CPPeriodic && CGRectContainsPoint([self rectForPart:_trackingPart], _trackingStartPoint))
[self sendAction:[self action] to:[self target]]; [self sendAction:[self action] to:[self target]];
[CPApp setTarget:self selector:@selector(trackScrollButtons:) forNextEventMatchingMask:CPPeriodicMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES]; [CPApp setTarget:self selector:@selector(trackScrollButtons:) forNextEventMatchingMask:CPPeriodicMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
} }
@@ -568,15 +569,15 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
{ {
if (![self isEnabled]) if (![self isEnabled])
return; return;
_hitPart = [self testPart:[anEvent locationInWindow]]; _hitPart = [self testPart:[anEvent locationInWindow]];
switch (_hitPart) switch (_hitPart)
{ {
case CPScrollerKnob: return [self trackKnob:anEvent]; case CPScrollerKnob: return [self trackKnob:anEvent];
case CPScrollerDecrementLine: case CPScrollerDecrementLine:
case CPScrollerIncrementLine: case CPScrollerIncrementLine:
case CPScrollerDecrementPage: case CPScrollerDecrementPage:
case CPScrollerIncrementPage: return [self trackScrollButtons:anEvent]; case CPScrollerIncrementPage: return [self trackScrollButtons:anEvent];
} }
@@ -602,32 +603,19 @@ var CPScrollerControlSizeKey = "CPScrollerControlSize",
_knobProportion = [aCoder decodeFloatForKey:CPScrollerKnobProportionKey]; _knobProportion = [aCoder decodeFloatForKey:CPScrollerKnobProportionKey];
_partRects = []; _partRects = [];
_hitPart = CPScrollerNoPart; _hitPart = CPScrollerNoPart;
[self _calculateIsVertical]; [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; return self;
} }
- (void)encodeWithCoder:(CPCoder)aCoder - (void)encodeWithCoder:(CPCoder)aCoder
{ {
[super encodeWithCoder:aCoder]; [super encodeWithCoder:aCoder];
[aCoder encodeInt:_controlSize forKey:CPScrollerControlSizeKey]; [aCoder encodeInt:_controlSize forKey:CPScrollerControlSizeKey];
[aCoder encodeFloat:_knobProportion forKey:CPScrollerKnobProportionKey]; [aCoder encodeFloat:_knobProportion forKey:CPScrollerKnobProportionKey];
} }
+135 -238
View File
@@ -20,28 +20,20 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
@import "CPButton.j"
@import "CPTextField.j" @import "CPTextField.j"
#include "Platform/Platform.h"
CPSearchFieldRecentsTitleMenuItemTag = 1000; CPSearchFieldRecentsTitleMenuItemTag = 1000;
CPSearchFieldRecentsMenuItemTag = 1001; CPSearchFieldRecentsMenuItemTag = 1001;
CPSearchFieldClearRecentsMenuItemTag = 1002; CPSearchFieldClearRecentsMenuItemTag = 1002;
CPSearchFieldNoRecentsMenuItemTag = 1003; CPSearchFieldNoRecentsMenuItemTag = 1003;
CPSearchFieldSeparatorMenuItemTag = 1004;
var CPSearchFieldSearchImage = nil, var CPSearchFieldSearchImage = nil,
CPSearchFieldFindImage = nil, CPSearchFieldFindImage = nil,
CPSearchFieldCancelImage = nil, CPSearchFieldCancelImage = nil,
CPSearchFieldCancelPressedImage = 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 @ingroup appkit
@class CPSearchField @class CPSearchField
@@ -62,37 +54,32 @@ var RECENT_SEARCH_PREFIX = @" ";
int _maximumRecents; int _maximumRecents;
BOOL _sendsWholeSearchString; BOOL _sendsWholeSearchString;
BOOL _sendsSearchStringImmediately; BOOL _sendsSearchStringImmediately;
BOOL _canResignFirstResponder;
CPTimer _partialStringTimer; CPTimer _partialStringTimer;
} }
+ (CPString)defaultThemeClass
{
return @"searchfield"
}
+ (void)initialize + (void)initialize
{ {
if (self != [CPSearchField class]) if (self != [CPSearchField class])
return; return;
var bundle = [CPBundle bundleForClass:self]; var bundle = [CPBundle bundleForClass:self];
CPSearchFieldSearchImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldSearch.png"] size:_CGSizeMake(SEARCH_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)]; CPSearchFieldSearchImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldSearch.png"] size:CGSizeMake(25, 22)];
CPSearchFieldFindImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldFind.png"] size:_CGSizeMake(SEARCH_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)]; CPSearchFieldFindImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldFind.png"] size:CGSizeMake(25, 22)];
CPSearchFieldCancelImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancel.png"] size:_CGSizeMake(CANCEL_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)]; CPSearchFieldCancelImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancel.png"] size:CGSizeMake(22, 22)];
CPSearchFieldCancelPressedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancelPressed.png"] size:_CGSizeMake(CANCEL_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)]; CPSearchFieldCancelPressedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancelPressed.png"] size:CGSizeMake(22, 22)];
} }
- (id)initWithFrame:(CGRect)frame - (id)initWithFrame:(CGRect)frame
{ {
if (self = [super initWithFrame:frame]) if (self = [super initWithFrame:frame])
{ {
_recentSearches = [CPArray array];
_maximumRecents = 10; _maximumRecents = 10;
_sendsWholeSearchString = NO; _sendsWholeSearchString = NO;
_sendsSearchStringImmediately = NO; _sendsSearchStringImmediately = NO;
_recentsAutosaveName = nil; _recentsAutosaveName = nil;
[self _init]; [self _initWithFrame:frame];
#if PLATFORM(DOM) #if PLATFORM(DOM)
_cancelButton._DOMElement.style.cursor = "default"; _cancelButton._DOMElement.style.cursor = "default";
_searchButton._DOMElement.style.cursor = "default"; _searchButton._DOMElement.style.cursor = "default";
@@ -102,28 +89,23 @@ var RECENT_SEARCH_PREFIX = @" ";
return self; return self;
} }
- (void)_init - (void)_initWithFrame:(CGRect)frame
{ {
_recentSearches = [CPArray array];
[self setBezeled:YES]; [self setBezeled:YES];
[self setBezelStyle:CPTextFieldRoundedBezel]; [self setBezelStyle:CPTextFieldRoundedBezel];
[self setBordered:YES]; [self setBordered:YES];
[self setEditable:YES]; [self setEditable:YES];
[self setDelegate:self]; [self setDelegate:self];
[self setContinuous:YES];
var bounds = [self bounds], _cancelButton = [[CPButton alloc] initWithFrame:CGRectMake(frame.size.width - 27,(frame.size.height-22)/2,22,22)];
cancelButton = [[CPButton alloc] initWithFrame:[self cancelButtonRectForBounds:bounds]],
searchButton = [[CPButton alloc] initWithFrame:[self searchButtonRectForBounds:bounds]];
[self setCancelButton:cancelButton];
[self resetCancelButton]; [self resetCancelButton];
[_cancelButton setHidden:YES];
[_cancelButton setAutoresizingMask:CPViewMinXMargin];
[self addSubview:_cancelButton];
[self setSearchButton:searchButton]; _searchButton = [[CPButton alloc] initWithFrame:CGRectMake(5,(frame.size.height-25)/2,25,25)];
[self resetSearchButton]; [self resetSearchButton];
[self addSubview:_searchButton];
_canResignFirstResponder = YES;
} }
// Managing Buttons // Managing Buttons
@@ -133,15 +115,7 @@ var RECENT_SEARCH_PREFIX = @" ";
*/ */
- (void)setSearchButton:(CPButton)button - (void)setSearchButton:(CPButton)button
{ {
if (button != _searchButton) _searchButton = button;
{
[_searchButton removeFromSuperview];
_searchButton = button;
[_searchButton setFrame:[self searchButtonRectForBounds:[self bounds]]];
[_searchButton setAutoresizingMask:CPViewMaxXMargin];
[self addSubview:_searchButton];
}
} }
/*! /*!
@@ -159,13 +133,30 @@ var RECENT_SEARCH_PREFIX = @" ";
*/ */
- (void)resetSearchButton - (void)resetSearchButton
{ {
var button = [self searchButton], var searchButtonImage,
searchButtonImage = (_searchMenuTemplate === nil) ? CPSearchFieldSearchImage : CPSearchFieldFindImage; action,
target,
button = [self searchButton];
if (_searchMenuTemplate === nil)
{
searchButtonImage = CPSearchFieldSearchImage;
action = @selector(_sendAction:);
target = self;
}
else
{
searchButtonImage = CPSearchFieldFindImage;
action = @selector(_showMenu:);
target = self;
}
[button setBordered:NO]; [button setBordered:NO];
[button setImageScaling:CPScaleToFit]; [button setImageScaling:CPScaleToFit];
[button setImage:searchButtonImage]; [button setImage:searchButtonImage];
[button setAutoresizingMask:CPViewMaxXMargin]; [button setAutoresizingMask:CPViewMaxXMargin];
[button setTarget:target];
[button setAction:action];
} }
/*! /*!
@@ -174,18 +165,7 @@ var RECENT_SEARCH_PREFIX = @" ";
*/ */
- (void)setCancelButton:(CPButton)button - (void)setCancelButton:(CPButton)button
{ {
if (button != _cancelButton) _cancelButton = button;
{
[_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];
}
} }
/*! /*!
@@ -220,25 +200,23 @@ var RECENT_SEARCH_PREFIX = @" ";
@return The updated bounding rectangle to use for the search text field. The default value is the value passed into the rect parameter. @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. 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.
*/ */
- (CGRect)searchTextRectForBounds:(CGRect)rect - (CPRect)searchTextRectForBounds:(CPRect)rect
{ {
var leftOffset = 0, var leftOffset = 0, width = rect.size.width;
width = _CGRectGetWidth(rect),
bounds = [self bounds];
if (_searchButton) if (_searchButton)
{ {
var searchBounds = [self searchButtonRectForBounds:bounds]; var searchRect = [_searchButton frame];
leftOffset = _CGRectGetMaxX(searchBounds) + 2; leftOffset = searchRect.origin.x + searchRect.size.width;
} }
if (_cancelButton) if (_cancelButton)
{ {
var cancelRect = [self cancelButtonRectForBounds:bounds]; var cancelRect = [_cancelButton frame];
width = _CGRectGetMinX(cancelRect) - leftOffset; width = cancelRect.origin.x - leftOffset;
} }
return _CGRectMake(leftOffset, _CGRectGetMinY(rect), width, _CGRectGetHeight(rect)); return CPMakeRect(leftOffset,rect.origin.y,width,rect.size.height);
} }
/*! /*!
@@ -246,9 +224,9 @@ var RECENT_SEARCH_PREFIX = @" ";
@param rect The current bounding rectangle for the search button. @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. 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.
*/ */
- (CGRect)searchButtonRectForBounds:(CGRect)rect - (CPRect)searchButtonRectForBounds:(CPRect)rect
{ {
return _CGRectMake(5, (_CGRectGetHeight(rect) - BUTTON_DEFAULT_HEIGHT) / 2, SEARCH_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT); return [_searchButton frame];
} }
/*! /*!
@@ -256,9 +234,9 @@ var RECENT_SEARCH_PREFIX = @" ";
@param rect The updated bounding rectangle to use for the cancel button. The default value is the value passed into the rect parameter. @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. 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.
*/ */
- (CGRect)cancelButtonRectForBounds:(CGRect)rect - (CPRect)cancelButtonRectForBounds:(CPRect)rect
{ {
return _CGRectMake(_CGRectGetWidth(rect) - CANCEL_BUTTON_DEFAULT_WIDTH - 5, (_CGRectGetHeight(rect) - CANCEL_BUTTON_DEFAULT_WIDTH) / 2, BUTTON_DEFAULT_HEIGHT, BUTTON_DEFAULT_HEIGHT); return [_cancelButton frame];
} }
// Managing Menu Templates // Managing Menu Templates
@@ -276,9 +254,9 @@ var RECENT_SEARCH_PREFIX = @" ";
@param menu The menu template to use. @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. 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)aMenu - (void)setSearchMenuTemplate:(CPMenu)menu
{ {
_searchMenuTemplate = aMenu; _searchMenuTemplate = menu;
[self resetSearchButton]; [self resetSearchButton];
[self _loadRecentSearchList]; [self _loadRecentSearchList];
@@ -395,7 +373,7 @@ var RECENT_SEARCH_PREFIX = @" ";
// Private methods and subclassing // Private methods and subclassing
- (CGRect)contentRectForBounds:(CGRect)bounds - (CPRect)contentRectForBounds:(CPRect)bounds
{ {
var superbounds = [super contentRectForBounds:bounds]; var superbounds = [super contentRectForBounds:bounds];
return [self searchTextRectForBounds:superbounds]; return [self searchTextRectForBounds:superbounds];
@@ -469,78 +447,37 @@ var RECENT_SEARCH_PREFIX = @" ";
[self _updateSearchMenu]; [self _updateSearchMenu];
} }
- (CPView)hitTest:(CGPoint)aPoint - (BOOL)trackMouse:(CPEvent)event
{ {
// Make sure a hit anywhere within the search field returns the search field itself var rect,
if (_CGRectContainsPoint([self frame], aPoint)) point,
return self; location = [event locationInWindow];
else
return nil; point = [self convertPoint:location fromView:nil];
}
rect = [self searchButtonRectForBounds:[self frame]];
- (BOOL)resignFirstResponder if (CPRectContainsPoint(rect,point))
{
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) return [[self searchButton] trackMouse:event];
[self _sendAction:self]; }
else
[self _showMenu]; rect = [self cancelButtonRectForBounds:[self frame]];
} if (CPRectContainsPoint(rect,point))
else if (_CGRectContainsPoint([self cancelButtonRectForBounds:[self bounds]], point)) {
[_cancelButton mouseDown:anEvent]; return [[self cancelButton] trackMouse:event];
else }
[super mouseDown:anEvent];
return [super trackMouse:event];
} }
/*! - (CPMenu)_defaultSearchMenuTemplate
Provides the common case items for a recent searches menu. If there are not recent searches,
displays a single disabled item:
No Recent Searches
If there are 1 more recent searches, it displays:
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], var template, item;
item;
template = [[CPMenu alloc] init];
item = [[CPMenuItem alloc] initWithTitle:@"Recent Searches"
action:nil item = [[CPMenuItem alloc] initWithTitle:@"Recent searches"
action:NULL
keyEquivalent:@""]; keyEquivalent:@""];
[item setTag:CPSearchFieldRecentsTitleMenuItemTag]; [item setTag:CPSearchFieldRecentsTitleMenuItemTag];
[item setEnabled:NO]; [item setEnabled:NO];
@@ -553,15 +490,15 @@ var RECENT_SEARCH_PREFIX = @" ";
[item setTarget:self]; [item setTarget:self];
[template addItem:item]; [template addItem:item];
item = [[CPMenuItem alloc] initWithTitle:@"Clear Recent Searches" item = [[CPMenuItem alloc] initWithTitle:@"Clear recent searches"
action:@selector(_searchFieldClearRecents:) action:@selector(_searchFieldClearRecents:)
keyEquivalent:@""]; keyEquivalent:@""];
[item setTag:CPSearchFieldClearRecentsMenuItemTag]; [item setTag:CPSearchFieldClearRecentsMenuItemTag];
[item setTarget:self]; [item setTarget:self];
[template addItem:item]; [template addItem:item];
item = [[CPMenuItem alloc] initWithTitle:@"No Recent Searches" item = [[CPMenuItem alloc] initWithTitle:@"No recent searches"
action:nil action:NULL
keyEquivalent:@""]; keyEquivalent:@""];
[item setTag:CPSearchFieldNoRecentsMenuItemTag]; [item setTag:CPSearchFieldNoRecentsMenuItemTag];
[item setEnabled:NO]; [item setEnabled:NO];
@@ -575,96 +512,61 @@ var RECENT_SEARCH_PREFIX = @" ";
if (_searchMenuTemplate === nil) if (_searchMenuTemplate === nil)
return; return;
var menu = [[CPMenu alloc] init], var i, menu = [[CPMenu alloc] init],
countOfRecents = [_recentSearches count], countOfRecents = [_recentSearches count],
numberOfItems = [_searchMenuTemplate numberOfItems]; numberOfItems = [_searchMenuTemplate numberOfItems];
for (var i = 0; i < numberOfItems; i++) for (i = 0; i < numberOfItems; i++)
{ {
var item = [[_searchMenuTemplate itemAtIndex:i] copy]; var item = [_searchMenuTemplate itemAtIndex:i],
tag = [item tag];
switch ([item tag])
{
case CPSearchFieldRecentsTitleMenuItemTag:
if (countOfRecents === 0)
continue;
if ([menu numberOfItems] > 0)
[self _addSeparatorToMenu:menu];
break;
case CPSearchFieldRecentsMenuItemTag:
{
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)]; if (!(tag === CPSearchFieldRecentsTitleMenuItemTag && countOfRecents === 0) &&
[menu addItem:item]; !(tag === CPSearchFieldClearRecentsMenuItemTag && countOfRecents === 0) &&
} !(tag === CPSearchFieldNoRecentsMenuItemTag && countOfRecents != 0) &&
!(tag === CPSearchFieldRecentsMenuItemTag))
[menu setDelegate:self]; {
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;
}
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)
{
var j;
for (j = 0; j < countOfRecents; j++)
{
var rencentItem = [[CPMenuItem alloc] initWithTitle:[_recentSearches objectAtIndex:j]
action:@selector(_searchFieldSearch:)
keyEquivalent:[item keyEquivalent]];
[rencentItem setTarget:self];
[menu addItem:rencentItem];
}
}
}
_searchMenu = menu; _searchMenu = menu;
} }
- (void)_addSeparatorToMenu:(CPMenu)aMenu - (void)_showMenu:(id)sender
{
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]) if (_searchMenu === nil || [_searchMenu numberOfItems] === 0 || ![self isEnabled])
return; return;
@@ -674,14 +576,12 @@ var RECENT_SEARCH_PREFIX = @" ";
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]; 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];
[self selectAll:nil]; [CPMenu popUpContextMenu:_searchMenu withEvent:anEvent forView:sender];
[CPMenu popUpContextMenu:_searchMenu withEvent:anEvent forView:self];
} }
- (void)_sendPartialString - (void)_sendPartialString
{ {
[super sendAction:[self action] to:[self target]]; [[self target] performSelector:[self action] withObject:self];
[_partialStringTimer invalidate];
} }
- (void)_searchFieldCancel:(id)sender - (void)_searchFieldCancel:(id)sender
@@ -693,15 +593,14 @@ var RECENT_SEARCH_PREFIX = @" ";
- (void)_searchFieldSearch:(id)sender - (void)_searchFieldSearch:(id)sender
{ {
var searchString = [[sender title] substringFromIndex:[RECENT_SEARCH_PREFIX length]]; var searchString = [sender title];
if ([sender tag] != CPSearchFieldRecentsMenuItemTag) if ([sender tag] != CPSearchFieldRecentsMenuItemTag)
[self _addStringToRecentSearches:searchString]; [self _addStringToRecentSearches:searchString];
[self setObjectValue:searchString]; [self setObjectValue:searchString];
[self _sendPartialString]; [self _sendPartialString];
[self selectAll:nil];
[self _updateCancelButtonVisibility]; [self _updateCancelButtonVisibility];
} }
@@ -709,8 +608,6 @@ var RECENT_SEARCH_PREFIX = @" ";
{ {
[self setRecentSearches:[CPArray array]]; [self setRecentSearches:[CPArray array]];
[self _updateSearchMenu]; [self _updateSearchMenu];
[self setStringValue:@""];
[self _updateCancelButtonVisibility];
} }
- (void)_registerForAutosaveNotification - (void)_registerForAutosaveNotification
@@ -771,7 +668,7 @@ var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
CPSendsWholeSearchStringKey = @"CPSendsWholeSearchStringKey", CPSendsWholeSearchStringKey = @"CPSendsWholeSearchStringKey",
CPSendsSearchStringImmediatelyKey = @"CPSendsSearchStringImmediatelyKey", CPSendsSearchStringImmediatelyKey = @"CPSendsSearchStringImmediatelyKey",
CPMaximumRecentsKey = @"CPMaximumRecentsKey", CPMaximumRecentsKey = @"CPMaximumRecentsKey",
CPSearchMenuTemplateKey = @"CPSearchMenuTemplateKey"; CPSearchMenuTemplateKey = @"CPSearchMenuTemplateKey";
@implementation CPSearchField (CPCoding) @implementation CPSearchField (CPCoding)
@@ -793,7 +690,6 @@ var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
if (_recentsAutosaveName) if (_recentsAutosaveName)
[coder encodeObject:_recentsAutosaveName forKey:CPRecentsAutosaveNameKey]; [coder encodeObject:_recentsAutosaveName forKey:CPRecentsAutosaveNameKey];
if (_searchMenuTemplate) if (_searchMenuTemplate)
[coder encodeObject:_searchMenuTemplate forKey:CPSearchMenuTemplateKey]; [coder encodeObject:_searchMenuTemplate forKey:CPSearchMenuTemplateKey];
} }
@@ -802,17 +698,18 @@ var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
{ {
if (self = [super initWithCoder:coder]) if (self = [super initWithCoder:coder])
{ {
[self _initWithFrame:[self frame]];
_recentsAutosaveName = [coder decodeObjectForKey:CPRecentsAutosaveNameKey]; _recentsAutosaveName = [coder decodeObjectForKey:CPRecentsAutosaveNameKey];
_sendsWholeSearchString = [coder decodeBoolForKey:CPSendsWholeSearchStringKey]; _sendsWholeSearchString = [coder decodeBoolForKey:CPSendsWholeSearchStringKey];
_sendsSearchStringImmediately = [coder decodeBoolForKey:CPSendsSearchStringImmediatelyKey]; _sendsSearchStringImmediately = [coder decodeBoolForKey:CPSendsSearchStringImmediatelyKey];
_maximumRecents = [coder decodeIntForKey:CPMaximumRecentsKey]; _maximumRecents = [coder decodeIntForKey:CPMaximumRecentsKey];
var template = [coder decodeObjectForKey:CPSearchMenuTemplateKey]; var template = [coder decodeObjectForKey:CPSearchMenuTemplateKey];
if (template) if (template)
[self setSearchMenuTemplate:template]; [self setSearchMenuTemplate:template];
[self _init]; [self setDelegate:self];
} }
return self; return self;
-1
View File
@@ -1,7 +1,6 @@
@import "CPTextField.j" @import "CPTextField.j"
/*! /*!
@ingroup appkit @ingroup appkit
*/ */
+133 -132
View File
@@ -24,12 +24,13 @@
@import "CPControl.j" @import "CPControl.j"
#include "CoreGraphics/CGGeometry.h"
CPSegmentSwitchTrackingSelectOne = 0; CPSegmentSwitchTrackingSelectOne = 0;
CPSegmentSwitchTrackingSelectAny = 1; CPSegmentSwitchTrackingSelectAny = 1;
CPSegmentSwitchTrackingMomentary = 2; CPSegmentSwitchTrackingMomentary = 2;
/*! /*!
@ingroup appkit @ingroup appkit
@class CPSegmentedControl @class CPSegmentedControl
@@ -48,7 +49,7 @@ CPSegmentSwitchTrackingMomentary = 2;
BOOL _trackingHighlighted; BOOL _trackingHighlighted;
} }
+ (CPString)defaultThemeClass + (CPString)themeClass
{ {
return "segmented-control"; return "segmented-control";
} }
@@ -63,16 +64,16 @@ CPSegmentSwitchTrackingMomentary = 2;
{ {
_segments = []; _segments = [];
_themeStates = []; _themeStates = [];
self = [super initWithFrame:aRect]; self = [super initWithFrame:aRect];
if (self) if (self)
{ {
_selectedSegment = -1; _selectedSegment = -1;
_trackingMode = CPSegmentSwitchTrackingSelectOne; _trackingMode = CPSegmentSwitchTrackingSelectOne;
} }
return self; return self;
} }
@@ -81,7 +82,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/ */
- (int)selectedTag - (int)selectedTag
{ {
return [_segments[_selectedSegment] tag]; return _segments[_selectedSegment].tag;
} }
// Specifying the number of segments // Specifying the number of segments
@@ -93,11 +94,11 @@ CPSegmentSwitchTrackingMomentary = 2;
{ {
if (_segments.length == aCount) if (_segments.length == aCount)
return; return;
var height = CGRectGetHeight([self bounds]); var height = CGRectGetHeight([self bounds]);
if (_segments.length < aCount) if (_segments.length < aCount)
{ {
for (var index = _segments.length; index < aCount; ++index) for (var index = _segments.length; index < aCount; ++index)
{ {
_segments[index] = [[_CPSegmentItem alloc] init]; _segments[index] = [[_CPSegmentItem alloc] init];
@@ -150,15 +151,15 @@ CPSegmentSwitchTrackingMomentary = 2;
- (BOOL)selectSegmentWithTag:(int)aTag - (BOOL)selectSegmentWithTag:(int)aTag
{ {
var index = 0; var index = 0;
for (; index < _segments.length; ++index) for (; index < _segments.length; ++index)
if (_segments[index].tag == aTag) if (_segments[index].tag == aTag)
{ {
[self setSelectedSegment:index]; [self setSelectedSegment:index];
return YES; return YES;
} }
return NO; return NO;
} }
@@ -173,28 +174,28 @@ CPSegmentSwitchTrackingMomentary = 2;
{ {
if (_trackingMode == aTrackingMode) if (_trackingMode == aTrackingMode)
return; return;
_trackingMode = aTrackingMode; _trackingMode = aTrackingMode;
if (_trackingMode == CPSegmentSwitchTrackingSelectOne) if (_trackingMode == CPSegmentSwitchTrackingSelectOne)
{ {
var index = 0, var index = 0,
selected = NO; selected = NO;
for (; index < _segments.length; ++index) for (; index < _segments.length; ++index)
if ([_segments[index] selected]) if (_segments[index].selected)
if (selected) if (selected)
[self setSelected:NO forSegment:index]; [self setSelected:NO forSegment:index];
else else
selected = YES; selected = YES;
} }
else if (_trackingMode == CPSegmentSwitchTrackingMomentary) else if (_trackingMode == CPSegmentSwitchTrackingMomentary)
{ {
var index = 0; var index = 0;
for (; index < _segments.length; ++index) for (; index < _segments.length; ++index)
if ([_segments[index] selected]) if (_segments[index].selected)
[self setSelected:NO forSegment:index]; [self setSelected:NO forSegment:index];
} }
} }
@@ -216,8 +217,8 @@ CPSegmentSwitchTrackingMomentary = 2;
*/ */
- (void)setWidth:(float)aWidth forSegment:(unsigned)aSegment - (void)setWidth:(float)aWidth forSegment:(unsigned)aSegment
{ {
[_segments[aSegment] setWidth:aWidth]; _segments[aSegment].width = aWidth;
[self tileWithChangedSegment:aSegment]; [self tileWithChangedSegment:aSegment];
} }
@@ -228,7 +229,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/ */
- (float)widthForSegment:(unsigned)aSegment - (float)widthForSegment:(unsigned)aSegment
{ {
return [_segments[aSegment] width]; return _segments[aSegment].width;
} }
/*! /*!
@@ -239,7 +240,9 @@ CPSegmentSwitchTrackingMomentary = 2;
*/ */
- (void)setImage:(CPImage)anImage forSegment:(unsigned)aSegment - (void)setImage:(CPImage)anImage forSegment:(unsigned)aSegment
{ {
[_segments[aSegment] setImage:anImage]; var segment = _segments[aSegment];
segment.image = anImage;
[self tileWithChangedSegment:aSegment]; [self tileWithChangedSegment:aSegment];
} }
@@ -251,7 +254,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/ */
- (CPImage)imageForSegment:(unsigned)aSegment - (CPImage)imageForSegment:(unsigned)aSegment
{ {
return [_segments[aSegment] image]; return _segments[aSegment].image;
} }
/*! /*!
@@ -262,8 +265,10 @@ CPSegmentSwitchTrackingMomentary = 2;
*/ */
- (void)setLabel:(CPString)aLabel forSegment:(unsigned)aSegment - (void)setLabel:(CPString)aLabel forSegment:(unsigned)aSegment
{ {
[_segments[aSegment] setLabel:aLabel]; var segment = _segments[aSegment];
_segments[aSegment].label = aLabel;
[self tileWithChangedSegment:aSegment]; [self tileWithChangedSegment:aSegment];
} }
@@ -274,7 +279,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/ */
- (CPString)labelForSegment:(unsigned)aSegment - (CPString)labelForSegment:(unsigned)aSegment
{ {
return [_segments[aSegment] label]; return _segments[aSegment].label;
} }
/*! /*!
@@ -285,7 +290,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/ */
- (void)setMenu:(CPMenu)aMenu forSegment:(unsigned)aSegment - (void)setMenu:(CPMenu)aMenu forSegment:(unsigned)aSegment
{ {
[_segments[aSegment] setMenu:aMenu]; _segments[aSegment].menu = aMenu;
} }
/*! /*!
@@ -295,7 +300,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/ */
- (CPMenu)menuForSegment:(unsigned)aSegment - (CPMenu)menuForSegment:(unsigned)aSegment
{ {
return [_segments[aSegment] menu]; return _segments[aSegment].menu;
} }
/*! /*!
@@ -308,12 +313,12 @@ CPSegmentSwitchTrackingMomentary = 2;
- (void)setSelected:(BOOL)isSelected forSegment:(unsigned)aSegment - (void)setSelected:(BOOL)isSelected forSegment:(unsigned)aSegment
{ {
var segment = _segments[aSegment]; var segment = _segments[aSegment];
// If we're already in this state, bail. // If we're already in this state, bail.
if ([segment selected] == isSelected) if (segment.selected == isSelected)
return; return;
[segment setSelected:isSelected]; segment.selected = isSelected;
_themeStates[aSegment] = isSelected ? CPThemeStateSelected : CPThemeStateNormal; _themeStates[aSegment] = isSelected ? CPThemeStateSelected : CPThemeStateNormal;
@@ -321,18 +326,18 @@ CPSegmentSwitchTrackingMomentary = 2;
if (isSelected) if (isSelected)
{ {
var oldSelectedSegment = _selectedSegment; var oldSelectedSegment = _selectedSegment;
_selectedSegment = aSegment; _selectedSegment = aSegment;
if (_trackingMode == CPSegmentSwitchTrackingSelectOne && oldSelectedSegment != aSegment && oldSelectedSegment != -1) if (_trackingMode == CPSegmentSwitchTrackingSelectOne && oldSelectedSegment != aSegment && oldSelectedSegment != -1)
{ {
[_segments[oldSelectedSegment] setSelected:NO]; _segments[oldSelectedSegment].selected = NO;
_themeStates[oldSelectedSegment] = CPThemeStateNormal; _themeStates[oldSelectedSegment] = CPThemeStateNormal;
[self drawSegmentBezel:oldSelectedSegment highlight:NO]; [self drawSegmentBezel:oldSelectedSegment highlight:NO];
} }
} }
if (_trackingMode != CPSegmentSwitchTrackingMomentary) if (_trackingMode != CPSegmentSwitchTrackingMomentary)
[self drawSegmentBezel:aSegment highlight:NO]; [self drawSegmentBezel:aSegment highlight:NO];
@@ -347,7 +352,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/ */
- (BOOL)isSelectedForSegment:(unsigned)aSegment - (BOOL)isSelectedForSegment:(unsigned)aSegment
{ {
return [_segments[aSegment] selected]; return _segments[aSegment].selected;
} }
/*! /*!
@@ -358,8 +363,6 @@ CPSegmentSwitchTrackingMomentary = 2;
*/ */
- (void)setEnabled:(BOOL)isEnabled forSegment:(unsigned)aSegment - (void)setEnabled:(BOOL)isEnabled forSegment:(unsigned)aSegment
{ {
[_segments[aSegment] setEnabled:isEnabled];
if (isEnabled) if (isEnabled)
_themeStates[aSegment] &= ~CPThemeStateDisabled; _themeStates[aSegment] &= ~CPThemeStateDisabled;
else else
@@ -376,7 +379,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/ */
- (BOOL)isEnabledForSegment:(unsigned)aSegment - (BOOL)isEnabledForSegment:(unsigned)aSegment
{ {
return [_segments[aSegment] enabled]; return !(_themeStates[aSegment] & CPThemeStateDisabled)
} }
/*! /*!
@@ -386,7 +389,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/ */
- (void)setTag:(int)aTag forSegment:(unsigned)aSegment - (void)setTag:(int)aTag forSegment:(unsigned)aSegment
{ {
[_segments[aSegment] setTag:aTag]; _segments[aSegment].tag = aTag;
} }
/*! /*!
@@ -395,7 +398,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/ */
- (int)tagForSegment:(unsigned)aSegment - (int)tagForSegment:(unsigned)aSegment
{ {
return [_segments[aSegment] tag]; return _segments[aSegment].tag;
} }
// Drawings // Drawings
@@ -458,7 +461,7 @@ CPSegmentSwitchTrackingMomentary = 2;
else if (aName.indexOf("segment-bezel") === 0) else if (aName.indexOf("segment-bezel") === 0)
{ {
var segment = parseInt(aName.substring("segment-bezel-".length), 10), var segment = parseInt(aName.substring("segment-bezel-".length), 10),
frame = CGRectCreateCopy([_segments[segment] frame]); frame = CGRectCreateCopy(_segments[segment].frame);
if (segment === 0) if (segment === 0)
{ {
@@ -492,7 +495,7 @@ CPSegmentSwitchTrackingMomentary = 2;
- (CPView)createEphemeralSubviewNamed:(CPString)aName - (CPView)createEphemeralSubviewNamed:(CPString)aName
{ {
if ([aName hasPrefix:@"segment-content"]) if (aName.substring(0, "segment-content".length) == "segment-content")
return [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()]; return [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
return [[CPView alloc] initWithFrame:_CGRectMakeZero()]; return [[CPView alloc] initWithFrame:_CGRectMakeZero()];
@@ -507,10 +510,10 @@ CPSegmentSwitchTrackingMomentary = 2;
themeState |= _themeState & CPThemeStateDisabled; themeState |= _themeState & CPThemeStateDisabled;
var leftCapColor = [self valueForThemeAttribute:@"left-segment-bezel-color" var leftCapColor = [self valueForThemeAttribute:@"left-segment-bezel-color"
inState:themeState], inState:themeState];
leftBezelView = [self layoutEphemeralSubviewNamed:@"left-segment-bezel" var leftBezelView = [self layoutEphemeralSubviewNamed:@"left-segment-bezel"
positioned:CPWindowBelow positioned:CPWindowBelow
relativeToEphemeralSubviewNamed:nil]; relativeToEphemeralSubviewNamed:nil];
@@ -520,39 +523,41 @@ CPSegmentSwitchTrackingMomentary = 2;
themeState |= _themeState & CPThemeStateDisabled; themeState |= _themeState & CPThemeStateDisabled;
var rightCapColor = [self valueForThemeAttribute:@"right-segment-bezel-color" var rightCapColor = [self valueForThemeAttribute:@"right-segment-bezel-color"
inState:themeState], inState:themeState];
rightBezelView = [self layoutEphemeralSubviewNamed:@"right-segment-bezel" var rightBezelView = [self layoutEphemeralSubviewNamed:@"right-segment-bezel"
positioned:CPWindowBelow positioned:CPWindowBelow
relativeToEphemeralSubviewNamed:nil]; relativeToEphemeralSubviewNamed:nil];
[rightBezelView setBackgroundColor:rightCapColor]; [rightBezelView setBackgroundColor:rightCapColor];
for (var i = 0, count = _themeStates.length; i < count; i++) for (var i=0, count = _themeStates.length; i<count; i++)
{ {
var themeState = _themeStates[i]; var themeState = _themeStates[i];
themeState |= _themeState & CPThemeStateDisabled; themeState |= _themeState & CPThemeStateDisabled;
var bezelColor = [self valueForThemeAttribute:@"center-segment-bezel-color" var bezelColor = [self valueForThemeAttribute:@"center-segment-bezel-color"
inState:themeState], inState:themeState];
bezelView = [self layoutEphemeralSubviewNamed:"segment-bezel-" + i var bezelView = [self layoutEphemeralSubviewNamed:"segment-bezel-"+i
positioned:CPWindowBelow positioned:CPWindowBelow
relativeToEphemeralSubviewNamed:nil]; relativeToEphemeralSubviewNamed:nil];
[bezelView setBackgroundColor:bezelColor]; [bezelView setBackgroundColor:bezelColor];
// layout image/title views //layout image/title views
var segment = _segments[i], var segment = _segments[i];
contentView = [self layoutEphemeralSubviewNamed:@"segment-content-" + i
positioned:CPWindowAbove
relativeToEphemeralSubviewNamed:@"segment-bezel-" + i];
[contentView setText:[segment label]];
[contentView setImage:[segment image]]; var contentView = [self layoutEphemeralSubviewNamed:@"segment-content-"+i
positioned:CPWindowAbove
relativeToEphemeralSubviewNamed:@"segment-bezel-"+i];
[contentView setText:segment.label];
[contentView setImage:segment.image];
[contentView setFont:[self valueForThemeAttribute:@"font" inState:themeState]]; [contentView setFont:[self valueForThemeAttribute:@"font" inState:themeState]];
[contentView setTextColor:[self valueForThemeAttribute:@"text-color" inState:themeState]]; [contentView setTextColor:[self valueForThemeAttribute:@"text-color" inState:themeState]];
@@ -561,27 +566,27 @@ CPSegmentSwitchTrackingMomentary = 2;
[contentView setLineBreakMode:[self valueForThemeAttribute:@"line-break-mode" inState:themeState]]; [contentView setLineBreakMode:[self valueForThemeAttribute:@"line-break-mode" inState:themeState]];
[contentView setTextShadowColor:[self valueForThemeAttribute:@"text-shadow-color" inState:themeState]]; [contentView setTextShadowColor:[self valueForThemeAttribute:@"text-shadow-color" inState:themeState]];
[contentView setTextShadowOffset:[self valueForThemeAttribute:@"text-shadow-offset" inState:themeState]]; [contentView setTextShadowOffset:[self valueForThemeAttribute:@"text-shadow-offset" inState:themeState]];
[contentView setImageScaling:[self valueForThemeAttribute:@"image-scaling" 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]]; [contentView setImagePosition:[self valueForThemeAttribute:@"image-position" inState:themeState]];
else if ([segment image]) else if (segment.image)
[contentView setImagePosition:CPImageOnly]; [contentView setImagePosition:CPImageOnly];
if (i == count - 1) if (i == count - 1)
continue; continue;
var borderState = _themeStates[i] | _themeStates[i + 1]; var borderState = _themeStates[i] | _themeStates[i+1];
borderState = (borderState & CPThemeStateSelected & ~CPThemeStateHighlighted) ? CPThemeStateSelected : CPThemeStateNormal; borderState = (borderState & CPThemeStateSelected & ~CPThemeStateHighlighted) ? CPThemeStateSelected : CPThemeStateNormal;
borderState |= _themeState & CPThemeStateDisabled; borderState |= _themeState & CPThemeStateDisabled;
var borderColor = [self valueForThemeAttribute:@"divider-bezel-color" var borderColor = [self valueForThemeAttribute:@"divider-bezel-color"
inState:borderState], inState:borderState];
borderView = [self layoutEphemeralSubviewNamed:"divider-bezel-" + i var borderView = [self layoutEphemeralSubviewNamed:"divider-bezel-"+i
positioned:CPWindowBelow positioned:CPWindowBelow
relativeToEphemeralSubviewNamed:nil]; relativeToEphemeralSubviewNamed:nil];
[borderView setBackgroundColor:borderColor]; [borderView setBackgroundColor:borderColor];
@@ -604,53 +609,48 @@ CPSegmentSwitchTrackingMomentary = 2;
return; return;
var segment = _segments[aSegment], var segment = _segments[aSegment],
segmentWidth = [segment width], segmentWidth = segment.width,
themeState = _themeStates[aSegment] | (_themeState & CPThemeStateDisabled), themeState = _themeStates[aSegment] | (_themeState & CPThemeStateDisabled),
contentInset = [self valueForThemeAttribute:@"content-inset" inState:themeState], contentInset = [self valueForThemeAttribute:@"content-inset" inState:themeState],
font = [self valueForThemeAttribute:@"font" inState:themeState]; font = [self valueForThemeAttribute:@"font" inState:themeState];
if (!segmentWidth) if (!segmentWidth)
{ {
if ([segment image] && [segment label]) if (segment.image && segment.label)
segmentWidth = [[segment label] sizeWithFont:font].width + [[segment image] size].width + contentInset.left + contentInset.right; segmentWidth = [segment.label sizeWithFont:font].width + [segment.image size].width + contentInset.left + contentInset.right;
else if (segment.image) 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) 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 else
segmentWidth = 0.0; segmentWidth = 0.0;
} }
var delta = segmentWidth - CGRectGetWidth([segment frame]); var delta = segmentWidth - CGRectGetWidth(segment.frame);
if (!delta) if (!delta)
{
[self setNeedsLayout];
[self setNeedsDisplay:YES];
return; return;
}
// Update control size // Update Contorl Size
var frame = [self frame]; var frame = [self frame];
[self setFrameSize:CGSizeMake(CGRectGetWidth(frame) + delta, CGRectGetHeight(frame))]; [self setFrameSize:CGSizeMake(CGRectGetWidth(frame) + delta, CGRectGetHeight(frame))];
// Update segment width // Update Segment Width
[segment setWidth:segmentWidth]; segment.width = segmentWidth;
[segment setFrame:[self frameForSegment:aSegment]]; segment.frame = [self frameForSegment:aSegment];;
// Update following segments widths // Update Following Segments Widths
var index = aSegment + 1; var index = aSegment + 1;
for (; index < _segments.length; ++index) for (; index < _segments.length; ++index)
{ {
[_segments[index] frame].origin.x += delta; _segments[index].frame.origin.x += delta;
[self drawSegmentBezel:index highlight:NO]; [self drawSegmentBezel:index highlight:NO];
[self drawSegment:index highlight:NO]; [self drawSegment:index highlight:NO];
} }
[self drawSegmentBezel:aSegment highlight:NO]; [self drawSegmentBezel:aSegment highlight:NO];
[self drawSegment:aSegment highlight:NO]; [self drawSegment:aSegment highlight:NO];
@@ -696,14 +696,14 @@ CPSegmentSwitchTrackingMomentary = 2;
{ {
var location = [self convertPoint:aPoint fromView:nil], var location = [self convertPoint:aPoint fromView:nil],
count = _segments.length; count = _segments.length;
while (count--) while (count--)
if (CGRectContainsPoint([_segments[count] frame], aPoint)) if (CGRectContainsPoint(_segments[count].frame, aPoint))
return count; return count;
if (_segments.length) 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; adjustedLastFrame.size.width = CGRectGetWidth([self bounds]) - adjustedLastFrame.origin.x;
if (CGRectContainsPoint(adjustedLastFrame, aPoint)) if (CGRectContainsPoint(adjustedLastFrame, aPoint))
@@ -717,7 +717,7 @@ CPSegmentSwitchTrackingMomentary = 2;
{ {
if (![self isEnabled]) if (![self isEnabled])
return; return;
[self trackSegment:anEvent]; [self trackSegment:anEvent];
} }
@@ -731,10 +731,10 @@ CPSegmentSwitchTrackingMomentary = 2;
@param anEvent the event to handle @param anEvent the event to handle
*/ */
- (void)trackSegment:(CPEvent)anEvent - (void)trackSegment:(CPEvent)anEvent
{ {
var type = [anEvent type], var type = [anEvent type],
location = [self convertPoint:[anEvent locationInWindow] fromView:nil]; location = [self convertPoint:[anEvent locationInWindow] fromView:nil];
if (type == CPLeftMouseUp) if (type == CPLeftMouseUp)
{ {
if (_trackingSegment == -1) if (_trackingSegment == -1)
@@ -745,30 +745,30 @@ CPSegmentSwitchTrackingMomentary = 2;
if (_trackingMode == CPSegmentSwitchTrackingSelectAny) if (_trackingMode == CPSegmentSwitchTrackingSelectAny)
{ {
[self setSelected:![self isSelectedForSegment:_trackingSegment] forSegment:_trackingSegment]; [self setSelected:![self isSelectedForSegment:_trackingSegment] forSegment:_trackingSegment];
// With ANY, _selectedSegment means last pressed. // With ANY, _selectedSegment means last pressed.
_selectedSegment = _trackingSegment; _selectedSegment = _trackingSegment;
} }
else else
[self setSelected:YES forSegment:_trackingSegment]; [self setSelected:YES forSegment:_trackingSegment];
[self sendAction:[self action] to:[self target]]; [self sendAction:[self action] to:[self target]];
if (_trackingMode == CPSegmentSwitchTrackingMomentary) if (_trackingMode == CPSegmentSwitchTrackingMomentary)
{ {
[self setSelected:NO forSegment:_trackingSegment]; [self setSelected:NO forSegment:_trackingSegment];
_selectedSegment = -1; _selectedSegment = -1;
} }
} }
[self drawSegmentBezel:_trackingSegment highlight:NO]; [self drawSegmentBezel:_trackingSegment highlight:NO];
_trackingSegment = -1; _trackingSegment = -1;
return; return;
} }
if (type == CPLeftMouseDown) if (type == CPLeftMouseDown)
{ {
var trackingSegment = [self testSegment:location]; var trackingSegment = [self testSegment:location];
@@ -779,7 +779,7 @@ CPSegmentSwitchTrackingMomentary = 2;
[self drawSegmentBezel:_trackingSegment highlight:YES]; [self drawSegmentBezel:_trackingSegment highlight:YES];
} }
} }
else if (type == CPLeftMouseDragged) else if (type == CPLeftMouseDragged)
{ {
if (_trackingSegment == -1) if (_trackingSegment == -1)
@@ -793,14 +793,14 @@ CPSegmentSwitchTrackingMomentary = 2;
[self drawSegmentBezel:_trackingSegment highlight:_trackingHighlighted]; [self drawSegmentBezel:_trackingSegment highlight:_trackingHighlighted];
} }
} }
[CPApp setTarget:self selector:@selector(trackSegment:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES]; [CPApp setTarget:self selector:@selector(trackSegment:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
} }
- (void)setFont:(CPFont)aFont - (void)setFont:(CPFont)aFont
{ {
[super setFont:aFont]; [super setFont:aFont];
[self tileWithChangedSegment:0]; [self tileWithChangedSegment:0];
} }
@@ -816,12 +816,12 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
- (id)initWithCoder:(CPCoder)aCoder - (id)initWithCoder:(CPCoder)aCoder
{ {
self = [super initWithCoder:aCoder]; self = [super initWithCoder:aCoder];
if (self) if (self)
{ {
var frame = [self frame], var frame = [self frame],
originalWidth = frame.size.width; originalWidth = frame.size.width;
frame.size.width = 0; frame.size.width = 0;
[self setFrame:frame]; [self setFrame:frame];
@@ -832,38 +832,38 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
if ([aCoder containsValueForKey:CPSegmentedControlSelectedKey]) if ([aCoder containsValueForKey:CPSegmentedControlSelectedKey])
_selectedSegment = [aCoder decodeIntForKey:CPSegmentedControlSelectedKey]; _selectedSegment = [aCoder decodeIntForKey:CPSegmentedControlSelectedKey];
else else
_selectedSegment = -1; _selectedSegment = -1;
if ([aCoder containsValueForKey:CPSegmentedControlTrackingModeKey]) if ([aCoder containsValueForKey:CPSegmentedControlTrackingModeKey])
_trackingMode = [aCoder decodeIntForKey:CPSegmentedControlTrackingModeKey]; _trackingMode = [aCoder decodeIntForKey:CPSegmentedControlTrackingModeKey];
else else
_trackingMode = CPSegmentSwitchTrackingSelectOne; _trackingMode = CPSegmentSwitchTrackingSelectOne;
// HACK // HACK
for (var i = 0; i < _segments.length; i++) 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]; [self tileWithChangedSegment:i];
} }
var difference = MAX(originalWidth - [self frame].size.width, 0.0), var difference = MAX(originalWidth - [self frame].size.width, 0.0),
remainingWidth = FLOOR(difference / _segments.length); remainingWidth = FLOOR(difference / _segments.length);
for (var i = 0; i < _segments.length; i++) 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]; [self tileWithChangedSegment:0];
} }
return self; return self;
} }
- (void)encodeWithCoder:(CPCoder)aCoder - (void)encodeWithCoder:(CPCoder)aCoder
{ {
[super encodeWithCoder:aCoder]; [super encodeWithCoder:aCoder];
[aCoder encodeObject:_segments forKey:CPSegmentedControlSegmentsKey]; [aCoder encodeObject:_segments forKey:CPSegmentedControlSegmentsKey];
[aCoder encodeInt:_selectedSegment forKey:CPSegmentedControlSelectedKey]; [aCoder encodeInt:_selectedSegment forKey:CPSegmentedControlSelectedKey];
[aCoder encodeInt:_segmentStyle forKey:CPSegmentedControlSegmentStyleKey]; [aCoder encodeInt:_segmentStyle forKey:CPSegmentedControlSegmentStyleKey];
@@ -875,15 +875,15 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
@implementation _CPSegmentItem : CPObject @implementation _CPSegmentItem : CPObject
{ {
CPImage image @accessors; CPImage image;
CPString label @accessors; CPString label;
CPMenu menu @accessors; CPMenu menu;
BOOL selected @accessors; BOOL selected;
BOOL enabled @accessors; BOOL enabled;
int tag @accessors; int tag;
int width @accessors; int width;
CGRect frame @accessors; CGRect frame;
} }
- (id)init - (id)init
@@ -894,8 +894,8 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
label = @""; label = @"";
menu = nil; menu = nil;
selected = NO; selected = NO;
enabled = YES; enabled = NO;
tag = -1; tag = 0;
width = 0; width = 0;
frame = CGRectMakeZero(); frame = CGRectMakeZero();
@@ -918,7 +918,7 @@ var CPSegmentItemImageKey = "CPSegmentItemImageKey",
- (id)initWithCoder:(CPCoder)aCoder - (id)initWithCoder:(CPCoder)aCoder
{ {
self = [super init]; self = [super init];
if (self) if (self)
{ {
image = [aCoder decodeObjectForKey:CPSegmentItemImageKey]; image = [aCoder decodeObjectForKey:CPSegmentItemImageKey];
@@ -931,7 +931,7 @@ var CPSegmentItemImageKey = "CPSegmentItemImageKey",
frame = CGRectMakeZero(); frame = CGRectMakeZero();
} }
return self; return self;
} }
@@ -947,3 +947,4 @@ var CPSegmentItemImageKey = "CPSegmentItemImageKey",
} }
@end @end
+18 -41
View File
@@ -28,17 +28,19 @@
@import "CPView.j" @import "CPView.j"
#include "CoreGraphics/CGGeometry.h"
CPLightShadow = 0; CPLightShadow = 0;
CPHeavyShadow = 1; CPHeavyShadow = 1;
var CPShadowViewLightBackgroundColor = nil, var CPShadowViewLightBackgroundColor = nil,
CPShadowViewHeavyBackgroundColor = nil; CPShadowViewHeavyBackgroundColor = nil;
var LIGHT_LEFT_INSET = 3.0, var LIGHT_LEFT_INSET = 3.0,
LIGHT_RIGHT_INSET = 3.0, LIGHT_RIGHT_INSET = 3.0,
LIGHT_TOP_INSET = 3.0, LIGHT_TOP_INSET = 3.0,
LIGHT_BOTTOM_INSET = 5.0, LIGHT_BOTTOM_INSET = 5.0,
HEAVY_LEFT_INSET = 7.0, HEAVY_LEFT_INSET = 7.0,
HEAVY_RIGHT_INSET = 7.0, HEAVY_RIGHT_INSET = 7.0,
HEAVY_TOP_INSET = 5.0, HEAVY_TOP_INSET = 5.0,
@@ -59,76 +61,51 @@ var LIGHT_LEFT_INSET = 3.0,
return; return;
var bundle = [CPBundle bundleForClass:[self class]]; var bundle = [CPBundle bundleForClass:[self class]];
CPShadowViewLightBackgroundColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices: 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/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/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/CPShadowViewLightTopRight.png"] size:CGSizeMake(9.0, 9.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightLeft.png"] size:CGSizeMake(9.0, 1.0)], [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightLeft.png"] size:CGSizeMake(9.0, 1.0)],
nil, nil,
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightRight.png"] size:CGSizeMake(9.0, 1.0)], [[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/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/CPShadowViewLightBottom.png"] size:CGSizeMake(1.0, 9.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightBottomRight.png"] size:CGSizeMake(9.0, 9.0)] [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightBottomRight.png"] size:CGSizeMake(9.0, 9.0)]
]]]; ]]];
CPShadowViewHeavyBackgroundColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices: 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/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/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/CPShadowViewHeavyTopRight.png"] size:CGSizeMake(17.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyLeft.png"] size:CGSizeMake(17.0, 1.0)], [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyLeft.png"] size:CGSizeMake(17.0, 1.0)],
nil, nil,
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyRight.png"] size:CGSizeMake(17.0, 1.0)], [[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/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/CPShadowViewHeavyBottom.png"] size:CGSizeMake(1.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyBottomRight.png"] size:CGSizeMake(17.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 - (id)initWithFrame:(CGRect)aFrame
{ {
self = [super initWithFrame:aFrame]; self = [super initWithFrame:aFrame];
if (self) if (self)
{ {
_weight = CPLightShadow; _weight = CPLightShadow;
[self setBackgroundColor:CPShadowViewLightBackgroundColor]; [self setBackgroundColor:CPShadowViewLightBackgroundColor];
[self setHitTests:NO]; [self setHitTests:NO];
} }
return self; return self;
} }
@@ -136,9 +113,9 @@ var LIGHT_LEFT_INSET = 3.0,
{ {
if (_weight == aWeight) if (_weight == aWeight)
return; return;
_weight = aWeight; _weight = aWeight;
if (_weight == CPLightShadow) if (_weight == CPLightShadow)
[self setBackgroundColor:CPShadowViewLightBackgroundColor]; [self setBackgroundColor:CPShadowViewLightBackgroundColor];
@@ -170,7 +147,7 @@ var LIGHT_LEFT_INSET = 3.0,
{ {
if (_weight == CPLightShadow) if (_weight == CPLightShadow)
return LIGHT_LEFT_INSET + LIGHT_RIGHT_INSET; return LIGHT_LEFT_INSET + LIGHT_RIGHT_INSET;
return HEAVY_LEFT_INSET + HEAVY_RIGHT_INSET; return HEAVY_LEFT_INSET + HEAVY_RIGHT_INSET;
} }
@@ -178,7 +155,7 @@ var LIGHT_LEFT_INSET = 3.0,
{ {
if (_weight == CPLightShadow) if (_weight == CPLightShadow)
return LIGHT_TOP_INSET + LIGHT_BOTTOM_INSET; return LIGHT_TOP_INSET + LIGHT_BOTTOM_INSET;
return HEAVY_TOP_INSET + HEAVY_BOTTOM_INSET; return HEAVY_TOP_INSET + HEAVY_BOTTOM_INSET;
} }
+40 -50
View File
@@ -22,6 +22,7 @@
@import "CPControl.j" @import "CPControl.j"
#include "CoreGraphics/CGGeometry.h"
/*! SLIDER STATES */ /*! SLIDER STATES */
@@ -41,7 +42,7 @@ CPCircularSlider = 1;
BOOL _isVertical; BOOL _isVertical;
} }
+ (CPString)defaultThemeClass + (CPString)themeClass
{ {
return "slider"; return "slider";
} }
@@ -60,14 +61,14 @@ CPCircularSlider = 1;
{ {
_minValue = 0.0; _minValue = 0.0;
_maxValue = 100.0; _maxValue = 100.0;
[self setObjectValue:50.0]; [self setObjectValue:50.0];
[self setContinuous:YES]; [self setContinuous:YES];
[self _recalculateIsVertical]; [self _recalculateIsVertical];
} }
return self; return self;
} }
@@ -75,11 +76,11 @@ CPCircularSlider = 1;
{ {
if (_minValue === aMinimumValue) if (_minValue === aMinimumValue)
return; return;
_minValue = aMinimumValue; _minValue = aMinimumValue;
var doubleValue = [self doubleValue]; var doubleValue = [self doubleValue];
if (doubleValue < _minValue) if (doubleValue < _minValue)
[self setDoubleValue:_minValue]; [self setDoubleValue:_minValue];
@@ -97,11 +98,11 @@ CPCircularSlider = 1;
{ {
if (_maxValue === aMaximumValue) if (_maxValue === aMaximumValue)
return; return;
_maxValue = aMaximumValue; _maxValue = aMaximumValue;
var doubleValue = [self doubleValue]; var doubleValue = [self doubleValue];
if (doubleValue > _maxValue) if (doubleValue > _maxValue)
[self setDoubleValue:_maxValue]; [self setDoubleValue:_maxValue];
@@ -168,27 +169,27 @@ CPCircularSlider = 1;
bounds.size.height = trackWidth; bounds.size.height = trackWidth;
} }
} }
return bounds; return bounds;
} }
- (CGRect)knobRectForBounds:(CGRect)bounds - (CGRect)knobRectForBounds:(CGRect)bounds
{ {
var knobSize = [self currentValueForThemeAttribute:@"knob-size"]; var knobSize = [self currentValueForThemeAttribute:@"knob-size"];
if (knobSize.width <= 0 || knobSize.height <= 0) if (knobSize.width <= 0 || knobSize.height <= 0)
return _CGRectMakeZero(); return _CGRectMakeZero();
var knobRect = _CGRectMake(0.0, 0.0, knobSize.width, knobSize.height), var knobRect = _CGRectMake(0.0, 0.0, knobSize.width, knobSize.height),
trackRect = [self trackRectForBounds:bounds]; trackRect = [self trackRectForBounds:bounds];
// No track, do our best to approximate a place for this thing. // No track, do our best to approximate a place for this thing.
if (!trackRect || _CGRectIsEmpty(trackRect)) if (!trackRect || _CGRectIsEmpty(trackRect))
trackRect = bounds; trackRect = bounds;
if ([self hasThemeState:CPThemeStateCircular]) if ([self hasThemeState:CPThemeStateCircular])
{ {
var angle = 3 * PI_2 - (1.0 - [self doubleValue] - _minValue) / (_maxValue - _minValue) * PI2, var angle = 3*PI_2 - (1.0 - [self doubleValue] - _minValue) / (_maxValue - _minValue) * PI2,
radius = CGRectGetWidth(trackRect) / 2.0 - 8.0; radius = CGRectGetWidth(trackRect) / 2.0 - 8.0;
knobRect.origin.x = radius * COS(angle) + CGRectGetMidX(trackRect) - 3.0; knobRect.origin.x = radius * COS(angle) + CGRectGetMidX(trackRect) - 3.0;
@@ -197,7 +198,7 @@ CPCircularSlider = 1;
else if ([self isVertical]) else if ([self isVertical])
{ {
knobRect.origin.x = _CGRectGetMidX(trackRect) - knobSize.width / 2.0; knobRect.origin.x = _CGRectGetMidX(trackRect) - knobSize.width / 2.0;
knobRect.origin.y = ((_maxValue - [self doubleValue]) / (_maxValue - _minValue)) * (_CGRectGetHeight(trackRect) - knobSize.height); knobRect.origin.y = (([self doubleValue] - _minValue) / (_maxValue - _minValue)) * (_CGRectGetHeight(trackRect) - knobSize.height);
} }
else else
{ {
@@ -212,10 +213,10 @@ CPCircularSlider = 1;
{ {
if (aName === "track-view") if (aName === "track-view")
return [self trackRectForBounds:[self bounds]]; return [self trackRectForBounds:[self bounds]];
else if (aName === "knob-view") else if (aName === "knob-view")
return [self knobRectForBounds:[self bounds]]; return [self knobRectForBounds:[self bounds]];
return [super rectForEphemeralSubviewNamed:aName]; return [super rectForEphemeralSubviewNamed:aName];
} }
@@ -224,12 +225,12 @@ CPCircularSlider = 1;
if (aName === "track-view" || aName === "knob-view") if (aName === "track-view" || aName === "knob-view")
{ {
var view = [[CPView alloc] init]; var view = [[CPView alloc] init];
[view setHitTests:NO]; [view setHitTests:NO];
return view; return view;
} }
return [super createEphemeralSubviewNamed:aName]; return [super createEphemeralSubviewNamed:aName];
} }
@@ -255,7 +256,7 @@ CPCircularSlider = 1;
var bounds = [self bounds], var bounds = [self bounds],
width = _CGRectGetWidth(bounds), width = _CGRectGetWidth(bounds),
height = _CGRectGetHeight(bounds); height = _CGRectGetHeight(bounds);
_isVertical = width < height ? 1 : (width > height ? 0 : -1); _isVertical = width < height ? 1 : (width > height ? 0 : -1);
if (_isVertical === 1) if (_isVertical === 1)
@@ -281,7 +282,7 @@ CPCircularSlider = 1;
var knobView = [self layoutEphemeralSubviewNamed:@"knob-view" var knobView = [self layoutEphemeralSubviewNamed:@"knob-view"
positioned:CPWindowAbove positioned:CPWindowAbove
relativeToEphemeralSubviewNamed:@"track-view"]; relativeToEphemeralSubviewNamed:@"track-view"];
if (knobView) if (knobView)
[knobView setBackgroundColor:[self currentValueForThemeAttribute:"knob-color"]]; [knobView setBackgroundColor:[self currentValueForThemeAttribute:"knob-color"]];
} }
@@ -319,7 +320,7 @@ CPCircularSlider = 1;
var minValue = [self minValue]; var minValue = [self minValue];
return MAX(0.0, MIN(1.0, (_CGRectGetMaxY(trackRect) - aPoint.y) / _CGRectGetHeight(trackRect))) * ([self maxValue] - minValue) + minValue; return MAX(0.0, MIN(1.0, (aPoint.y - _CGRectGetMinY(trackRect)) / _CGRectGetHeight(trackRect))) * ([self maxValue] - minValue) + minValue;
} }
else else
{ {
@@ -338,43 +339,44 @@ CPCircularSlider = 1;
{ {
var bounds = [self bounds], var bounds = [self bounds],
knobRect = [self knobRectForBounds:_CGRectMakeCopy(bounds)]; knobRect = [self knobRectForBounds:_CGRectMakeCopy(bounds)];
if (_CGRectContainsPoint(knobRect, aPoint)) if (_CGRectContainsPoint(knobRect, aPoint))
_dragOffset = _CGSizeMake(_CGRectGetMidX(knobRect) - aPoint.x, _CGRectGetMidY(knobRect) - aPoint.y); _dragOffset = _CGSizeMake(_CGRectGetMidX(knobRect) - aPoint.x, _CGRectGetMidY(knobRect) - aPoint.y);
else
else
{ {
var trackRect = [self trackRectForBounds:bounds]; var trackRect = [self trackRectForBounds:bounds];
if (trackRect && _CGRectContainsPoint(trackRect, aPoint)) if (trackRect && _CGRectContainsPoint(trackRect, aPoint))
{ {
_dragOffset = _CGSizeMakeZero(); _dragOffset = _CGSizeMakeZero();
[self setObjectValue:[self _valueAtPoint:aPoint]]; [self setObjectValue:[self _valueAtPoint:aPoint]];
} }
else else
return NO; return NO;
} }
[self setHighlighted:YES]; [self setHighlighted:YES];
[self setNeedsLayout]; [self setNeedsLayout];
[self setNeedsDisplay:YES]; [self setNeedsDisplay:YES];
return YES; return YES;
} }
- (BOOL)continueTracking:(CGPoint)lastPoint at:(CGPoint)aPoint - (BOOL)continueTracking:(CGPoint)lastPoint at:(CGPoint)aPoint
{ {
[self setObjectValue:[self _valueAtPoint:_CGPointMake(aPoint.x + _dragOffset.width, aPoint.y + _dragOffset.height)]]; [self setObjectValue:[self _valueAtPoint:_CGPointMake(aPoint.x + _dragOffset.width, aPoint.y + _dragOffset.height)]];
return YES; return YES;
} }
- (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp - (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp
{ {
[self setHighlighted:NO]; [self setHighlighted:NO];
if ([_target respondsToSelector:@selector(sliderDidFinish:)]) if ([_target respondsToSelector:@selector(sliderDidFinish:)])
[_target sliderDidFinish:self]; [_target sliderDidFinish:self];
@@ -390,22 +392,10 @@ CPCircularSlider = 1;
{ {
if (flag) if (flag)
_sendActionOn |= CPLeftMouseDraggedMask; _sendActionOn |= CPLeftMouseDraggedMask;
else else
_sendActionOn &= ~CPLeftMouseDraggedMask; _sendActionOn &= ~CPLeftMouseDraggedMask;
} }
- (void)takeValueFromKeyPath:(CPString)aKeyPath ofObjects:(CPArray)objects
{
var count = objects.length,
value = [objects[0] valueForKeyPath:aKeyPath];
[self setObjectValue:value];
while (count-- > 1)
if (value !== ([objects[count] valueForKeyPath:aKeyPath]))
return [self setFloatValue:1.0];
}
@end @end
var CPSliderMinValueKey = "CPSliderMinValueKey", var CPSliderMinValueKey = "CPSliderMinValueKey",
@@ -452,14 +442,14 @@ var CPSliderMinValueKey = "CPSliderMinValueKey",
- (id)value - (id)value
{ {
CPLog.warn("[CPSlider value] is deprecated, use doubleValue or objectValue instead."); CPLog.warn("[CPSlider value] is deprecated, use doubleValue or objectValue instead.");
return [self doubleValue]; return [self doubleValue];
} }
- (void)setValue:(id)aValue - (void)setValue:(id)aValue
{ {
CPLog.warn("[CPSlider setValue:] is deprecated, use setDoubleValue: or setObjectValue: instead."); CPLog.warn("[CPSlider setValue:] is deprecated, use setDoubleValue: or setObjectValue: instead.");
[self setObjectValue:aValue]; [self setObjectValue:aValue];
} }
+167 -103
View File
@@ -20,10 +20,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
@import "CPView.j"
@import "CPColorPicker.j" @import "CPColorPicker.j"
/* /*
@ignore @ignore
*/ */
@@ -47,15 +45,16 @@
CPTextField _saturationLabel; CPTextField _saturationLabel;
CPTextField _brightnessLabel; CPTextField _brightnessLabel;
CPTextField _hexLabel; CPTextField _hexLabel;
CPTextField _hexValue;
CPTextField _hexValue; #if PLATFORM(DOM)
CPTextField _redValue; DOMElement _redValue;
CPTextField _greenValue; DOMElement _greenValue;
CPTextField _blueValue; DOMElement _blueValue;
CPTextField _hueValue; DOMElement _hueValue;
CPTextField _saturationValue; DOMElement _saturationValue;
CPTextField _brightnessValue; DOMElement _brightnessValue;
DOMElement _hexValue;
#endif
} }
- (id)initWithPickerMask:(int)mask colorPanel:(CPColorPanel)owningColorPanel - (id)initWithPickerMask:(int)mask colorPanel:(CPColorPanel)owningColorPanel
@@ -85,13 +84,73 @@
[_redSlider setAction: @selector(sliderChanged:)]; [_redSlider setAction: @selector(sliderChanged:)];
[_redSlider setAutoresizingMask: CPViewWidthSizable]; [_redSlider setAutoresizingMask: CPViewWidthSizable];
// red value input box #if PLATFORM(DOM)
_redValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 30, 45, 29)]; var updateFunction = function(aDOMEvent)
[_redValue setAutoresizingMask: CPViewMinXMargin]; {
[_redValue setEditable: YES]; if(isNaN(this.value))
[_redValue setBezeled: YES]; return;
[_redValue setDelegate: self];
[_contentView addSubview: _redValue]; 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
_greenLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 58, 15, 20)]; _greenLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 58, 15, 20)];
[_greenLabel setStringValue: "G"]; [_greenLabel setStringValue: "G"];
@@ -104,13 +163,17 @@
[_greenSlider setAction: @selector(sliderChanged:)]; [_greenSlider setAction: @selector(sliderChanged:)];
[_greenSlider setAutoresizingMask: CPViewWidthSizable]; [_greenSlider setAutoresizingMask: CPViewWidthSizable];
// green value input box #if PLATFORM(DOM)
_greenValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 53, 45, 29)]; //green value input box
[_greenValue setAutoresizingMask: CPViewMinXMargin]; var greenValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 58, 45, 20)];
[_greenValue setEditable: YES]; [greenValue setAutoresizingMask: CPViewMinXMargin];
[_greenValue setBezeled: YES];
[_greenValue setDelegate: self]; _greenValue = _redValue.cloneNode(false);
[_contentView addSubview: _greenValue]; _greenValue.onchange = updateFunction;
greenValue._DOMElement.appendChild(_greenValue);
[_contentView addSubview: greenValue];
#endif
_blueLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 81, 15, 20)]; _blueLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 81, 15, 20)];
[_blueLabel setStringValue: "B"]; [_blueLabel setStringValue: "B"];
@@ -123,14 +186,17 @@
[_blueSlider setAction: @selector(sliderChanged:)]; [_blueSlider setAction: @selector(sliderChanged:)];
[_blueSlider setAutoresizingMask: CPViewWidthSizable]; [_blueSlider setAutoresizingMask: CPViewWidthSizable];
// blue value input box #if PLATFORM(DOM)
_blueValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 76, 45, 29)]; //blue value input box
[_blueValue setAutoresizingMask: CPViewMinXMargin]; var blueValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 81, 45, 20)];
[_blueValue setEditable: YES]; [blueValue setAutoresizingMask: CPViewMinXMargin];
[_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 = [[CPTextField alloc] initWithFrame: CPRectMake(0, 120, 190, 20)];
[_hsbLabel setStringValue: "Hue, Saturation, Brightness"]; [_hsbLabel setStringValue: "Hue, Saturation, Brightness"];
[_hsbLabel setTextColor:[CPColor blackColor]]; [_hsbLabel setTextColor:[CPColor blackColor]];
@@ -146,14 +212,17 @@
[_hueSlider setAction: @selector(sliderChanged:)]; [_hueSlider setAction: @selector(sliderChanged:)];
[_hueSlider setAutoresizingMask: CPViewWidthSizable]; [_hueSlider setAutoresizingMask: CPViewWidthSizable];
// hue value input box #if PLATFORM(DOM)
_hueValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 140, 45, 29)]; //red value input box
[_hueValue setAutoresizingMask: CPViewMinXMargin]; var hueValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 145, 45, 20)];
[_hueValue setEditable: YES]; [hueValue setAutoresizingMask: CPViewMinXMargin];
[_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 = [[CPTextField alloc] initWithFrame: CPRectMake(0, 168, 15, 20)];
[_saturationLabel setStringValue: "S"]; [_saturationLabel setStringValue: "S"];
[_saturationLabel setTextColor:[CPColor blackColor]]; [_saturationLabel setTextColor:[CPColor blackColor]];
@@ -165,14 +234,17 @@
[_saturationSlider setAction: @selector(sliderChanged:)]; [_saturationSlider setAction: @selector(sliderChanged:)];
[_saturationSlider setAutoresizingMask: CPViewWidthSizable]; [_saturationSlider setAutoresizingMask: CPViewWidthSizable];
// saturation value input box #if PLATFORM(DOM)
_saturationValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 163, 45, 29)]; //green value input box
[_saturationValue setAutoresizingMask: CPViewMinXMargin]; var saturationValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 168, 45, 20)];
[_saturationValue setEditable: YES]; [saturationValue setAutoresizingMask: CPViewMinXMargin];
[_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 = [[CPTextField alloc] initWithFrame: CPRectMake(0, 191, 15, 20)];
[_brightnessLabel setStringValue: "B"]; [_brightnessLabel setStringValue: "B"];
[_brightnessLabel setTextColor:[CPColor blackColor]]; [_brightnessLabel setTextColor:[CPColor blackColor]];
@@ -184,24 +256,51 @@
[_brightnessSlider setAction: @selector(sliderChanged:)]; [_brightnessSlider setAction: @selector(sliderChanged:)];
[_brightnessSlider setAutoresizingMask: CPViewWidthSizable]; [_brightnessSlider setAutoresizingMask: CPViewWidthSizable];
// brightness value input box #if PLATFORM(DOM)
_brightnessValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 186, 45, 29)]; //blue value input box
[_brightnessValue setAutoresizingMask: CPViewMinXMargin]; var brightnessValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 191, 45, 20)];
[_brightnessValue setEditable: YES]; [brightnessValue setAutoresizingMask: CPViewMinXMargin];
[_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 = [[CPTextField alloc] initWithFrame: CPRectMake(0, 230, 30, 20)];
[_hexLabel setStringValue: "Hex"]; [_hexLabel setStringValue: "Hex"];
[_hexLabel setTextColor:[CPColor blackColor]]; [_hexLabel setTextColor:[CPColor blackColor]];
#if PLATFORM(DOM)
//hex input box //hex input box
_hexValue = [[CPTextField alloc] initWithFrame: CGRectMake(32, 225, 80, 29)]; _hexValue = _redValue.cloneNode(false);
[_hexValue setEditable: YES]; _hexValue.style.top = "228px";
[_hexValue setBezeled: YES]; _hexValue.style.width = "80px";
[_hexValue setDelegate: self]; _hexValue.style.left = "35px";
[_contentView addSubview: _hexValue]; _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
[_contentView addSubview: _rgbLabel]; [_contentView addSubview: _rgbLabel];
[_contentView addSubview: _redLabel]; [_contentView addSubview: _redLabel];
@@ -293,7 +392,9 @@
- (void)updateHex:(CPColor)aColor - (void)updateHex:(CPColor)aColor
{ {
[_hexValue setStringValue:[aColor hexString]]; #if PLATFORM(DOM)
_hexValue.value = [aColor hexString];
#endif
} }
- (void)updateRGBSliders:(CPColor)aColor - (void)updateRGBSliders:(CPColor)aColor
@@ -307,13 +408,15 @@
- (void)updateLabels - (void)updateLabels
{ {
[_hueValue setStringValue: ROUND([_hueSlider floatValue])]; #if PLATFORM(DOM)
[_saturationValue setStringValue: ROUND([_saturationSlider floatValue])]; _hueValue.value = ROUND([_hueSlider floatValue]);
[_brightnessValue setStringValue: ROUND([_brightnessSlider floatValue])]; _saturationValue.value = ROUND([_saturationSlider floatValue]);
_brightnessValue.value = ROUND([_brightnessSlider floatValue]);
[_redValue setStringValue: ROUND([_redSlider floatValue] * 255)]; _redValue.value = ROUND([_redSlider floatValue] * 255);
[_greenValue setStringValue: ROUND([_greenSlider floatValue] * 255)]; _greenValue.value = ROUND([_greenSlider floatValue] * 255);
[_blueValue setStringValue: ROUND([_blueSlider floatValue] * 255)]; _blueValue.value = ROUND([_blueSlider floatValue] * 255);
#endif
} }
- (CPImage)provideNewButtonImage - (CPImage)provideNewButtonImage
@@ -326,43 +429,4 @@
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:CPColorPicker] pathForResource:"slider_button_h.png"] size:CGSizeMake(32, 32)]; 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 @end
+32 -54
View File
@@ -24,6 +24,10 @@
@import "CPImage.j" @import "CPImage.j"
@import "CPView.j" @import "CPView.j"
#include "CoreGraphics/CGGeometry.h"
#include "Platform/Platform.h"
#include "Platform/DOM/CPDOMDisplayServer.h"
CPSplitViewDidResizeSubviewsNotification = @"CPSplitViewDidResizeSubviewsNotification"; CPSplitViewDidResizeSubviewsNotification = @"CPSplitViewDidResizeSubviewsNotification";
CPSplitViewWillResizeSubviewsNotification = @"CPSplitViewWillResizeSubviewsNotification"; CPSplitViewWillResizeSubviewsNotification = @"CPSplitViewWillResizeSubviewsNotification";
@@ -43,7 +47,6 @@ var CPSplitViewHorizontalImage = nil,
int _currentDivider; int _currentDivider;
float _initialOffset; float _initialOffset;
float _preCollapsePosition;
CPString _originComponent; CPString _originComponent;
CPString _sizeComponent; CPString _sizeComponent;
@@ -57,17 +60,6 @@ var CPSplitViewHorizontalImage = nil,
CPArray _buttonBars; CPArray _buttonBars;
} }
+ (CPString)defaultThemeClass
{
return @"splitview";
}
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[10.0, 1.0, [CPColor grayColor]]
forKeys:[@"divider-thickness", @"pane-divider-thickness", @"pane-divider-color"]];
}
/* /*
@ignore @ignore
*/ */
@@ -98,7 +90,7 @@ var CPSplitViewHorizontalImage = nil,
- (float)dividerThickness - (float)dividerThickness
{ {
return [self currentValueForThemeAttribute:[self isPaneSplitter] ? @"pane-divider-thickness" : @"divider-thickness"]; return _isPaneSplitter ? 1.0 : 10.0;
} }
- (BOOL)isVertical - (BOOL)isVertical
@@ -159,8 +151,8 @@ var CPSplitViewHorizontalImage = nil,
_isPaneSplitter = shouldBePaneSplitter; _isPaneSplitter = shouldBePaneSplitter;
if (_DOMDividerElements[_drawingDivider]) if(_DOMDividerElements[_drawingDivider])
[self _setupDOMDivider]; [self _setupDOMDivider]
// The divider changes size when pane splitter mode is toggled, so the // The divider changes size when pane splitter mode is toggled, so the
// subviews need to change size too. // subviews need to change size too.
@@ -193,8 +185,9 @@ var CPSplitViewHorizontalImage = nil,
- (CGRect)effectiveRectOfDividerAtIndex:(int)aDivider - (CGRect)effectiveRectOfDividerAtIndex:(int)aDivider
{ {
var realRect = [self rectOfDividerAtIndex:aDivider], var realRect = [self rectOfDividerAtIndex:aDivider];
padding = 2;
var padding = 2;
realRect.size[_sizeComponent] += padding * 2; realRect.size[_sizeComponent] += padding * 2;
realRect.origin[_originComponent] -= padding; realRect.origin[_originComponent] -= padding;
@@ -224,9 +217,10 @@ var CPSplitViewHorizontalImage = nil,
_DOMDividerElements[_drawingDivider].style.backgroundRepeat = "repeat"; _DOMDividerElements[_drawingDivider].style.backgroundRepeat = "repeat";
CPDOMDisplayServerAppendChild(_DOMElement, _DOMDividerElements[_drawingDivider]); CPDOMDisplayServerAppendChild(_DOMElement, _DOMDividerElements[_drawingDivider]);
[self _setupDOMDivider];
} }
[self _setupDOMDivider];
CPDOMDisplayServerSetStyleLeftTop(_DOMDividerElements[_drawingDivider], NULL, _CGRectGetMinX(aRect), _CGRectGetMinY(aRect)); CPDOMDisplayServerSetStyleLeftTop(_DOMDividerElements[_drawingDivider], NULL, _CGRectGetMinX(aRect), _CGRectGetMinY(aRect));
CPDOMDisplayServerSetStyleSize(_DOMDividerElements[_drawingDivider], _CGRectGetWidth(aRect), _CGRectGetHeight(aRect)); CPDOMDisplayServerSetStyleSize(_DOMDividerElements[_drawingDivider], _CGRectGetWidth(aRect), _CGRectGetHeight(aRect));
#endif #endif
@@ -236,7 +230,7 @@ var CPSplitViewHorizontalImage = nil,
{ {
if (_isPaneSplitter) if (_isPaneSplitter)
{ {
_DOMDividerElements[_drawingDivider].style.backgroundColor = [[self currentValueForThemeAttribute:@"pane-divider-color"] cssString]; _DOMDividerElements[_drawingDivider].style.backgroundColor = "#A5A5A5";
_DOMDividerElements[_drawingDivider].style.backgroundImage = ""; _DOMDividerElements[_drawingDivider].style.backgroundImage = "";
} }
else else
@@ -300,7 +294,7 @@ var CPSplitViewHorizontalImage = nil,
if ([_delegate respondsToSelector:@selector(splitView:additionalEffectiveRectOfDividerAtIndex:)]) if ([_delegate respondsToSelector:@selector(splitView:additionalEffectiveRectOfDividerAtIndex:)])
additionalRect = [_delegate splitView:self additionalEffectiveRectOfDividerAtIndex:anIndex]; additionalRect = [_delegate splitView:self additionalEffectiveRectOfDividerAtIndex:anIndex];
return CGRectContainsPoint(effectiveRect, aPoint) || return CGRectContainsPoint(effectiveRect, aPoint) ||
(additionalRect && CGRectContainsPoint(additionalRect, aPoint)) || (additionalRect && CGRectContainsPoint(additionalRect, aPoint)) ||
(buttonBarRect && CGRectContainsPoint(buttonBarRect, aPoint)); (buttonBarRect && CGRectContainsPoint(buttonBarRect, aPoint));
} }
@@ -310,9 +304,9 @@ var CPSplitViewHorizontalImage = nil,
if ([self isHidden] || ![self hitTests] || !CGRectContainsPoint([self frame], aPoint)) if ([self isHidden] || ![self hitTests] || !CGRectContainsPoint([self frame], aPoint))
return nil; return nil;
var point = [self convertPoint:aPoint fromView:[self superview]], var point = [self convertPoint:aPoint fromView:[self superview]];
count = [_subviews count] - 1;
var count = [_subviews count] - 1;
for (var i = 0; i < count; i++) for (var i = 0; i < count; i++)
{ {
if ([self cursorAtPoint:point hitDividerAtIndex:i]) if ([self cursorAtPoint:point hitDividerAtIndex:i])
@@ -365,14 +359,14 @@ var CPSplitViewHorizontalImage = nil,
if ([_delegate splitView:self canCollapseSubview:_subviews[i]] && [_delegate splitView:self shouldCollapseSubview:_subviews[i] forDoubleClickOnDividerAtIndex:i]) if ([_delegate splitView:self canCollapseSubview:_subviews[i]] && [_delegate splitView:self shouldCollapseSubview:_subviews[i] forDoubleClickOnDividerAtIndex:i])
{ {
if ([self isSubviewCollapsed:_subviews[i]]) if ([self isSubviewCollapsed:_subviews[i]])
[self setPosition:_preCollapsePosition ? _preCollapsePosition : (minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i]; [self setPosition:(minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i];
else else
[self setPosition:minPosition ofDividerAtIndex:i]; [self setPosition:minPosition ofDividerAtIndex:i];
} }
else if ([_delegate splitView:self canCollapseSubview:_subviews[i + 1]] && [_delegate splitView:self shouldCollapseSubview:_subviews[i + 1] forDoubleClickOnDividerAtIndex: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]]) if ([self isSubviewCollapsed:_subviews[i+1]])
[self setPosition:_preCollapsePosition ? _preCollapsePosition : (minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i]; [self setPosition:(minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i];
else else
[self setPosition:maxPosition ofDividerAtIndex:i]; [self setPosition:maxPosition ofDividerAtIndex:i];
} }
@@ -451,19 +445,11 @@ var CPSplitViewHorizontalImage = nil,
if (_currentDivider === i || (_currentDivider == CPNotFound && [self cursorAtPoint:point hitDividerAtIndex:i])) if (_currentDivider === i || (_currentDivider == CPNotFound && [self cursorAtPoint:point hitDividerAtIndex:i]))
{ {
var frame = [_subviews[i] frame], var frame = [_subviews[i] frame],
size = frame.size[_sizeComponent], startPosition = frame.origin[_originComponent] + frame.size[_sizeComponent],
startPosition = frame.origin[_originComponent] + size, canShrink = [self _realPositionForPosition:startPosition-1 ofDividerAtIndex:i] < startPosition,
canShrink = [self _realPositionForPosition:startPosition - 1 ofDividerAtIndex:i] < startPosition, canGrow = [self _realPositionForPosition:startPosition+1 ofDividerAtIndex:i] > startPosition,
canGrow = [self _realPositionForPosition:startPosition + 1 ofDividerAtIndex:i] > startPosition,
cursor = [CPCursor arrowCursor]; 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) if (_isVertical && canShrink && canGrow)
cursor = [CPCursor resizeLeftRightCursor]; cursor = [CPCursor resizeLeftRightCursor];
else if (_isVertical && canShrink) else if (_isVertical && canShrink)
@@ -518,10 +504,10 @@ var CPSplitViewHorizontalImage = nil,
actualMax = proposedMax, actualMax = proposedMax,
actualMin = proposedMin; actualMin = proposedMin;
if ([_delegate respondsToSelector:@selector(splitView:constrainMinCoordinate:ofSubviewAt:)]) if([_delegate respondsToSelector:@selector(splitView:constrainMinCoordinate:ofSubviewAt:)])
actualMin = [_delegate splitView:self constrainMinCoordinate:proposedMin ofSubviewAt:dividerIndex]; actualMin = [_delegate splitView:self constrainMinCoordinate:proposedMin ofSubviewAt:dividerIndex];
if ([_delegate respondsToSelector:@selector(splitView:constrainMaxCoordinate:ofSubviewAt:)]) if([_delegate respondsToSelector:@selector(splitView:constrainMaxCoordinate:ofSubviewAt:)])
actualMax = [_delegate splitView:self constrainMaxCoordinate:proposedMax ofSubviewAt:dividerIndex]; actualMax = [_delegate splitView:self constrainMaxCoordinate:proposedMax ofSubviewAt:dividerIndex];
var viewA = _subviews[dividerIndex], var viewA = _subviews[dividerIndex],
@@ -546,18 +532,10 @@ var CPSplitViewHorizontalImage = nil,
viewB = _subviews[dividerIndex + 1], viewB = _subviews[dividerIndex + 1],
frameB = [viewB frame]; frameB = [viewB frame];
_preCollapsePosition = 0;
var preSize = frameA.size[_sizeComponent];
frameA.size[_sizeComponent] = realPosition - frameA.origin[_originComponent]; frameA.size[_sizeComponent] = realPosition - frameA.origin[_originComponent];
if (preSize !== 0 && frameA.size[_sizeComponent] === 0)
_preCollapsePosition = preSize;
[_subviews[dividerIndex] setFrame:frameA]; [_subviews[dividerIndex] setFrame:frameA];
preSize = frameB.size[_sizeComponent];
frameB.size[_sizeComponent] = frameB.origin[_originComponent] + frameB.size[_sizeComponent] - realPosition - [self dividerThickness]; 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]; frameB.origin[_originComponent] = realPosition + [self dividerThickness];
[_subviews[dividerIndex + 1] setFrame:frameB]; [_subviews[dividerIndex + 1] setFrame:frameB];
@@ -612,8 +590,8 @@ var CPSplitViewHorizontalImage = nil,
var nonSizableSpace = totalSizableSpace ? bounds.size[_sizeComponent] - totalSizableSpace : 0, var nonSizableSpace = totalSizableSpace ? bounds.size[_sizeComponent] - totalSizableSpace : 0,
remainingFlexibleSpace = bounds.size[_sizeComponent] - oldSize[_sizeComponent], remainingFlexibleSpace = bounds.size[_sizeComponent] - oldSize[_sizeComponent],
oldDimension = (oldSize[_sizeComponent] - totalDividers * dividerThickness - nonSizableSpace), oldDimension = (oldSize[_sizeComponent]- totalDividers*dividerThickness - nonSizableSpace),
ratio = oldDimension <= 0 ? 0 : (bounds.size[_sizeComponent] - totalDividers * dividerThickness - nonSizableSpace) / oldDimension; ratio = oldDimension <= 0 ? 0 : (bounds.size[_sizeComponent] - totalDividers*dividerThickness - nonSizableSpace) / oldDimension;
for (index = 0; index < count; ++index) for (index = 0; index < count; ++index)
{ {
@@ -664,14 +642,14 @@ var CPSplitViewHorizontalImage = nil,
/*! /*!
Set the button bar who's resize control should act as a control for this splitview. 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. 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 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 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. 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. parameters of the button bar, and will override any currently set values.
*/ */
- (void)setButtonBar:(CPButtonBar)aButtonBar forDividerAtIndex:(unsigned)dividerIndex - (void)setButtonBar:(CPButtonBar)aButtonBar forDividerAtIndex:(unsigned)dividerIndex
@@ -692,7 +670,7 @@ var CPSplitViewHorizontalImage = nil,
} }
if (view !== self) if (view !== self)
[CPException raise:CPInvalidArgumentException [CPException raise:CPInvalidArgumentException
reason:@"CPSplitView button bar must be a subview of the split view."]; reason:@"CPSplitView button bar must be a subview of the split view."];
var viewIndex = [[self subviews] indexOfObject:subview]; var viewIndex = [[self subviews] indexOfObject:subview];
@@ -700,7 +678,7 @@ var CPSplitViewHorizontalImage = nil,
[aButtonBar setHasResizeControl:YES]; [aButtonBar setHasResizeControl:YES];
[aButtonBar setResizeControlIsLeftAligned:dividerIndex < viewIndex]; [aButtonBar setResizeControlIsLeftAligned:dividerIndex < viewIndex];
_buttonBars[dividerIndex] = aButtonBar; _buttonBars[dividerIndex] = aButtonBar;
} }
- (void)_postNotificationWillResize - (void)_postNotificationWillResize
@@ -737,7 +715,7 @@ var CPSplitViewDelegateKey = "CPSplitViewDelegateKey",
_DOMDividerElements = []; _DOMDividerElements = [];
_buttonBars = [aCoder decodeObjectForKey:CPSplitViewButtonBarsKey] || []; _buttonBars = [aCoder decodeObjectForKey:CPSplitViewButtonBarsKey] || [];
_delegate = [aCoder decodeObjectForKey:CPSplitViewDelegateKey]; _delegate = [aCoder decodeObjectForKey:CPSplitViewDelegateKey];
_isPaneSplitter = [aCoder decodeBoolForKey:CPSplitViewIsPaneSplitterKey]; _isPaneSplitter = [aCoder decodeBoolForKey:CPSplitViewIsPaneSplitterKey];
+1 -25
View File
@@ -25,20 +25,8 @@
@import "CPPlatformString.j" @import "CPPlatformString.j"
var CPStringSizeWithFontInWidthCache = {};
CPStringSizeCachingEnabled = YES;
@implementation CPString (CPStringDrawing) @implementation CPString (CPStringDrawing)
/*!
Returns a dictionary with the items "ascender", "descender", "lineHeight"
*/
+ (CPDictionary)metricsOfFont:(CPFont)aFont
{
return [CPPlatformString metricsOfFont:aFont];
}
/*! /*!
Returns the string Returns the string
*/ */
@@ -54,19 +42,7 @@ CPStringSizeCachingEnabled = YES;
- (CGSize)sizeWithFont:(CPFont)aFont inWidth:(float)aWidth - (CGSize)sizeWithFont:(CPFont)aFont inWidth:(float)aWidth
{ {
if (!CPStringSizeCachingEnabled) return [CPPlatformString sizeOfString:self withFont:aFont forWidth:aWidth];
return [CPPlatformString sizeOfString:self withFont:aFont forWidth:aWidth];
var cacheKey = self + [aFont cssString] + aWidth,
size = CPStringSizeWithFontInWidthCache[cacheKey];
if (size === undefined)
{
size = [CPPlatformString sizeOfString:self withFont:aFont forWidth:aWidth];
CPStringSizeWithFontInWidthCache[cacheKey] = size;
}
return CGSizeMakeCopy(size);
} }
@end @end
+553 -202
View File
@@ -1,8 +1,32 @@
@import "CPBox.j" /*
@import "CPSegmentedControl.j" * CPTabView.j
* AppKit
*
* Created by Francisco Tolmasky.
* Copyright 2008, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPImageView.j"
@import "CPTabViewItem.j" @import "CPTabViewItem.j"
@import "CPView.j" @import "CPView.j"
#include "CoreGraphics/CGGeometry.h"
/* /*
Places tabs on top with a bezeled border. Places tabs on top with a bezeled border.
@global @global
@@ -10,7 +34,7 @@
*/ */
CPTopTabsBezelBorder = 0; CPTopTabsBezelBorder = 0;
//CPLeftTabsBezelBorder = 1; //CPLeftTabsBezelBorder = 1;
CPBottomTabsBezelBorder = 2; //CPBottomTabsBezelBorder = 2;
//CPRightTabsBezelBorder = 3; //CPRightTabsBezelBorder = 3;
/* /*
Displays no tabs and has a bezeled border. Displays no tabs and has a bezeled border.
@@ -31,55 +55,173 @@ CPNoTabsLineBorder = 5;
*/ */
CPNoTabsNoBorder = 6; CPNoTabsNoBorder = 6;
var CPTabViewBezelBorderLeftImage = nil,
CPTabViewBackgroundCenterImage = nil,
CPTabViewBezelBorderRightImage = nil,
CPTabViewBezelBorderColor = nil,
CPTabViewBezelBorderBackgroundColor = nil;
var LEFT_INSET = 7.0,
RIGHT_INSET = 7.0;
var CPTabViewDidSelectTabViewItemSelector = 1, var CPTabViewDidSelectTabViewItemSelector = 1,
CPTabViewShouldSelectTabViewItemSelector = 2, CPTabViewShouldSelectTabViewItemSelector = 2,
CPTabViewWillSelectTabViewItemSelector = 4, CPTabViewWillSelectTabViewItemSelector = 4,
CPTabViewDidChangeNumberOfTabViewItemsSelector = 8; CPTabViewDidChangeNumberOfTabViewItemsSelector = 8;
var HEIGHT_OF_SEGMENTED_CONTROL = 24; /*!
@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 @implementation CPTabView : CPView
{ {
CPArray items; CPView _labelsView;
CPView _backgroundView;
CPView _separatorView;
CPView _auxiliaryView;
CPView _contentView;
CPArray _tabViewItems;
CPTabViewItem _selectedTabViewItem;
CPSegmentedControl tabs; CPTabViewType _tabViewType;
CPBox box;
id _delegate;
unsigned _delegateSelectors;
}
CPNumber selectedIndex; /*
@ignore
*/
+ (void)initialize
{
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,
CPTabViewType type; bezelBorderLeftImage,
backgroundImage,
bezelBorderRightImage,
id delegate; bezelBorderLeftImage,
unsigned delegateSelectors; bezerBorderImage,
bezelBorderRightImage
]]];
CPTabViewBezelBorderColor = [CPColor colorWithPatternImage:bezerBorderImage];
}
/*
@ignore
*/
+ (CPColor)bezelBorderColor
{
return CPTabViewBezelBorderColor;
} }
- (id)initWithFrame:(CGRect)aFrame - (id)initWithFrame:(CGRect)aFrame
{ {
self = [super initWithFrame:aFrame]; self = [super initWithFrame:aFrame];
if (self) if (self)
{ {
items = [CPArray array]; _tabViewType = CPTopTabsBezelBorder;
_tabViewItems = [];
tabs = [[CPSegmentedControl alloc] initWithFrame:CGRectMake(0, 0, 0, HEIGHT_OF_SEGMENTED_CONTROL)];
[tabs setHitTests:NO];
box = [[CPBox alloc] initWithFrame:CGRectMake(0, HEIGHT_OF_SEGMENTED_CONTROL / 2, CGRectGetWidth(aFrame),
CGRectGetHeight(aFrame) - HEIGHT_OF_SEGMENTED_CONTROL)];
selectedIndex = CPNotFound;
[self setTabViewType:CPTopTabsBezelBorder];
[self setBackgroundColor:[CPColor colorWithCalibratedWhite:0.95 alpha:1.0]];
[self addSubview:box];
[self addSubview:tabs];
[box setAutoresizingMask:CPViewWidthSizable];
[tabs setAutoresizingMask:CPViewMinXMargin | CPViewMaxXMargin];
} }
return self; return self;
} }
- (void)viewDidMoveToWindow
{
if (_tabViewType != CPTopTabsBezelBorder || _labelsView)
return;
[self _createBezelBorder];
[self layoutSubviews];
}
/* @ignore */
- (void)_createBezelBorder
{
var bounds = [self bounds];
_labelsView = [[_CPTabLabelsView alloc] initWithFrame:CGRectMake(0.0, 0.0, CGRectGetWidth(bounds), 0.0)];
[_labelsView setTabView:self];
[_labelsView setAutoresizingMask:CPViewWidthSizable];
[self addSubview:_labelsView];
_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];
}
/*
Lays out the subviews
@ignore
*/
- (void)layoutSubviews
{
if (_tabViewType == CPTopTabsBezelBorder)
{
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)];
}
// CPNoTabsNoBorder
[_contentView setFrame:[self contentRect]];
}
// Adding and Removing Tabs // Adding and Removing Tabs
/*! /*!
Adds a CPTabViewItem to the tab view. Adds a CPTabViewItem to the tab view.
@@ -87,7 +229,7 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
*/ */
- (void)addTabViewItem:(CPTabViewItem)aTabViewItem - (void)addTabViewItem:(CPTabViewItem)aTabViewItem
{ {
[self insertTabViewItem:aTabViewItem atIndex:[items count]]; [self insertTabViewItem:aTabViewItem atIndex:[_tabViewItems count]];
} }
/*! /*!
@@ -98,13 +240,20 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
*/ */
- (void)insertTabViewItem:(CPTabViewItem)aTabViewItem atIndex:(unsigned)anIndex - (void)insertTabViewItem:(CPTabViewItem)aTabViewItem atIndex:(unsigned)anIndex
{ {
[items insertObject:aTabViewItem atIndex:anIndex]; if (!_labelsView && _tabViewType == CPTopTabsBezelBorder)
[self _createBezelBorder];
[_tabViewItems insertObject:aTabViewItem atIndex:anIndex];
[_labelsView tabView:self didAddTabViewItem:aTabViewItem];
[aTabViewItem _setTabView:self];
if ([_tabViewItems count] == 1)
[self selectFirstTabViewItem:self];
[self _updateItems]; if (_delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
[self _repositionTabs]; [_delegate tabViewDidChangeNumberOfTabViewItems:self];
if (delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
[delegate tabViewDidChangeNumberOfTabViewItems:self];
} }
/*! /*!
@@ -113,19 +262,16 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
*/ */
- (void)removeTabViewItem:(CPTabViewItem)aTabViewItem - (void)removeTabViewItem:(CPTabViewItem)aTabViewItem
{ {
for (var i = 0; i < [items count]; i++) var index = [self indexOfTabViewItem:aTabViewItem];
{
if ([items objectAtIndex:i] === aTabViewItem)
{
[items removeObjectAtIndex:i];
}
}
[self _updateItems]; [_tabViewItems removeObjectIdenticalTo:aTabViewItem];
[self _repositionTabs];
[_labelsView tabView:self didRemoveTabViewItemAtIndex:index];
if (delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
[delegate tabViewDidChangeNumberOfTabViewItems:self]; [aTabViewItem _setTabView:nil];
if (_delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
[_delegate tabViewDidChangeNumberOfTabViewItems:self];
} }
// Accessing Tabs // Accessing Tabs
@@ -135,7 +281,7 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
*/ */
- (int)indexOfTabViewItem:(CPTabViewItem)aTabViewItem - (int)indexOfTabViewItem:(CPTabViewItem)aTabViewItem
{ {
return [items indexOfObjectIdenticalTo:aTabViewItem]; return [_tabViewItems indexOfObjectIdenticalTo:aTabViewItem];
} }
/*! /*!
@@ -144,11 +290,14 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
*/ */
- (int)indexOfTabViewItemWithIdentifier:(CPString)anIdentifier - (int)indexOfTabViewItemWithIdentifier:(CPString)anIdentifier
{ {
for (var index = [items count]; index >= 0; index--) var index = 0,
if ([[items[index] identifier] isEqual:anIdentifier]) count = [_tabViewItems count];
for (; index < count; ++index)
if ([[_tabViewItems[index] identifier] isEqual:anIdentifier])
return index; return index;
return CPNotFound; return index;
} }
/*! /*!
@@ -156,7 +305,7 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
*/ */
- (unsigned)numberOfTabViewItems - (unsigned)numberOfTabViewItems
{ {
return [items count]; return [_tabViewItems count];
} }
/*! /*!
@@ -164,7 +313,7 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
*/ */
- (CPTabViewItem)tabViewItemAtIndex:(unsigned)anIndex - (CPTabViewItem)tabViewItemAtIndex:(unsigned)anIndex
{ {
return [items objectAtIndex:anIndex]; return _tabViewItems[anIndex];
} }
/*! /*!
@@ -172,7 +321,7 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
*/ */
- (CPArray)tabViewItems - (CPArray)tabViewItems
{ {
return [items copy]; // Copy? return _tabViewItems;
} }
// Selecting a Tab // Selecting a Tab
@@ -182,10 +331,10 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
*/ */
- (void)selectFirstTabViewItem:(id)aSender - (void)selectFirstTabViewItem:(id)aSender
{ {
if ([items count] === 0) var count = [_tabViewItems count];
return; // throw?
if (count)
[self selectTabViewItemAtIndex:0]; [self selectTabViewItemAtIndex:0];
} }
/*! /*!
@@ -194,10 +343,10 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
*/ */
- (void)selectLastTabViewItem:(id)aSender - (void)selectLastTabViewItem:(id)aSender
{ {
if ([items count] === 0) var count = [_tabViewItems count];
return; // throw?
if (count)
[self selectTabViewItemAtIndex:[items count] - 1]; [self selectTabViewItemAtIndex:count - 1];
} }
/*! /*!
@@ -206,16 +355,13 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
*/ */
- (void)selectNextTabViewItem:(id)aSender - (void)selectNextTabViewItem:(id)aSender
{ {
if (selectedIndex === CPNotFound) if (!_selectedTabViewItem)
return; return;
var nextIndex = selectedIndex + 1; var index = [self indexOfTabViewItem:_selectedTabViewItem],
count = [_tabViewItems count];
if (nextIndex === [items count])
// does nothing. According to spec at (http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Reference/ApplicationKit/Classes/NSTabView_Class/Reference/Reference.html#//apple_ref/occ/instm/NSTabView/selectNextTabViewItem:) [self selectTabViewItemAtIndex:index + 1 % count];
return;
[self selectTabViewItemAtIndex:nextIndex];
} }
/*! /*!
@@ -224,15 +370,13 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
*/ */
- (void)selectPreviousTabViewItem:(id)aSender - (void)selectPreviousTabViewItem:(id)aSender
{ {
if (selectedIndex === CPNotFound) if (!_selectedTabViewItem)
return; return;
var previousIndex = selectedIndex - 1; var index = [self indexOfTabViewItem:_selectedTabViewItem],
count = [_tabViewItems count];
if (previousIndex < 0)
return; // does nothing. See above. [self selectTabViewItemAtIndex:index == 0 ? count : index - 1];
[self selectTabViewItemAtIndex:previousIndex];
} }
/*! /*!
@@ -241,7 +385,41 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
*/ */
- (void)selectTabViewItem:(CPTabViewItem)aTabViewItem - (void)selectTabViewItem:(CPTabViewItem)aTabViewItem
{ {
[self selectTabViewItemAtIndex:[self indexOfTabViewItem:aTabViewItem]]; if ((_delegateSelectors & CPTabViewShouldSelectTabViewItemSelector) && ![_delegate tabView:self shouldSelectTabViewItem:aTabViewItem])
return;
if (_delegateSelectors & CPTabViewWillSelectTabViewItemSelector)
[_delegate tabView:self willSelectTabViewItem:aTabViewItem];
if (_selectedTabViewItem)
{
_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)
[self addSubview:_auxiliaryView];
[_labelsView tabView:self didChangeStateOfTabViewItem:_selectedTabViewItem];
[self layoutSubviews];
if (_delegateSelectors & CPTabViewDidSelectTabViewItemSelector)
[_delegate tabView:self didSelectTabViewItem:aTabViewItem];
} }
/*! /*!
@@ -250,24 +428,7 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
*/ */
- (void)selectTabViewItemAtIndex:(unsigned)anIndex - (void)selectTabViewItemAtIndex:(unsigned)anIndex
{ {
var aTabViewItem = [items objectAtIndex:anIndex]; [self selectTabViewItem:_tabViewItems[anIndex]];
if (anIndex === selectedIndex)
return;
var aTabViewItem = [self tabViewItemAtIndex:anIndex];
if ((delegateSelectors & CPTabViewShouldSelectTabViewItemSelector) && ![delegate tabView:self shouldSelectTabViewItem:aTabViewItem])
return;
if (delegateSelectors & CPTabViewWillSelectTabViewItemSelector)
[delegate tabView:self willSelectTabViewItem:aTabViewItem];
[tabs selectSegmentWithTag:anIndex];
[self _setSelectedIndex:anIndex];
if (delegateSelectors & CPTabViewDidSelectTabViewItemSelector)
[delegate tabView:self didSelectTabViewItem:aTabViewItem];
} }
/*! /*!
@@ -275,43 +436,32 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
*/ */
- (CPTabViewItem)selectedTabViewItem - (CPTabViewItem)selectedTabViewItem
{ {
return [items objectAtIndex:selectedIndex]; return _selectedTabViewItem;
} }
// //
/*! /*!
Sets the tab view type. Sets the tab view type.
@param aTabViewType the view type @param aTabViewType the view type
*/ */
- (void)setTabViewType:(CPTabViewType)aTabViewType - (void)setTabViewType:(CPTabViewType)aTabViewType
{ {
if (type === aTabViewType) if (_tabViewType == aTabViewType)
return; return;
if ((type === CPTopTabsBezelBorder || type === CPBottomTabsBezelBorder) _tabViewType = aTabViewType;
&& (aTabViewType !== CPTopTabsBezelBorder && aTabViewType !== CPBottomTabsBezelBorder))
[tabs removeFromSuperview]; if (_tabViewType == CPNoTabsBezelBorder || _tabViewType == CPNoTabsLineBorder || _tabViewType == CPNoTabsNoBorder)
[_labelsView removeFromSuperview];
if ((type === CPNoTabsBezelBorder || type === CPNoTabsLineBorder || type === CPNoTabsNoBorder) else if (![_labelsView superview])
&& (aTabViewType !== CPNoTabsBezelBorder && aTabViewType !== CPNoTabsBezelBorder && aTabViewType !== CPNoTabsNoBorder)) [self addSubview:_labelsView];
[self addSubview:tabs];
if (_tabViewType == CPNoTabsLineBorder || _tabViewType == CPNoTabsNoBorder)
type = aTabViewType; [_backgroundView removeFromSuperview];
else if (![_backgroundView superview])
switch (type) [self addSubview:_backgroundView];
{
case CPTopTabsBezelBorder: [self layoutSubviews];
case CPBottomTabsBezelBorder:
case CPNoTabsBezelBorder:
[box setBorderType:CPBezelBorder];
break;
case CPNoTabsLineBorder:
[box setBorderType:CPLineBorder];
break;
case CPNoTabsNoBorder:
[box setBorderType:CPNoBorder];
break;
}
} }
/*! /*!
@@ -319,7 +469,31 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
*/ */
- (CPTabViewType)tabViewType - (CPTabViewType)tabViewType
{ {
return type; return _tabViewType;
}
// Determining the Size
/*!
Returns the content rectangle.
*/
- (CGRect)contentRect
{
var contentRect = CGRectMakeCopy([self bounds]);
if (_tabViewType == CPTopTabsBezelBorder)
{
var labelsViewHeight = [_CPTabLabelsView height],
auxiliaryViewHeight = _auxiliaryView ? CGRectGetHeight([_auxiliaryView frame]) : 5.0,
separatorViewHeight = 1.0;
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;
}
return contentRect;
} }
/*! /*!
@@ -327,7 +501,7 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
*/ */
- (id)delegate - (id)delegate
{ {
return delegate; return _delegate;
} }
/*! /*!
@@ -336,74 +510,35 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
*/ */
- (void)setDelegate:(id)aDelegate - (void)setDelegate:(id)aDelegate
{ {
if (delegate == aDelegate) if (_delegate == aDelegate)
return; return;
_delegate = aDelegate;
_delegateSelectors = 0;
delegate = aDelegate; if ([_delegate respondsToSelector:@selector(tabView:shouldSelectTabViewItem:)])
_delegateSelectors |= CPTabViewShouldSelectTabViewItemSelector;
delegateSelectors = 0; if ([_delegate respondsToSelector:@selector(tabView:willSelectTabViewItem:)])
_delegateSelectors |= CPTabViewWillSelectTabViewItemSelector;
if ([delegate respondsToSelector:@selector(tabView:shouldSelectTabViewItem:)]) if ([_delegate respondsToSelector:@selector(tabView:didSelectTabViewItem:)])
delegateSelectors |= CPTabViewShouldSelectTabViewItemSelector; _delegateSelectors |= CPTabViewDidSelectTabViewItemSelector;
if ([delegate respondsToSelector:@selector(tabView:willSelectTabViewItem:)]) if ([_delegate respondsToSelector:@selector(tabViewDidChangeNumberOfTabViewItems:)])
delegateSelectors |= CPTabViewWillSelectTabViewItemSelector; _delegateSelectors |= CPTabViewDidChangeNumberOfTabViewItemsSelector;
if ([delegate respondsToSelector:@selector(tabView:didSelectTabViewItem:)])
delegateSelectors |= CPTabViewDidSelectTabViewItemSelector;
if ([delegate respondsToSelector:@selector(tabViewDidChangeNumberOfTabViewItems:)])
delegateSelectors |= CPTabViewDidChangeNumberOfTabViewItemsSelector;
} }
- (void)setBackgroundColor:(CPColor)aColor //
{
[box setBackgroundColor:aColor];
}
- (void)mouseDown:(CPEvent)anEvent - (void)mouseDown:(CPEvent)anEvent
{ {
var segmentIndex = [tabs testSegment:[tabs convertPoint:[anEvent locationInWindow] fromView:nil]]; var location = [_labelsView convertPoint:[anEvent locationInWindow] fromView:nil],
tabViewItem = [_labelsView representedTabViewItemAtPoint:location];
if (segmentIndex != CPNotFound)
{ if (tabViewItem)
[self selectTabViewItemAtIndex:segmentIndex]; [self selectTabViewItem:tabViewItem];
[tabs trackSegment:anEvent];
}
}
- (void)_repositionTabs
{
var horizontalCenterOfSelf = CGRectGetWidth([self bounds]) / 2,
verticalCenterOfTabs = CGRectGetHeight([tabs bounds]) / 2;
if (type === CPBottomTabsBezelBorder)
[tabs setCenter:CGPointMake(horizontalCenterOfSelf, CGRectGetHeight([self bounds]) - verticalCenterOfTabs)];
else
[tabs setCenter:CGPointMake(horizontalCenterOfSelf, verticalCenterOfTabs)];
}
- (void)_setSelectedIndex:(CPNumber)index
{
selectedIndex = index;
[box setContentView:[[items objectAtIndex:selectedIndex] view]];
}
- (void)_updateItems
{
[tabs setSegmentCount:[items count]];
for (var i = 0; i < [items count]; i++)
{
[tabs setLabel:[[items objectAtIndex:i] label] forSegment:i];
[tabs setTag:i forSegment:i];
}
if (selectedIndex === CPNotFound)
{
[self selectFirstTabViewItem:self];
}
} }
@end @end
@@ -419,17 +554,20 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
{ {
if (self = [super initWithCoder:aCoder]) if (self = [super initWithCoder:aCoder])
{ {
type = [aCoder decodeIntForKey:CPTabViewTypeKey]; _tabViewType = [aCoder decodeIntForKey:CPTabViewTypeKey];
items = []; _tabViewItems = [];
var encodedItems = [aCoder decodeObjectForKey:CPTabViewItemsKey]; // FIXME: this is somewhat hacky
for (var i = 0; encodedItems && i < encodedItems.length; i++) [self _createBezelBorder];
[self insertTabViewItem:encodedItems[i] atIndex:i];
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]; var selected = [aCoder decodeObjectForKey:CPTabViewSelectedItemKey];
if (selected) if (selected)
[self selectTabViewItem:selected]; [self selectTabViewItem:selected];
[self setDelegate:[aCoder decodeObjectForKey:CPTabViewDelegateKey]]; [self setDelegate:[aCoder decodeObjectForKey:CPTabViewDelegateKey]];
} }
@@ -438,14 +576,227 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
- (void)encodeWithCoder:(CPCoder)aCoder - (void)encodeWithCoder:(CPCoder)aCoder
{ {
var actualSubviews = _subviews;
_subviews = [];
[super encodeWithCoder:aCoder]; [super encodeWithCoder:aCoder];
_subviews = actualSubviews;
[aCoder encodeObject:items forKey:CPTabViewItemsKey];;
[aCoder encodeObject:[self selectedTabViewItem] forKey:CPTabViewSelectedItemKey]; [aCoder encodeObject:_tabViewItems forKey:CPTabViewItemsKey];;
[aCoder encodeObject:_selectedTabViewItem forKey:CPTabViewSelectedItemKey];
[aCoder encodeInt:type forKey:CPTabViewTypeKey];
[aCoder encodeInt:_tabViewType forKey:CPTabViewTypeKey];
[aCoder encodeConditionalObject:delegate forKey:CPTabViewDelegateKey];
[aCoder encodeConditionalObject:_delegate forKey:CPTabViewDelegateKey];
}
@end
var _CPTabLabelsViewBackgroundColor = nil,
_CPTabLabelsViewInsideMargin = 10.0,
_CPTabLabelsViewOutsideMargin = 15.0;
/* @ignore */
@implementation _CPTabLabelsView : CPView
{
CPTabView _tabView;
CPDictionary _tabLabels;
}
+ (void)initialize
{
if (self != [_CPTabLabelsView class])
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)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelsViewCenter.png"] size:CGSizeMake(1.0, 26.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelsViewRight.png"] size:CGSizeMake(12.0, 26.0)]
] isVertical:NO]];
}
+ (float)height
{
return 26.0;
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
_tabLabels = [];
[self setBackgroundColor:_CPTabLabelsViewBackgroundColor];
[self setFrameSize:CGSizeMake(CGRectGetWidth(aFrame), 26.0)];
}
return self;
}
- (void)setTabView:(CPTabView)aTabView
{
_tabView = aTabView;
}
- (CPTabView)tabView
{
return _tabView;
}
- (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];
}
-(void)tabView:(CPTabView)aTabView didChangeStateOfTabViewItem:(CPTabViewItem)aTabViewItem
{
[_tabLabels[[aTabView indexOfTabViewItem:aTabViewItem]] setTabState:[aTabViewItem tabState]];
}
- (CPTabViewItem)representedTabViewItemAtPoint:(CGPoint)aPoint
{
var index = 0,
count = _tabLabels.length;
for (; index < count; ++index)
{
var label = _tabLabels[index];
if (CGRectContainsPoint([label frame], aPoint))
return [label tabViewItem];
}
return nil;
}
- (void)layoutSubviews
{
var index = 0,
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;
}
}
- (void)setFrameSize:(CGSize)aSize
{
if (CGSizeEqualToSize([self frame].size, aSize))
return;
[super setFrameSize:aSize];
[self layoutSubviews];
}
@end
var _CPTabLabelBackgroundColor = nil,
_CPTabLabelSelectedBackgroundColor = nil;
/* @ignore */
@implementation _CPTabLabel : CPView
{
CPTabViewItem _tabViewItem;
CPTextField _labelField;
}
+ (void)initialize
{
if (self != [_CPTabLabel class])
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)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelSelectedCenter.png"] size:CGSizeMake(1.0, 18.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelSelectedRight.png"] size:CGSizeMake(3.0, 18.0)]
] isVertical:NO]];
}
- (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;
}
- (void)setTabState:(CPTabState)aTabState
{
[self setBackgroundColor:aTabState == CPSelectedTab ? _CPTabLabelSelectedBackgroundColor : _CPTabLabelBackgroundColor];
}
- (void)setTabViewItem:(CPTabViewItem)aTabViewItem
{
_tabViewItem = aTabViewItem;
[self update];
}
- (CPTabViewItem)tabViewItem
{
return _tabViewItem;
}
- (void)update
{
[_labelField setStringValue:[_tabViewItem label]];
} }
@end @end
+1 -1
View File
@@ -22,7 +22,7 @@
@import <Foundation/CPObject.j> @import <Foundation/CPObject.j>
@import "CPView.j" @import <AppKit/CPView.j>
/* /*
+28 -112
View File
@@ -22,12 +22,12 @@
@import <Foundation/CPDictionary.j> @import <Foundation/CPDictionary.j>
@import <Foundation/CPObject.j> @import <Foundation/CPObject.j>
@import <Foundation/CPIndexSet.j>
@import <Foundation/CPSortDescriptor.j> @import <Foundation/CPSortDescriptor.j>
@import <Foundation/CPString.j> @import <Foundation/CPString.j>
@import "CPTableHeaderView.j" @import "CPTableHeaderView.j"
#include "CoreGraphics/CGGeometry.h"
CPTableColumnNoResizing = 0; CPTableColumnNoResizing = 0;
CPTableColumnAutoresizingMask = 1 << 0; CPTableColumnAutoresizingMask = 1 << 0;
@@ -50,7 +50,7 @@ CPTableColumnUserResizingMask = 1 << 1;
CPSortDescriptor _sortDescriptorPrototype; CPSortDescriptor _sortDescriptorPrototype;
BOOL _isHidden; BOOL _isHidden;
CPString _headerToolTip; CPString _headerToolTip;
BOOL _disableResizingPosting @accessors(property=disableResizingPosting); BOOL _disableResizingPosting @accessors(property=disableResizingPosting);
} }
@@ -72,13 +72,19 @@ CPTableColumnUserResizingMask = 1 << 1;
_maxWidth = 1000000.0; _maxWidth = 1000000.0;
_resizingMask = CPTableColumnAutoresizingMask | CPTableColumnUserResizingMask; _resizingMask = CPTableColumnAutoresizingMask | CPTableColumnUserResizingMask;
_disableResizingPosting = NO; _disableResizingPosting = NO;
[self setIdentifier:anIdentifier]; [self setIdentifier:anIdentifier];
var header = [[_CPTableColumnHeaderView alloc] initWithFrame:CGRectMakeZero()]; var header = [[_CPTableColumnHeaderView alloc] initWithFrame:CGRectMakeZero()];
[self setHeaderView:header]; [self setHeaderView:header];
[self setDataView:[CPTextField new]]; var textDataView = [CPTextField new];
[textDataView setLineBreakMode:CPLineBreakByTruncatingTail];
[textDataView setValue:[CPColor colorWithHexString:@"333333"] forThemeAttribute:@"text-color"];
[textDataView setValue:[CPColor whiteColor] forThemeAttribute:@"text-color" inState:CPThemeStateSelected];
[textDataView setValue:[CPFont boldSystemFontOfSize:12] forThemeAttribute:@"font" inState:CPThemeStateSelected];
[textDataView setValue:CPCenterVerticalTextAlignment forThemeAttribute:@"vertical-alignment"];
[self setDataView:textDataView];
} }
return self; return self;
@@ -117,19 +123,19 @@ CPTableColumnUserResizingMask = 1 << 1;
{ {
var index = [[tableView tableColumns] indexOfObjectIdenticalTo:self], var index = [[tableView tableColumns] indexOfObjectIdenticalTo:self],
dirtyTableColumnRangeIndex = tableView._dirtyTableColumnRangeIndex; dirtyTableColumnRangeIndex = tableView._dirtyTableColumnRangeIndex;
if (dirtyTableColumnRangeIndex < 0) if (dirtyTableColumnRangeIndex < 0)
tableView._dirtyTableColumnRangeIndex = index; tableView._dirtyTableColumnRangeIndex = index;
else else
tableView._dirtyTableColumnRangeIndex = MIN(index, tableView._dirtyTableColumnRangeIndex); tableView._dirtyTableColumnRangeIndex = MIN(index, tableView._dirtyTableColumnRangeIndex);
var rows = tableView._exposedRows, var rows = tableView._exposedRows,
columns = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(index, [tableView._exposedColumns lastIndex] - index + 1)]; columns = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(index, [tableView._exposedColumns lastIndex] - index + 1)];
// FIXME: Would be faster with some sort of -setNeedsDisplayInColumns: that updates a dirtyTableColumnForDisplay cache; then marked columns would relayout their data views at display time. // FIXME: Would be faster with some sort of -setNeedsDisplayInColumns: that updates a dirtyTableColumnForDisplay cache; then marked columns would relayout their data views at display time.
[tableView _layoutDataViewsInRows:rows columns:columns]; [tableView _layoutDataViewsInRows:rows columns:columns];
[tableView tile]; [tableView tile];
if (!_disableResizingPosting) if (!_disableResizingPosting)
[self _postDidResizeNotificationWithOldWidth:oldWidth]; [self _postDidResizeNotificationWithOldWidth:oldWidth];
} }
@@ -226,12 +232,12 @@ CPTableColumnUserResizingMask = 1 << 1;
/*! /*!
This method set's the "prototype" view which will be used to create all table cells in this column. 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. individual cell that is shown. As a result, changes made after calling this method won't be reflected.
Example: Example:
[tableColumn setDataView:someView]; // snapshot taken [tableColumn setDataView:someView]; // snapshot taken
[[tableColumn dataView] setSomething:x]; //won't work [[tableColumn dataView] setSomething:x]; //won't work
@@ -242,11 +248,12 @@ CPTableColumnUserResizingMask = 1 << 1;
*/ */
- (void)setDataView:(CPView)aView - (void)setDataView:(CPView)aView
{ {
if (_dataView === aView)
return;
if (_dataView) if (_dataView)
_dataViewData[[_dataView UID]] = nil; _dataViewData[[_dataView UID]] = nil;
[aView setThemeState:CPThemeStateTableDataView];
_dataView = aView; _dataView = aView;
_dataViewData[[aView UID]] = [CPKeyedArchiver archivedDataWithRootObject:aView]; _dataViewData[[aView UID]] = [CPKeyedArchiver archivedDataWithRootObject:aView];
} }
@@ -285,10 +292,7 @@ CPTableColumnUserResizingMask = 1 << 1;
// unarchive the data view cache // unarchive the data view cache
var newDataView = [CPKeyedUnarchiver unarchiveObjectWithData:_dataViewData[dataViewUID]]; var newDataView = [CPKeyedUnarchiver unarchiveObjectWithData:_dataViewData[dataViewUID]];
newDataView.identifier = dataViewUID; newDataView.identifier = dataViewUID;
// make sure only we have control over the size and placement
[newDataView setAutoresizingMask:CPViewNotSizable];
return newDataView; return newDataView;
} }
@@ -321,7 +325,7 @@ CPTableColumnUserResizingMask = 1 << 1;
} }
/* /*
Returns YES if the user can edit cells associated with the receiver by double-clicking the Returns YES if the user can edit cells associated with the receiver by double-clicking the
column in the NSTableView, NO otherwise. column in the NSTableView, NO otherwise.
*/ */
- (BOOL)isEditable - (BOOL)isEditable
@@ -344,14 +348,7 @@ CPTableColumnUserResizingMask = 1 << 1;
- (void)setHidden:(BOOL)shouldBeHidden - (void)setHidden:(BOOL)shouldBeHidden
{ {
shouldBeHidden = !!shouldBeHidden
if (_isHidden === shouldBeHidden)
return;
_isHidden = shouldBeHidden; _isHidden = shouldBeHidden;
[[self headerView] setHidden:shouldBeHidden];
[[self tableView] _tableColumnVisibilityDidChange:self];
} }
- (BOOL)isHidden - (BOOL)isHidden
@@ -362,7 +359,7 @@ CPTableColumnUserResizingMask = 1 << 1;
//Setting Tool Tips //Setting Tool Tips
/* /*
Sets the tooltip string that is displayed when the cursor pauses over the Sets the tooltip string that is displayed when the cursor pauses over the
header cell of the receiver. header cell of the receiver.
*/ */
- (void)setHeaderToolTip:(CPString)aToolTip - (void)setHeaderToolTip:(CPString)aToolTip
@@ -385,86 +382,13 @@ CPTableColumnUserResizingMask = 1 << 1;
@end @end
@implementation CPTableColumn (Bindings)
- (void)bind:(CPString)aBinding toObject:(id)anObject withKeyPath:(CPString)aKeyPath options:(CPDictionary)options
{
[super bind:aBinding toObject:anObject withKeyPath:aKeyPath options:options];
if (![aBinding isEqual:@"someListOfExceptedBindings(notAcceptedBindings)"])
[[self tableView] _establishBindingsIfUnbound:anObject];
}
- (void)prepareDataView:(CPView)aDataView forRow:(unsigned)aRow
{
var bindingsDictionary = [CPKeyValueBinding allBindingsForObject:self],
keys = [bindingsDictionary allKeys];
for (var i = 0, count = [keys count]; i < count; i++)
{
var bindingName = keys[i],
bindingPath = [aDataView _replacementKeyPathForBinding:bindingName],
binding = [bindingsDictionary objectForKey:bindingName],
bindingInfo = binding._info,
destination = [bindingInfo objectForKey:CPObservedObjectKey],
keyPath = [bindingInfo objectForKey:CPObservedKeyPathKey],
dotIndex = keyPath.lastIndexOf("."),
value;
if (dotIndex === CPNotFound)
value = [[destination valueForKeyPath:keyPath] objectAtIndex:aRow];
else
{
/*
Optimize the prototypical use case where the key path describes a value
in an array. Without this optimization, we call CPArray's valueForKey
which generates as many values as objects in the array, of which we then
pick one and throw away the rest.
The optimization is to get the array and access the value directly. This
turns the operation into a single access regardless of how long the model
array is.
*/
var firstPart = keyPath.substring(0, dotIndex),
secondPart = keyPath.substring(dotIndex + 1),
firstValue = [destination valueForKeyPath:firstPart];
if ([firstValue isKindOfClass:CPArray])
value = [[firstValue objectAtIndex:aRow] valueForKeyPath:secondPart];
else
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];
}
}
//- (void)objectValue
//{
// return nil;
//}
- (void)setValue:(CPArray)content
{
[[self tableView] reloadData];
}
@end
var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey", var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
CPTableColumnHeaderViewKey = @"CPTableColumnHeaderViewKey", CPTableColumnHeaderViewKey = @"CPTableColumnHeaderViewKey",
CPTableColumnDataViewKey = @"CPTableColumnDataViewKey", CPTableColumnDataViewKey = @"CPTableColumnDataViewKey",
CPTableColumnWidthKey = @"CPTableColumnWidthKey", CPTableColumnWidthKey = @"CPTableColumnWidthKey",
CPTableColumnMinWidthKey = @"CPTableColumnMinWidthKey", CPTableColumnMinWidthKey = @"CPTableColumnMinWidthKey",
CPTableColumnMaxWidthKey = @"CPTableColumnMaxWidthKey", CPTableColumnMaxWidthKey = @"CPTableColumnMaxWidthKey",
CPTableColumnResizingMaskKey = @"CPTableColumnResizingMaskKey", CPTableColumnResizingMaskKey = @"CPTableColumnResizingMaskKey";
CPTableColumnIsHiddenKey = @"CPTableColumnIsHiddenKey",
CPSortDescriptorPrototypeKey = @"CPSortDescriptorPrototypeKey",
CPTableColumnIsEditableKey = @"CPTableColumnIsEditableKey";
@implementation CPTableColumn (CPCoding) @implementation CPTableColumn (CPCoding)
@@ -485,11 +409,7 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
[self setDataView:[aCoder decodeObjectForKey:CPTableColumnDataViewKey]]; [self setDataView:[aCoder decodeObjectForKey:CPTableColumnDataViewKey]];
[self setHeaderView:[aCoder decodeObjectForKey:CPTableColumnHeaderViewKey]]; [self setHeaderView:[aCoder decodeObjectForKey:CPTableColumnHeaderViewKey]];
_resizingMask = [aCoder decodeIntForKey:CPTableColumnResizingMaskKey]; _resizingMask = [aCoder decodeBoolForKey:CPTableColumnResizingMaskKey];
_isHidden = [aCoder decodeBoolForKey:CPTableColumnIsHiddenKey];
_isEditable = [aCoder decodeBoolForKey:CPTableColumnIsEditableKey];
_sortDescriptorPrototype = [aCoder decodeObjectForKey:CPSortDescriptorPrototypeKey];
} }
return self; return self;
@@ -507,10 +427,6 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
[aCoder encodeObject:_dataView forKey:CPTableColumnDataViewKey]; [aCoder encodeObject:_dataView forKey:CPTableColumnDataViewKey];
[aCoder encodeObject:_resizingMask forKey:CPTableColumnResizingMaskKey]; [aCoder encodeObject:_resizingMask forKey:CPTableColumnResizingMaskKey];
[aCoder encodeBool:_isHidden forKey:CPTableColumnIsHiddenKey];
[aCoder encodeBool:_isEditable forKey:CPTableColumnIsEditableKey];
[aCoder encodeObject:_sortDescriptorPrototype forKey:CPSortDescriptorPrototypeKey];
} }
@end @end
@@ -547,4 +463,4 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
reason:@"dataCellForRow: is not supported. Use -dataViewForRow:row instead."]; reason:@"dataCellForRow: is not supported. Use -dataViewForRow:row instead."];
} }
@end @end
+188 -374
View File
@@ -20,64 +20,54 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
@import <Foundation/CPIndexSet.j>
@import "CPTableColumn.j" @import "CPTableColumn.j"
@import "CPTableView.j" @import "CPTableView.j"
@import "CPView.j" @import "CPView.j"
@implementation _CPTableColumnHeaderView : CPView @implementation _CPTableColumnHeaderView : CPView
{ {
_CPImageAndTextView _textField; _CPImageAndTextView _textField;
}
+ (CPString)defaultThemeClass
{
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 - (void)initWithFrame:(CGRect)frame
{ {
self = [super initWithFrame:frame]; self = [super initWithFrame:frame];
if (self) if (self)
{
[self _init]; [self _init];
}
return self; return self;
} }
- (void)_init - (void)_init
{ {
_textField = [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()]; _textField = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(5, 1, CGRectGetWidth([self bounds]) - 10, CGRectGetHeight([self bounds]) - 1)];
[_textField setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable]; [_textField setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
[_textField setLineBreakMode:CPLineBreakByTruncatingTail]; [_textField setLineBreakMode:CPLineBreakByTruncatingTail];
[_textField setTextColor: [CPColor colorWithHexString: @"333333"]];
[_textField setFont:[CPFont boldSystemFontOfSize:12.0]];
[_textField setAlignment:CPLeftTextAlignment]; [_textField setAlignment:CPLeftTextAlignment];
[_textField setVerticalAlignment:CPCenterVerticalTextAlignment]; [_textField setVerticalAlignment:CPCenterVerticalTextAlignment];
[_textField setTextShadowColor:[CPColor whiteColor]];
[_textField setTextShadowOffset:CGSizeMake(0,1)];
[self addSubview:_textField]; [self addSubview:_textField];
} }
- (void)layoutSubviews - (void)layoutSubviews
{ {
[self setBackgroundColor:[self currentValueForThemeAttribute:@"background-color"]]; var themeState = [self themeState];
var inset = [self currentValueForThemeAttribute:@"text-inset"], if(themeState & CPThemeStateSelected && themeState & CPThemeStateHighlighted)
bounds = [self bounds]; [self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-highlighted-pressed.png", CGSizeMake(1.0, 22.0))]];
else if (themeState & CPThemeStateSelected)
[_textField setFrame:_CGRectMake(inset.right, inset.top, bounds.size.width - inset.right - inset.left, bounds.size.height - inset.top - inset.bottom)]; [self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-highlighted.png", CGSizeMake(1.0, 22.0))]];
[_textField setTextColor:[self currentValueForThemeAttribute:@"text-color"]]; else if (themeState & CPThemeStateHighlighted)
[_textField setFont:[self currentValueForThemeAttribute:@"text-font"]]; [self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-pressed.png", CGSizeMake(1.0, 22.0))]];
[_textField setTextShadowColor:[self currentValueForThemeAttribute:@"text-shadow-color"]]; else
[_textField setTextShadowOffset:[self currentValueForThemeAttribute:@"text-shadow-offset"]]; [self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview.png", CGSizeMake(1.0, 22.0))]];
[_textField setAlignment:[self currentValueForThemeAttribute:@"text-alignment"]];
} }
- (void)setStringValue:(CPString)string - (void)setStringValue:(CPString)string
@@ -105,6 +95,11 @@
[_textField setFont:aFont]; [_textField setFont:aFont];
} }
- (void)setValue:(id)aValue forThemeAttribute:(id)aKey
{
[_textField setValue:aValue forThemeAttribute:aKey];
}
- (void)_setIndicatorImage:(CPImage)anImage - (void)_setIndicatorImage:(CPImage)anImage
{ {
if (anImage) if (anImage)
@@ -142,7 +137,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
- (void)encodeWithCoder:(CPCoder)aCoder - (void)encodeWithCoder:(CPCoder)aCoder
{ {
[super encodeWithCoder:aCoder]; [super encodeWithCoder:aCoder];
[aCoder encodeObject:[_textField text] forKey:_CPTableColumnHeaderViewStringValueKey]; [aCoder encodeObject:[_textField text] forKey:_CPTableColumnHeaderViewStringValueKey];
[aCoder encodeObject:[_textField image] forKey:_CPTableColumnHeaderViewImageKey]; [aCoder encodeObject:[_textField image] forKey:_CPTableColumnHeaderViewImageKey];
[aCoder encodeObject:[_textField font] forKey:_CPTableColumnHeaderViewFontKey]; [aCoder encodeObject:[_textField font] forKey:_CPTableColumnHeaderViewFontKey];
@@ -152,47 +147,27 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
@implementation CPTableHeaderView : CPView @implementation CPTableHeaderView : CPView
{ {
CGPoint _mouseDownLocation; int _resizedColumn @accessors(readonly, property=resizedColumn);
CGPoint _previousTrackingLocation; int _draggedColumn @accessors(readonly, property=draggedColumn);
int _activeColumn; int _pressedColumn @accessors(readonly, property=pressedColumn);
int _pressedColumn;
float _draggedDistance @accessors(readonly, property=draggedDistance);
BOOL _isResizing; float _lastLocation;
BOOL _isDragging; float _columnOldWidth;
BOOL _isTrackingColumn;
BOOL _drawsColumnLines; CPTableView _tableView @accessors(property=tableView);
float _columnOldWidth;
CPTableView _tableView @accessors(property=tableView);
}
+ (CPString)defaultThemeClass
{
return @"tableHeaderRow";
}
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[[CPNull null], [CPColor grayColor]]
forKeys:[@"background-color", @"divider-color"]];
} }
- (void)_init - (void)_init
{ {
_mouseDownLocation = _CGPointMakeZero(); _resizedColumn = -1;
_previousTrackingLocation = _CGPointMakeZero(); _draggedColumn = -1;
_activeColumn = -1;
_pressedColumn = -1; _pressedColumn = -1;
_draggedDistance = 0.0;
_lastLocation = nil;
_columnOldWidth = nil;
_isResizing = NO; [self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview.png", CGSizeMake(1.0, 22.0))]];
_isDragging = NO;
_isTrackingColumn = NO;
_drawsColumnLines = YES;
_columnOldWidth = 0.0;
[self setBackgroundColor:[self currentValueForThemeAttribute:@"background-color"]];
} }
- (id)initWithFrame:(CGRect)aFrame - (id)initWithFrame:(CGRect)aFrame
@@ -207,41 +182,39 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
- (int)columnAtPoint:(CGPoint)aPoint - (int)columnAtPoint:(CGPoint)aPoint
{ {
return [_tableView columnAtPoint:CGPointMake(aPoint.x, aPoint.y)]; return [_tableView columnAtPoint:CGPointMake(aPoint.x, 0)];
} }
- (CGRect)headerRectOfColumn:(int)aColumnIndex - (CGRect)headerRectOfColumn:(int)aColumnIndex
{ {
var headerRect = [self bounds], var tableColumns = [_tableView tableColumns];
columnRect = [_tableView rectOfColumn:aColumnIndex];
headerRect.origin.x = _CGRectGetMinX(columnRect); if (aColumnIndex < 0 || aColumnIndex > [tableColumns count])
headerRect.size.width = _CGRectGetWidth(columnRect); [CPException raise:"invalid" reason:"tried to get headerRectOfColumn: on invalid column"];
return headerRect; // UPDATE COLUMN RANGES ?
}
var tableRange = _tableView._tableColumnRanges[aColumnIndex],
bounds = [self bounds];
- (void)setDrawsColumnLines:(BOOL)aFlag var rMinX = ROUND(tableRange.location);
{ bounds.origin.x = rMinX;
_drawsColumnLines = aFlag; bounds.size.width = FLOOR(tableRange.length + tableRange.location - rMinX);
}
return bounds;
- (BOOL)drawsColumnLines
{
return _drawsColumnLines;
} }
- (CGRect)_cursorRectForColumn:(int)column - (CGRect)_cursorRectForColumn:(int)column
{ {
if (column == -1 || !([_tableView._tableColumns[column] resizingMask] & CPTableColumnUserResizingMask)) if (column == -1 || !([_tableView._tableColumns[column] resizingMask] & CPTableColumnUserResizingMask))
return _CGRectMakeZero(); return CGRectMakeZero();
var rect = [self headerRectOfColumn:column]; var rect = [self headerRectOfColumn:column];
rect.origin.x = _CGRectGetMaxX(rect) - 5; rect.origin.x = CGRectGetMaxX(rect) - 5;
rect.size.width = 20; rect.size.width = 20;
return rect; return rect;
} }
- (void)_setPressedColumn:(CPInteger)column - (void)_setPressedColumn:(CPInteger)column
@@ -250,293 +223,117 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
{ {
var headerView = [_tableView._tableColumns[_pressedColumn] headerView]; var headerView = [_tableView._tableColumns[_pressedColumn] headerView];
[headerView unsetThemeState:CPThemeStateHighlighted]; [headerView unsetThemeState:CPThemeStateHighlighted];
} }
if (column != -1) if (column != -1)
{ {
var headerView = [_tableView._tableColumns[column] headerView]; var headerView = [_tableView._tableColumns[column] headerView];
[headerView setThemeState:CPThemeStateHighlighted]; [headerView setThemeState:CPThemeStateHighlighted];
} }
_pressedColumn = column; _pressedColumn = column;
} }
- (void)mouseDown:(CPEvent)theEvent - (void)mouseDown:(CPEvent)theEvent
{ {
[self trackMouse:theEvent]; var mouseLocation = [self convertPoint:[theEvent locationInWindow] fromView:nil],
clickedColumn = [self columnAtPoint:mouseLocation];
// should we send column -1 ?
[_tableView _sendDelegateDidMouseDownInHeader:clickedColumn];
var resizeLocation = CGPointMake(mouseLocation.x - 5, mouseLocation.y),
resizedColumn = [self columnAtPoint:resizeLocation];
if (resizedColumn == -1)
return;
// 2 different tracking methods: one for resizing/stop-resizing, another one for selection/reordering
if ([_tableView allowsColumnResizing]
&& CGRectContainsPoint([self _cursorRectForColumn:resizedColumn], mouseLocation))
{
_resizedColumn = resizedColumn;
[_tableView._tableColumns[_resizedColumn] setDisableResizingPosting:YES];
[_tableView setDisableAutomaticResizing:YES];
[self trackResizeWithEvent:theEvent];
}
else
{
[self _setPressedColumn:clickedColumn];
[self trackMouseWithEvent:theEvent];
}
} }
- (void)trackMouse:(CPEvent)theEvent - (void)trackMouseWithEvent:(CPEvent)theEvent
{ {
var type = [theEvent type], var type = [theEvent type];
currentLocation = [self convertPoint:[theEvent locationInWindow] fromView:nil];
if (type == CPLeftMouseUp)
// Take the right columns resize tracking area into account
currentLocation.x -= 5.0;
var columnIndex = [self columnAtPoint:currentLocation],
shouldResize = [self shouldResizeTableColumn:columnIndex at:_CGPointMake(currentLocation.x + 5.0, currentLocation.y)];
if (type === CPLeftMouseUp)
{ {
if (shouldResize) var location = [self convertPoint:[theEvent locationInWindow] fromView:nil],
[self stopResizingTableColumn:_activeColumn at:currentLocation]; clickedColumn = [self columnAtPoint:location];
else if ([self _shouldStopTrackingTableColumn:columnIndex at:currentLocation])
{
[_tableView _didClickTableColumn:columnIndex modifierFlags:[theEvent modifierFlags]];
[self stopTrackingTableColumn:columnIndex at:currentLocation];
_isTrackingColumn = NO; [self _setPressedColumn:-1];
}
if (clickedColumn != -1)
[self _updateResizeCursor:[CPApp currentEvent]]; [_tableView _didClickTableColumn:clickedColumn modifierFlags:[theEvent modifierFlags]];
_activeColumn = CPNotFound;
return; return;
} }
if (type === CPLeftMouseDown) [CPApp setTarget:self selector:@selector(trackMouseWithEvent:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPLeftMouseDownMask untilDate:nil inMode:nil dequeue:YES];
{ }
if (columnIndex === -1)
return;
_mouseDownLocation = currentLocation; - (void)trackResizeWithEvent:(CPEvent)anEvent
_activeColumn = columnIndex; {
var location = [self convertPoint:[anEvent locationInWindow] fromView:nil],
tableColumn = [[_tableView tableColumns] objectAtIndex:_resizedColumn],
type = [anEvent type];
[_tableView _sendDelegateDidMouseDownInHeader:columnIndex]; if (_lastLocation == nil)
_lastLocation = location;
if (shouldResize) if (_columnOldWidth == nil)
[self startResizingTableColumn:columnIndex at:currentLocation]; _columnOldWidth = [tableColumn width];
else
{ if (type === CPLeftMouseUp)
[self startTrackingTableColumn:columnIndex at:currentLocation]; {
_isTrackingColumn = YES; [self _updateResizeCursor:anEvent];
}
} [tableColumn _postDidResizeNotificationWithOldWidth:_columnOldWidth];
[tableColumn setDisableResizingPosting:NO];
[_tableView setDisableAutomaticResizing:NO];
_resizedColumn = -1;
_lastLocation = nil;
_columnOldWidth = nil;
return;
}
else if (type === CPLeftMouseDragged) else if (type === CPLeftMouseDragged)
{ {
if (shouldResize) var newWidth = [tableColumn width] + location.x - _lastLocation.x;
[self continueResizingTableColumn:_activeColumn at:currentLocation];
if (newWidth < [tableColumn minWidth])
[[CPCursor resizeRightCursor] set];
else if (newWidth > [tableColumn maxWidth])
[[CPCursor resizeLeftCursor] set];
else else
{ {
if (_activeColumn === columnIndex && _CGRectContainsPoint([self headerRectOfColumn:columnIndex], currentLocation)) _tableView._lastColumnShouldSnap = NO;
{ [tableColumn setWidth:newWidth];
if (_isTrackingColumn && _pressedColumn !== -1) // FIXME: there has to be a better way to do this...
{ // We should refactor the auto resizing crap.
if (![self continueTrackingTableColumn:columnIndex at:currentLocation]) // We need to figure out the exact cocoa behavior here though.
return; // Stop tracking the column, because it's being dragged _lastLocation = location;
} else
[self startTrackingTableColumn:columnIndex at:currentLocation];
} else if (_isTrackingColumn && _pressedColumn !== -1) [[CPCursor resizeLeftRightCursor] set];
[self stopTrackingTableColumn:_activeColumn at:currentLocation]; [self setNeedsLayout];
[self setNeedsDisplay:YES];
} }
} }
_previousTrackingLocation = currentLocation; [CPApp setTarget:self selector:@selector(trackResizeWithEvent:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
[CPApp setTarget:self selector:@selector(trackMouse:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
}
- (void)startTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
{
[self _setPressedColumn:aColumnIndex];
}
- (BOOL)continueTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
{
if ([self _shouldDragTableColumn:aColumnIndex at:aPoint])
{
var columnRect = [self headerRectOfColumn:aColumnIndex],
offset = _CGPointMakeZero(),
view = [_tableView _dragViewForColumn:aColumnIndex event:[CPApp currentEvent] offset:offset],
viewLocation = _CGPointMakeZero();
viewLocation.x = ( _CGRectGetMinX(columnRect) + offset.x ) + ( aPoint.x - _mouseDownLocation.x );
viewLocation.y = _CGRectGetMinY(columnRect) + offset.y;
[self dragView:view at:viewLocation offset:_CGSizeMakeZero() event:[CPApp currentEvent]
pasteboard:[CPPasteboard pasteboardWithName:CPDragPboard] source:self slideBack:YES];
return NO;
}
return YES;
}
- (BOOL)_shouldStopTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
{
return _isTrackingColumn && _activeColumn === aColumnIndex &&
_CGRectContainsPoint([self headerRectOfColumn:aColumnIndex], aPoint);
}
- (void)stopTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
{
[self _setPressedColumn:CPNotFound];
[self _updateResizeCursor:[CPApp currentEvent]];
}
- (BOOL)_shouldDragTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
{
return [_tableView allowsColumnReordering] && ABS(aPoint.x - _mouseDownLocation.x) >= 10.0;
}
- (CGRect)_headerRectOfLastVisibleColumn
{
var tableColumns = [_tableView tableColumns],
columnIndex = [tableColumns count];
while (columnIndex--)
{
var tableColumn = [tableColumns objectAtIndex:columnIndex];
if (![tableColumn isHidden])
return [self headerRectOfColumn:columnIndex];
}
return nil;
}
- (void)_constrainDragView:(CPView)theDragView at:(CGPoint)aPoint
{
var tableColumns = [_tableView tableColumns],
lastColumnRect = [self _headerRectOfLastVisibleColumn],
activeColumnRect = [self headerRectOfColumn:_activeColumn],
dragWindow = [theDragView window],
frame = [dragWindow frame];
// Convert the frame origin from the global coordinate system to the windows' coordinate system
frame.origin = [[self window] convertGlobalToBase:frame.origin];
// the from the window to the view
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)));
// Make sure the column cannot move vertically
frame.origin.y = _CGRectGetMinY(lastColumnRect);
// Convert the calculated origin back to the window coordinate system
frame.origin = [self convertPoint:frame.origin toView:nil];
// Then back to the global coordinate system
frame.origin = [[self window] convertBaseToGlobal:frame.origin];
[dragWindow setFrame:frame];
}
- (void)_moveColumn:(int)aFromIndex toColumn:(int)aToIndex
{
[_tableView moveColumn:aFromIndex toColumn:aToIndex];
_activeColumn = aToIndex;
_pressedColumn = _activeColumn;
}
- (void)draggedView:(CPView)aView beganAt:(CGPoint)aPoint
{
_isDragging = YES;
var column = [[_tableView tableColumns] objectAtIndex:_activeColumn];
[[column headerView] setHidden:YES];
[_tableView _setDraggedColumn:column];
[self setNeedsDisplay:YES];
}
- (void)draggedView:(CPView)aView movedTo:(CGPoint)aPoint
{
[self _constrainDragView:aView at:aPoint];
var dragWindow = [aView window],
dragWindowFrame = [dragWindow frame];
var hoverPoint = CGPointCreateCopy(aPoint);
if (aPoint.x < _previousTrackingLocation.x)
hoverPoint = _CGPointMake(_CGRectGetMinX(dragWindowFrame), _CGRectGetMinY(dragWindowFrame));
else if (aPoint.x > _previousTrackingLocation.x)
hoverPoint = _CGPointMake(_CGRectGetMaxX(dragWindowFrame), _CGRectGetMinY(dragWindowFrame));
// Convert the hover point from the global coordinate system to windows' coordinate system
hoverPoint = [[self window] convertGlobalToBase:hoverPoint];
// then to the view
hoverPoint = [self convertPoint:hoverPoint fromView:nil];
var hoveredColumn = [self columnAtPoint:hoverPoint];
if (hoveredColumn !== -1)
{
var columnRect = [self headerRectOfColumn:hoveredColumn],
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)
[self _moveColumn:_activeColumn toColumn:hoveredColumn];
}
_previousTrackingLocation = aPoint;
}
- (void)draggedView:(CPImage)aView endedAt:(CGPoint)aLocation operation:(CPDragOperation)anOperation
{
_isDragging = NO;
_isTrackingColumn = NO; // We need to do this explicitly because the mouse up section of trackMouse is never reached
[_tableView _setDraggedColumn:nil];
[[[[_tableView tableColumns] objectAtIndex:_activeColumn] headerView] setHidden:NO];
[self stopTrackingTableColumn:_activeColumn at:aLocation];
[self setNeedsDisplay:YES];
}
- (BOOL)shouldResizeTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
{
if (_isResizing)
return YES;
if (_isTrackingColumn)
return NO;
return [_tableView allowsColumnResizing] && _CGRectContainsPoint([self _cursorRectForColumn:aColumnIndex], aPoint);
}
- (void)startResizingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
{
_isResizing = YES;
var tableColumn = [[_tableView tableColumns] objectAtIndex:aColumnIndex];
[tableColumn setDisableResizingPosting:YES];
[_tableView setDisableAutomaticResizing:YES];
}
- (void)continueResizingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
{
var tableColumn = [[_tableView tableColumns] objectAtIndex:aColumnIndex],
newWidth = [tableColumn width] + aPoint.x - _previousTrackingLocation.x;
if (newWidth < [tableColumn minWidth])
[[CPCursor resizeRightCursor] set];
else if (newWidth > [tableColumn maxWidth])
[[CPCursor resizeLeftCursor] set];
else
{
_tableView._lastColumnShouldSnap = NO;
[tableColumn setWidth:newWidth];
[[CPCursor resizeLeftRightCursor] set];
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
}
- (void)stopResizingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
{
var tableColumn = [[_tableView tableColumns] objectAtIndex:aColumnIndex];
[tableColumn _postDidResizeNotificationWithOldWidth:_columnOldWidth];
[tableColumn setDisableResizingPosting:NO];
[_tableView setDisableAutomaticResizing:NO];
_isResizing = NO;
} }
- (void)_updateResizeCursor:(CPEvent)theEvent - (void)_updateResizeCursor:(CPEvent)theEvent
@@ -548,15 +345,15 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
return; return;
} }
var mouseLocation = [self convertPoint:[theEvent locationInWindow] fromView:nil], var mouseLocation = [self convertPoint:[theEvent locationInWindow] fromView:nil],
mouseOverLocation = CGPointMake(mouseLocation.x - 5, mouseLocation.y), mouseOverLocation = CGPointMake(mouseLocation.x - 5, mouseLocation.y),
overColumn = [self columnAtPoint:mouseOverLocation]; 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], var tableColumn = [[_tableView tableColumns] objectAtIndex:overColumn],
width = [tableColumn width]; width = [tableColumn width];
if (width == [tableColumn minWidth]) if (width == [tableColumn minWidth])
[[CPCursor resizeRightCursor] set]; [[CPCursor resizeRightCursor] set];
else if (width == [tableColumn maxWidth]) else if (width == [tableColumn maxWidth])
@@ -568,8 +365,14 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
[[CPCursor arrowCursor] set]; [[CPCursor arrowCursor] set];
} }
- (void)mouseEntered:(CPEvent)theEvent - (void)viewDidMoveToWindow
{ {
//if ([_tableView allowsColumnResizing])
// [[self window] setAcceptsMouseMovedEvents:YES];
}
- (void)mouseEntered:(CPEvent)theEvent
{
[self _updateResizeCursor:theEvent]; [self _updateResizeCursor:theEvent];
} }
@@ -587,33 +390,31 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
- (void)layoutSubviews - (void)layoutSubviews
{ {
var tableColumns = [_tableView tableColumns], 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], var column = [tableColumns objectAtIndex:i],
headerView = [column headerView]; headerView = [column headerView];
var frame = [self headerRectOfColumn:i]; var frame = [self headerRectOfColumn:i];
frame.size.height -= 0.5; frame.size.height -= 0.5;
if (i > 0) if (i > 0)
{ {
frame.origin.x += 0.5; frame.origin.x += 0.5;
frame.size.width -= 1; frame.size.width -= 1;
} }
[headerView setFrame:frame]; [headerView setFrame:frame];
if([headerView superview] != self) if([headerView superview] != self)
[self addSubview:headerView]; [self addSubview:headerView];
} }
[self setBackgroundColor:[self currentValueForThemeAttribute:@"background-color"]];
} }
- (void)drawRect:(CGRect)aRect - (void)drawRect:(CGRect)aRect
{ {
if (!_tableView || ![self drawsColumnLines]) if (!_tableView)
return; return;
var context = [[CPGraphicsContext currentContext] graphicsPort], var context = [[CPGraphicsContext currentContext] graphicsPort],
@@ -625,41 +426,55 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
exposedRange = CPMakeRange(firstIndex, [exposedTableColumns lastIndex] - firstIndex + 1); exposedRange = CPMakeRange(firstIndex, [exposedTableColumns lastIndex] - firstIndex + 1);
CGContextSetLineWidth(context, 1); CGContextSetLineWidth(context, 1);
CGContextSetStrokeColor(context, [self currentValueForThemeAttribute:@"divider-color"]); CGContextSetStrokeColor(context, [_tableView gridColor]);
[exposedColumnIndexes getIndexes:columnsArray maxCount:-1 inIndexRange:exposedRange]; [exposedColumnIndexes getIndexes:columnsArray maxCount:-1 inIndexRange:exposedRange];
var columnArrayIndex = 0, var columnArrayIndex = 0,
columnArrayCount = columnsArray.length, columnArrayCount = columnsArray.length,
columnMaxX; columnMaxX;
CGContextBeginPath(context); CGContextBeginPath(context);
for(; columnArrayIndex < columnArrayCount; columnArrayIndex++) for(; columnArrayIndex < columnArrayCount; columnArrayIndex++)
{ {
// grab each column rect and add vertical lines // grab each column rect and add vertical lines
var columnIndex = columnsArray[columnArrayIndex], var columnIndex = columnsArray[columnArrayIndex],
columnToStroke = [self headerRectOfColumn:columnIndex]; columnToStroke = [self headerRectOfColumn:columnIndex];
columnMaxX = _CGRectGetMaxX(columnToStroke); columnMaxX = CGRectGetMaxX(columnToStroke);
CGContextMoveToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(_CGRectGetMinY(columnToStroke))); CGContextMoveToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(CGRectGetMinY(columnToStroke)));
CGContextAddLineToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(_CGRectGetMaxY(columnToStroke))); CGContextAddLineToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(CGRectGetMaxY(columnToStroke)));
} }
CGContextClosePath(context); CGContextClosePath(context);
CGContextStrokePath(context); CGContextStrokePath(context);
/*if (_isDragging) /*
var maxY = CGRectGetMaxY([self bounds]);
// draw normal gradient for remaining space
if (supportsCanvasGradient)
{ {
CGContextSetFillColor(context, [CPColor grayColor]); aRect.origin.x = columnMaxX - 0.5;
CGContextFillRect(context, [self headerRectOfColumn:_activeColumn]) aRect.size.width -= columnMaxX;
}*/ CGContextBeginPath(context);
CGContextAddRect(context, CGRectMake(columnMaxX + 1, 0, CGRectGetMaxX([self bounds]) - columnMaxX, CGRectGetHeight([self bounds])));
CGContextClosePath(context);
CGContextDrawLinearGradient(context, [_CPTableColumnHeaderView headerGradient], CGPointMake(0,0), CGPointMake(0, maxY - 1),0);
}
// Draw bottom line
CGContextBeginPath(context);
CGContextMoveToPoint(context, 0, maxY - 0.5);
CGContextAddLineToPoint(context, CGRectGetMaxX([self bounds]), maxY - 0.5);
CGContextClosePath(context);
CGContextStrokePath(context);
*/
} }
@end @end
var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey", var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey";
CPTableHeaderViewDrawsColumnLines = @"CPTableHeaderViewDrawsColumnLines";
@implementation CPTableHeaderView (CPCoding) @implementation CPTableHeaderView (CPCoding)
@@ -669,7 +484,6 @@ var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey",
{ {
[self _init]; [self _init];
_tableView = [aCoder decodeObjectForKey:CPTableHeaderViewTableViewKey]; _tableView = [aCoder decodeObjectForKey:CPTableHeaderViewTableViewKey];
_drawsColumnLines = [aCoder decodeBoolForKey:CPTableHeaderViewDrawsColumnLines];
} }
return self; return self;
@@ -679,7 +493,7 @@ var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey",
{ {
[super encodeWithCoder:aCoder]; [super encodeWithCoder:aCoder];
[aCoder encodeObject:_tableView forKey:CPTableHeaderViewTableViewKey]; [aCoder encodeObject:_tableView forKey:CPTableHeaderViewTableViewKey];
[aCoder encodeBool:_drawsColumnLines forKey:CPTableHeaderViewDrawsColumnLines];
} }
@end @end
+530 -1043
View File
File diff suppressed because it is too large Load Diff
-30
View File
@@ -1,30 +0,0 @@
/*
* CPText.j
* AppKit
*
* Created by Alexander Ljungberg.
* Copyright 2010, WireLoad, LLC.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
CPEnterCharacter = "\u0003";
CPBackspaceCharacter = "\u0008";
CPTabCharacter = "\u0009";
CPNewlineCharacter = "\u000a";
CPFormFeedCharacter = "\u000c";
CPCarriageReturnCharacter = "\u000d";
CPBackTabCharacter = "\u0019";
CPDeleteCharacter = "\u007f";
+119 -266
View File
@@ -26,6 +26,9 @@
@import "CPCompatibility.j" @import "CPCompatibility.j"
@import "_CPImageAndTextView.j" @import "_CPImageAndTextView.j"
#include "CoreGraphics/CGGeometry.h"
#include "Platform/Platform.h"
#include "Platform/DOM/CPDOMDisplayServer.h"
CPTextFieldSquareBezel = 0; /*! A textfield bezel with a squared corners. */ CPTextFieldSquareBezel = 0; /*! A textfield bezel with a squared corners. */
CPTextFieldRoundedBezel = 1; /*! A textfield bezel with rounded corners. */ CPTextFieldRoundedBezel = 1; /*! A textfield bezel with rounded corners. */
@@ -46,7 +49,7 @@ var CPTextFieldDOMInputElement = nil,
CPTextFieldCachedSelectStartFunction = nil, CPTextFieldCachedSelectStartFunction = nil,
CPTextFieldCachedDragFunction = nil, CPTextFieldCachedDragFunction = nil,
CPTextFieldBlurFunction = nil; CPTextFieldBlurFunction = nil;
#endif #endif
var CPSecureTextFieldCharacter = "\u2022"; var CPSecureTextFieldCharacter = "\u2022";
@@ -77,18 +80,15 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
BOOL _isEditable; BOOL _isEditable;
BOOL _isSelectable; BOOL _isSelectable;
BOOL _isSecure; BOOL _isSecure;
BOOL _willBecomeFirstResponderByClick;
BOOL _drawsBackground; BOOL _drawsBackground;
CPColor _textFieldBackgroundColor; CPColor _textFieldBackgroundColor;
id _placeholderString; id _placeholderString;
id _originalPlaceholderString;
BOOL _currentValueIsPlaceholder;
id _delegate; id _delegate;
CPString _textDidChangeValue; CPString _textDidChangeValue;
// NS-style Display Properties // NS-style Display Properties
@@ -155,7 +155,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
return textField; return textField;
} }
+ (CPString)defaultThemeClass + (CPString)themeClass
{ {
return "textfield"; return "textfield";
} }
@@ -199,7 +199,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
} }
CPTextFieldHandleBlur = function(anEvent) CPTextFieldHandleBlur = function(anEvent)
{ {
CPTextFieldInputOwner = nil; CPTextFieldInputOwner = nil;
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode]; [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
@@ -207,10 +207,10 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
//FIXME make this not onblur //FIXME make this not onblur
CPTextFieldDOMInputElement.onblur = CPTextFieldBlurFunction; CPTextFieldDOMInputElement.onblur = CPTextFieldBlurFunction;
CPTextFieldDOMStandardInputElement = CPTextFieldDOMInputElement; CPTextFieldDOMStandardInputElement = CPTextFieldDOMInputElement;
} }
if (CPFeatureIsCompatible(CPInputTypeCanBeChangedFeature)) if (CPFeatureIsCompatible(CPInputTypeCanBeChangedFeature))
{ {
if ([self isSecure]) if ([self isSecure])
@@ -237,14 +237,14 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
CPTextFieldDOMPasswordInputElement.onblur = CPTextFieldBlurFunction; CPTextFieldDOMPasswordInputElement.onblur = CPTextFieldBlurFunction;
} }
CPTextFieldDOMInputElement = CPTextFieldDOMPasswordInputElement; CPTextFieldDOMInputElement = CPTextFieldDOMPasswordInputElement;
} }
else else
{ {
CPTextFieldDOMInputElement = CPTextFieldDOMStandardInputElement; CPTextFieldDOMInputElement = CPTextFieldDOMStandardInputElement;
} }
return CPTextFieldDOMInputElement; return CPTextFieldDOMInputElement;
} }
#endif #endif
@@ -262,29 +262,18 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
[self setValue:CPLeftTextAlignment forThemeAttribute:@"alignment"]; [self setValue:CPLeftTextAlignment forThemeAttribute:@"alignment"];
} }
return self; return self;
} }
#pragma mark Controlling Editability and Selectability #pragma mark Controlling Editability and Selectability
/*! /*!
Sets whether or not the receiver text field can be edited. If NO, any Sets whether or not the receiver text field can be edited
ongoing edit is ended.
*/ */
- (void)setEditable:(BOOL)shouldBeEditable - (void)setEditable:(BOOL)shouldBeEditable
{ {
if (_isEditable === shouldBeEditable)
return;
_isEditable = shouldBeEditable; _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];
} }
/*! /*!
@@ -295,19 +284,6 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
return _isEditable; 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. Sets whether the field's text is selectable by the user.
@param aFlag \c YES makes the text selectable @param aFlag \c YES makes the text selectable
@@ -370,7 +346,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
- (void)setBezelStyle:(CPTextFieldBezelStyle)aBezelStyle - (void)setBezelStyle:(CPTextFieldBezelStyle)aBezelStyle
{ {
var shouldBeRounded = aBezelStyle === CPTextFieldRoundedBezel; var shouldBeRounded = aBezelStyle === CPTextFieldRoundedBezel;
if (shouldBeRounded) if (shouldBeRounded)
[self setThemeState:CPTextFieldStateRounded]; [self setThemeState:CPTextFieldStateRounded];
else else
@@ -416,9 +392,9 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
{ {
if (_drawsBackground == shouldDrawBackground) if (_drawsBackground == shouldDrawBackground)
return; return;
_drawsBackground = shouldDrawBackground; _drawsBackground = shouldDrawBackground;
[self setNeedsLayout]; [self setNeedsLayout];
[self setNeedsDisplay:YES]; [self setNeedsDisplay:YES];
} }
@@ -439,9 +415,9 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
{ {
if (_textFieldBackgroundColor == aColor) if (_textFieldBackgroundColor == aColor)
return; return;
_textFieldBackgroundColor = aColor; _textFieldBackgroundColor = aColor;
[self setNeedsLayout]; [self setNeedsLayout];
[self setNeedsDisplay:YES]; [self setNeedsDisplay:YES];
} }
@@ -504,31 +480,24 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
_DOMElement.appendChild(element); _DOMElement.appendChild(element);
window.setTimeout(function() window.setTimeout(function()
{ {
element.focus(); element.focus();
// Select the text if the textfield became first responder through keyboard interaction
if (!_willBecomeFirstResponderByClick)
[self selectText:self];
_willBecomeFirstResponderByClick = NO;
[self textDidFocus:[CPNotification notificationWithName:CPTextFieldDidFocusNotification object:self userInfo:nil]]; [self textDidFocus:[CPNotification notificationWithName:CPTextFieldDidFocusNotification object:self userInfo:nil]];
CPTextFieldInputOwner = self; CPTextFieldInputOwner = self;
}, 0.0); }, 0.0);
element.value = [self stringValue]; element.value = [self stringValue];
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES]; [[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
CPTextFieldInputIsActive = YES; CPTextFieldInputIsActive = YES;
if (document.attachEvent) if (document.attachEvent)
{ {
CPTextFieldCachedSelectStartFunction = [[self window] platformWindow]._DOMBodyElement.onselectstart; CPTextFieldCachedSelectStartFunction = [[self window] platformWindow]._DOMBodyElement.onselectstart;
CPTextFieldCachedDragFunction = [[self window] platformWindow]._DOMBodyElement.ondrag; CPTextFieldCachedDragFunction = [[self window] platformWindow]._DOMBodyElement.ondrag;
[[self window] platformWindow]._DOMBodyElement.ondrag = function () {}; [[self window] platformWindow]._DOMBodyElement.ondrag = function () {};
[[self window] platformWindow]._DOMBodyElement.onselectstart = function () {}; [[self window] platformWindow]._DOMBodyElement.onselectstart = function () {};
} }
@@ -550,15 +519,14 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
var element = [self _inputElement]; var element = [self _inputElement];
if ([self stringValue] !== element.value) [self setObjectValue:element.value];
[self _setStringValue:element.value];
CPTextFieldInputResigning = YES; CPTextFieldInputResigning = YES;
element.blur(); element.blur();
if (!CPTextFieldInputDidBlur) if (!CPTextFieldInputDidBlur)
CPTextFieldBlurFunction(); CPTextFieldBlurFunction();
CPTextFieldInputDidBlur = NO; CPTextFieldInputDidBlur = NO;
CPTextFieldInputResigning = NO; CPTextFieldInputResigning = NO;
@@ -569,13 +537,13 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
if (document.attachEvent) if (document.attachEvent)
{ {
[[self window] platformWindow]._DOMBodyElement.ondrag = CPTextFieldCachedDragFunction;
[[self window] platformWindow]._DOMBodyElement.onselectstart = CPTextFieldCachedSelectStartFunction;
CPTextFieldCachedSelectStartFunction = nil; CPTextFieldCachedSelectStartFunction = nil;
CPTextFieldCachedDragFunction = nil; CPTextFieldCachedDragFunction = nil;
[[self window] platformWindow]._DOMBodyElement.ondrag = CPTextFieldCachedDragFunction;
[[self window] platformWindow]._DOMBodyElement.onselectstart = CPTextFieldCachedSelectStartFunction;
} }
#endif #endif
//post CPControlTextDidEndEditingNotification //post CPControlTextDidEndEditingNotification
@@ -605,50 +573,21 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
{ {
// Don't track! (ever?) // Don't track! (ever?)
if ([self isEditable] && [self isEnabled]) if ([self isEditable] && [self isEnabled])
{ return [[self window] makeFirstResponder:self];
_willBecomeFirstResponderByClick = YES;
[[self window] makeFirstResponder:self];
}
else if ([self isSelectable])
{
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 () {};
}
return [[[anEvent window] platformWindow] _propagateCurrentDOMEvent:YES];
}
else else
return [[self nextResponder] mouseDown:anEvent]; return [[self nextResponder] mouseDown:anEvent];
} }
- (void)mouseUp:(CPEvent)anEvent - (void)mouseUp:(CPEvent)anEvent
{ {
if (![self isSelectable] && (![self isEditable] || ![self isEnabled])) if (![self isEditable] || ![self isEnabled])
[[self nextResponder] mouseUp:anEvent]; [[self nextResponder] mouseUp:anEvent];
else if ([self isSelectable])
{
if (document.attachEvent)
{
[[self window] platformWindow]._DOMBodyElement.ondrag = CPTextFieldCachedDragFunction;
[[self window] platformWindow]._DOMBodyElement.onselectstart = CPTextFieldCachedSelectStartFunction;
CPTextFieldCachedSelectStartFunction = nil
CPTextFieldCachedDragFunction = nil;
}
return [[[anEvent window] platformWindow] _propagateCurrentDOMEvent:YES];
}
} }
- (void)mouseDragged:(CPEvent)anEvent - (void)mouseDragged:(CPEvent)anEvent
{ {
if (![self isSelectable] && (![self isEditable] || ![self isEnabled])) if (![self isEditable] || ![self isEnabled])
[[self nextResponder] mouseDragged:anEvent]; [[self nextResponder] mouseDragged:anEvent];
else if ([self isSelectable])
return [[[anEvent window] platformWindow] _propagateCurrentDOMEvent:YES];
} }
- (void)keyUp:(CPEvent)anEvent - (void)keyUp:(CPEvent)anEvent
@@ -685,16 +624,29 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
[[[self window] platformWindow] _propagateCurrentDOMEvent:NO]; [[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
} }
else if ([anEvent keyCode] === CPTabKeyCode)
{
if ([anEvent modifierFlags] & CPShiftKeyMask)
[[self window] selectPreviousKeyView:self];
else
[[self window] selectNextKeyView:self];
if ([[[self window] firstResponder] respondsToSelector:@selector(selectText:)])
[[[self window] firstResponder] selectText:self];
[[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
}
else else
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES]; [[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode]; [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
} }
- (void)textDidBlur:(CPNotification)note - (void)textDidBlur:(CPNotification)note
{ {
// this looks to prevent false propagation of notifications for other objects //this looks to prevent false propagation of notifications for other objects
if ([note object] != self) if([note object] != self)
return; return;
[[CPNotificationCenter defaultCenter] postNotification:note]; [[CPNotificationCenter defaultCenter] postNotification:note];
@@ -702,22 +654,13 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
- (void)textDidFocus:(CPNotification)note - (void)textDidFocus:(CPNotification)note
{ {
// this looks to prevent false propagation of notifications for other objects //this looks to prevent false propagation of notifications for other objects
if ([note object] != self) if([note object] != self)
return; return;
[[CPNotificationCenter defaultCenter] postNotification:note]; [[CPNotificationCenter defaultCenter] postNotification:note];
} }
- (void)sendAction:(SEL)anAction to:(id)anObject
{
// Don't reverse set our empty value
if (!_currentValueIsPlaceholder)
[self _reverseSetBinding];
[CPApp sendAction:anAction to:anObject from:self];
}
/*! /*!
Returns the string the text field. Returns the string the text field.
*/ */
@@ -740,7 +683,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
- (void)setObjectValue:(id)aValue - (void)setObjectValue:(id)aValue
{ {
[super setObjectValue:aValue]; [super setObjectValue:aValue];
#if PLATFORM(DOM) #if PLATFORM(DOM)
if (CPTextFieldInputOwner === self || [[self window] firstResponder] === self) if (CPTextFieldInputOwner === self || [[self window] firstResponder] === self)
@@ -764,11 +707,11 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
Sets a placeholder string for the receiver. The placeholder is displayed until editing begins, Sets a placeholder string for the receiver. The placeholder is displayed until editing begins,
and after editing ends, if the text field has an empty string value and after editing ends, if the text field has an empty string value
*/ */
- (void)setPlaceholderString:(CPString)aStringValue -(void)setPlaceholderString:(CPString)aStringValue
{ {
if (_placeholderString === aStringValue) if (_placeholderString === aStringValue)
return; return;
_placeholderString = aStringValue; _placeholderString = aStringValue;
// Only update things if we need to show the placeholder // Only update things if we need to show the placeholder
@@ -787,101 +730,43 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
return _placeholderString; return _placeholderString;
} }
- (void)_setCurrentValueIsPlaceholder:(BOOL)isPlaceholder
{
// The initial _currentValueIsPlaceholder is null so convert it to NO for comparison purposes.
if (!!_currentValueIsPlaceholder === isPlaceholder)
return;
if (isPlaceholder)
{
// Save the original placeholder value so we can restore it later
// Only do this if the placeholder is not already overridden because the bindings logic might call this method
// several times and we don't want the bindings placeholder to ever become the original placeholder
if (!_currentValueIsPlaceholder)
_originalPlaceholderString = [self placeholderString];
// Set the current string value as the current placeholder and clear the string value
[self setPlaceholderString:[self stringValue]];
[self setStringValue:@""];
}
else
{
// Restore the original placeholder, the actual textfield value is already correct
// because it was set using setValue:forKey:
[self setPlaceholderString:_originalPlaceholderString];
}
_currentValueIsPlaceholder = isPlaceholder;
}
/*! /*!
For non-bezeled text fields (typically a label), sizeToFit has two behaviors, depending Size to fit has two behavior, depending on if the receiver is an editable text field or not.
on the line break mode of the receiver.
For non-editable text fields (typically, a label), sizeToFit will change the frame of the
For non-bezeled receivers with a non-wrapping line break mode, sizeToFit will change the frame of the receiver to perfectly fit the current text in stringValue in the current font, and respecting
receiver to perfectly fit the current text in stringValue in the current font, respecting the current theme values for content-inset, min-size, and max-size.
the current theme value for content-inset. For receivers with a wrapping line break mode,
sizeToFit will wrap the text within the current width (respecting the current content-inset), For editable text fields, sizeToFit will ONLY change the HEIGHT of the text field. It will not
so it will ONLY change the HEIGHT. 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 bezeled text fields (typically editable fields), sizeToFit will ONLY change the HEIGHT
of the text field. It will not change the width of the text field. sizeToFit will attempt to
change the height to fit a single line of text, respecting the current theme values for min-size,
max-size and content-inset.
The logic behind this decision is that most of the time you do not know what content will be placed The logic behind this decision is that most of the time you do not know what content will be placed
in a bezeled 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 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. useful for making the textfield an appropriate height.
*/ */
- (void)sizeToFit - (void)sizeToFit
{ {
[self setFrameSize:[self _minimumFrameSize]]; var size = [([self stringValue] || " ") sizeWithFont:[self currentValueForThemeAttribute:@"font"]],
}
- (CGSize)_minimumFrameSize
{
var frameSize = [self frameSize],
contentInset = [self currentValueForThemeAttribute:@"content-inset"], contentInset = [self currentValueForThemeAttribute:@"content-inset"],
minSize = [self currentValueForThemeAttribute:@"min-size"], minSize = [self currentValueForThemeAttribute:@"min-size"],
maxSize = [self currentValueForThemeAttribute:@"max-size"], maxSize = [self currentValueForThemeAttribute:@"max-size"];
lineBreakMode = [self lineBreakMode],
text = ([self stringValue] || @" "),
textSize = _CGSizeMakeCopy(frameSize),
font = [self currentValueForThemeAttribute:@"font"];
textSize.width -= contentInset.left + contentInset.right; size.width = MAX(size.width + contentInset.left + contentInset.right, minSize.width);
textSize.height -= contentInset.top + contentInset.bottom; size.height = MAX(size.height + contentInset.top + contentInset.bottom, minSize.height);
if (frameSize.width !== 0 && if (maxSize.width >= 0.0)
![self isBezeled] && size.width = MIN(size.width, maxSize.width);
(lineBreakMode === CPLineBreakByWordWrapping || lineBreakMode === CPLineBreakByCharWrapping))
{
textSize = [text sizeWithFont:font inWidth:textSize.width];
}
else
textSize = [text sizeWithFont:font];
frameSize.height = textSize.height + contentInset.top + contentInset.bottom; if (maxSize.height >= 0.0)
size.height = MIN(size.height, maxSize.height);
if ([self isBezeled]) if ([self isEditable])
{ size.width = CGRectGetWidth([self frame]);
frameSize.height = MAX(frameSize.height, minSize.height);
if (maxSize.width > 0.0) [self setFrameSize:size];
frameSize.width = MIN(frameSize.width, maxSize.width);
if (maxSize.height > 0.0)
frameSize.height = MIN(frameSize.height, maxSize.height);
}
else
frameSize.width = textSize.width + contentInset.left + contentInset.right;
frameSize.width = MAX(frameSize.width, minSize.width);
return frameSize;
} }
/*! /*!
@@ -891,13 +776,16 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
{ {
#if PLATFORM(DOM) #if PLATFORM(DOM)
var element = [self _inputElement]; var element = [self _inputElement];
if (([self isEditable] || [self isSelectable])) if (([self isEditable] || [self isSelectable]))
{ {
if ([[self window] firstResponder] === self) if ([[self window] firstResponder] === self)
window.setTimeout(function() { element.select(); }, 0); window.setTimeout(function() { element.select(); }, 0);
else if ([self window] !== nil && [[self window] makeFirstResponder:self]) else
{
[[self window] makeFirstResponder:self];
window.setTimeout(function() {[self selectText:sender];}, 0); window.setTimeout(function() {[self selectText:sender];}, 0);
}
} }
#endif #endif
} }
@@ -946,7 +834,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:pasteString]; newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:pasteString];
[self setStringValue:newValue]; [self setStringValue:newValue];
[self setSelectedRange:CPMakeRange(selectedRange.location + pasteString.length, 0)]; [self setSelectedRange:CPMakeRange(selectedRange.location+pasteString.length, 0)];
} }
} }
@@ -956,14 +844,14 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
return CPMakeRange(0, 0); return CPMakeRange(0, 0);
// we wrap this in try catch because firefox will throw an exception in certain instances // we wrap this in try catch because firefox will throw an exception in certain instances
try try
{ {
var inputElement = [self _inputElement], var inputElement = [self _inputElement],
selectionStart = inputElement.selectionStart, selectionStart = inputElement.selectionStart,
selectionEnd = inputElement.selectionEnd; selectionEnd = inputElement.selectionEnd;
if ([selectionStart isKindOfClass:CPNumber]) if ([selectionStart isKindOfClass:CPNumber])
return CPMakeRange(selectionStart, selectionEnd - selectionStart); return CPMakeRange(selectionStart, selectionEnd - selectionStart);
// browsers which don't support selectionStart/selectionEnd (aka IE). // browsers which don't support selectionStart/selectionEnd (aka IE).
var theDocument = inputElement.ownerDocument || inputElement.document, var theDocument = inputElement.ownerDocument || inputElement.document,
@@ -975,8 +863,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
range.setEndPoint('EndToStart', selectionRange); range.setEndPoint('EndToStart', selectionRange);
return CPMakeRange(range.text.length, selectionRange.text.length); return CPMakeRange(range.text.length, selectionRange.text.length);
} }
} }
catch (e) catch (e)
{ {
// fall through to the return // fall through to the return
} }
@@ -991,7 +879,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
var inputElement = [self _inputElement]; var inputElement = [self _inputElement];
try try
{ {
if ([inputElement.selectionStart isKindOfClass:CPNumber]) if ([inputElement.selectionStart isKindOfClass:CPNumber])
{ {
@@ -1004,7 +892,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
var theDocument = inputElement.ownerDocument || inputElement.document, var theDocument = inputElement.ownerDocument || inputElement.document,
existingRange = theDocument.selection.createRange(), existingRange = theDocument.selection.createRange(),
range = inputElement.createTextRange(); range = inputElement.createTextRange();
if (range.inRange(existingRange)) if (range.inRange(existingRange))
{ {
range.collapse(true); range.collapse(true);
@@ -1039,7 +927,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
- (void)setDelegate:(id)aDelegate - (void)setDelegate:(id)aDelegate
{ {
var defaultCenter = [CPNotificationCenter defaultCenter]; var defaultCenter = [CPNotificationCenter defaultCenter];
//unsubscribe the existing delegate if it exists //unsubscribe the existing delegate if it exists
if (_delegate) if (_delegate)
{ {
@@ -1049,24 +937,24 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
[defaultCenter removeObserver:_delegate name:CPTextFieldDidFocusNotification object:self]; [defaultCenter removeObserver:_delegate name:CPTextFieldDidFocusNotification object:self];
[defaultCenter removeObserver:_delegate name:CPTextFieldDidBlurNotification object:self]; [defaultCenter removeObserver:_delegate name:CPTextFieldDidBlurNotification object:self];
} }
_delegate = aDelegate; _delegate = aDelegate;
if ([_delegate respondsToSelector:@selector(controlTextDidBeginEditing:)]) if ([_delegate respondsToSelector:@selector(controlTextDidBeginEditing:)])
[defaultCenter [defaultCenter
addObserver:_delegate addObserver:_delegate
selector:@selector(controlTextDidBeginEditing:) selector:@selector(controlTextDidBeginEditing:)
name:CPControlTextDidBeginEditingNotification name:CPControlTextDidBeginEditingNotification
object:self]; object:self];
if ([_delegate respondsToSelector:@selector(controlTextDidChange:)]) if ([_delegate respondsToSelector:@selector(controlTextDidChange:)])
[defaultCenter [defaultCenter
addObserver:_delegate addObserver:_delegate
selector:@selector(controlTextDidChange:) selector:@selector(controlTextDidChange:)
name:CPControlTextDidChangeNotification name:CPControlTextDidChangeNotification
object:self]; object:self];
if ([_delegate respondsToSelector:@selector(controlTextDidEndEditing:)]) if ([_delegate respondsToSelector:@selector(controlTextDidEndEditing:)])
[defaultCenter [defaultCenter
addObserver:_delegate addObserver:_delegate
@@ -1097,30 +985,30 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
- (CGRect)contentRectForBounds:(CGRect)bounds - (CGRect)contentRectForBounds:(CGRect)bounds
{ {
var contentInset = [self currentValueForThemeAttribute:@"content-inset"]; var contentInset = [self currentValueForThemeAttribute:@"content-inset"];
if (!contentInset) if (!contentInset)
return bounds; return bounds;
bounds.origin.x += contentInset.left; bounds.origin.x += contentInset.left;
bounds.origin.y += contentInset.top; bounds.origin.y += contentInset.top;
bounds.size.width -= contentInset.left + contentInset.right; bounds.size.width -= contentInset.left + contentInset.right;
bounds.size.height -= contentInset.top + contentInset.bottom; bounds.size.height -= contentInset.top + contentInset.bottom;
return bounds; return bounds;
} }
- (CGRect)bezelRectForBounds:(CGRect)bounds - (CGRect)bezelRectForBounds:(CFRect)bounds
{ {
var bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"]; var bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"];
if (_CGInsetIsEmpty(bezelInset)) if (_CGInsetIsEmpty(bezelInset))
return bounds; return bounds;
bounds.origin.x += bezelInset.left; bounds.origin.x += bezelInset.left;
bounds.origin.y += bezelInset.top; bounds.origin.y += bezelInset.top;
bounds.size.width -= bezelInset.left + bezelInset.right; bounds.size.width -= bezelInset.left + bezelInset.right;
bounds.size.height -= bezelInset.top + bezelInset.bottom; bounds.size.height -= bezelInset.top + bezelInset.bottom;
return bounds; return bounds;
} }
@@ -1128,10 +1016,10 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
{ {
if (aName === "bezel-view") if (aName === "bezel-view")
return [self bezelRectForBounds:[self bounds]]; return [self bezelRectForBounds:[self bounds]];
else if (aName === "content-view") else if (aName === "content-view")
return [self contentRectForBounds:[self bounds]]; return [self contentRectForBounds:[self bounds]];
return [super rectForEphemeralSubviewNamed:aName]; return [super rectForEphemeralSubviewNamed:aName];
} }
@@ -1142,19 +1030,19 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()]; var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
[view setHitTests:NO]; [view setHitTests:NO];
return view; return view;
} }
else else
{ {
var view = [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()]; var view = [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
//[view setImagePosition:CPNoImage]; //[view setImagePosition:CPNoImage];
[view setHitTests:NO]; [view setHitTests:NO];
return view; return view;
} }
return [super createEphemeralSubviewNamed:aName]; return [super createEphemeralSubviewNamed:aName];
} }
@@ -1163,10 +1051,10 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
var bezelView = [self layoutEphemeralSubviewNamed:@"bezel-view" var bezelView = [self layoutEphemeralSubviewNamed:@"bezel-view"
positioned:CPWindowBelow positioned:CPWindowBelow
relativeToEphemeralSubviewNamed:@"content-view"]; relativeToEphemeralSubviewNamed:@"content-view"];
if (bezelView) if (bezelView)
[bezelView setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]]; [bezelView setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
var contentView = [self layoutEphemeralSubviewNamed:@"content-view" var contentView = [self layoutEphemeralSubviewNamed:@"content-view"
positioned:CPWindowAbove positioned:CPWindowAbove
relativeToEphemeralSubviewNamed:@"bezel-view"]; relativeToEphemeralSubviewNamed:@"bezel-view"];
@@ -1176,7 +1064,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
[contentView setHidden:[self hasThemeState:CPThemeStateEditing]]; [contentView setHidden:[self hasThemeState:CPThemeStateEditing]];
var string = ""; var string = "";
if ([self hasThemeState:CPTextFieldStatePlaceholder]) if ([self hasThemeState:CPTextFieldStatePlaceholder])
string = [self placeholderString]; string = [self placeholderString];
else else
@@ -1199,22 +1087,6 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
} }
} }
- (void)takeValueFromKeyPath:(CPString)aKeyPath ofObjects:(CPArray)objects
{
var count = objects.length,
value = [objects[0] valueForKeyPath:aKeyPath];
[self setStringValue:value];
[self setPlaceholderString:@""];
while (count-- > 1)
if (value !== [objects[count] valueForKeyPath:aKeyPath])
{
[self setPlaceholderString:@"Multiple Values"];
[self setStringValue:@""];
}
}
@end @end
var secureStringForString = function(aString) var secureStringForString = function(aString)
@@ -1223,7 +1095,7 @@ var secureStringForString = function(aString)
if (!aString) if (!aString)
return ""; return "";
return Array(aString.length + 1).join(CPSecureTextFieldCharacter); return Array(aString.length+1).join(CPSecureTextFieldCharacter);
} }
@@ -1234,7 +1106,6 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
CPTextFieldBezelStyleKey = "CPTextFieldBezelStyleKey", CPTextFieldBezelStyleKey = "CPTextFieldBezelStyleKey",
CPTextFieldDrawsBackgroundKey = "CPTextFieldDrawsBackgroundKey", CPTextFieldDrawsBackgroundKey = "CPTextFieldDrawsBackgroundKey",
CPTextFieldLineBreakModeKey = "CPTextFieldLineBreakModeKey", CPTextFieldLineBreakModeKey = "CPTextFieldLineBreakModeKey",
CPTextFieldAlignmentKey = "CPTextFieldAlignmentKey",
CPTextFieldBackgroundColorKey = "CPTextFieldBackgroundColorKey", CPTextFieldBackgroundColorKey = "CPTextFieldBackgroundColorKey",
CPTextFieldPlaceholderStringKey = "CPTextFieldPlaceholderStringKey"; CPTextFieldPlaceholderStringKey = "CPTextFieldPlaceholderStringKey";
@@ -1248,7 +1119,7 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
- (id)initWithCoder:(CPCoder)aCoder - (id)initWithCoder:(CPCoder)aCoder
{ {
self = [super initWithCoder:aCoder]; self = [super initWithCoder:aCoder];
if (self) if (self)
{ {
[self setEditable:[aCoder decodeBoolForKey:CPTextFieldIsEditableKey]]; [self setEditable:[aCoder decodeBoolForKey:CPTextFieldIsEditableKey]];
@@ -1258,24 +1129,9 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
[self setTextFieldBackgroundColor:[aCoder decodeObjectForKey:CPTextFieldBackgroundColorKey]]; [self setTextFieldBackgroundColor:[aCoder decodeObjectForKey:CPTextFieldBackgroundColorKey]];
[self setLineBreakMode:[aCoder decodeIntForKey:CPTextFieldLineBreakModeKey]];
[self setAlignment:[aCoder decodeIntForKey:CPTextFieldAlignmentKey]];
[self setPlaceholderString:[aCoder decodeObjectForKey:CPTextFieldPlaceholderStringKey]]; [self setPlaceholderString:[aCoder decodeObjectForKey:CPTextFieldPlaceholderStringKey]];
// Make sure the frame is big enough
var minSize = [self _minimumFrameSize];
minSize.width = MAX(CGRectGetWidth([self frame]), minSize.width);
minSize.height = MAX(CGRectGetHeight([self frame]), minSize.height);
// Only size multiline bezeled textfields if it's to small to fit the content
if ([self isBezeled])
if ([self lineBreakMode] === CPLineBreakByCharWrapping || [self lineBreakMode] == CPLineBreakByWordWrapping)
minSize.height = MAX(CGRectGetHeight([self frame]), minSize.height);
[self setFrameSize:minSize];
} }
return self; return self;
} }
@@ -1286,17 +1142,14 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
- (void)encodeWithCoder:(CPCoder)aCoder - (void)encodeWithCoder:(CPCoder)aCoder
{ {
[super encodeWithCoder:aCoder]; [super encodeWithCoder:aCoder];
[aCoder encodeBool:_isEditable forKey:CPTextFieldIsEditableKey]; [aCoder encodeBool:_isEditable forKey:CPTextFieldIsEditableKey];
[aCoder encodeBool:_isSelectable forKey:CPTextFieldIsSelectableKey]; [aCoder encodeBool:_isSelectable forKey:CPTextFieldIsSelectableKey];
[aCoder encodeBool:_drawsBackground forKey:CPTextFieldDrawsBackgroundKey]; [aCoder encodeBool:_drawsBackground forKey:CPTextFieldDrawsBackgroundKey];
[aCoder encodeObject:_textFieldBackgroundColor forKey:CPTextFieldBackgroundColorKey]; [aCoder encodeObject:_textFieldBackgroundColor forKey:CPTextFieldBackgroundColorKey];
[aCoder encodeInt:[self lineBreakMode] forKey:CPTextFieldLineBreakModeKey];
[aCoder encodeInt:[self alignment] forKey:CPTextFieldAlignmentKey];
[aCoder encodeObject:_placeholderString forKey:CPTextFieldPlaceholderStringKey]; [aCoder encodeObject:_placeholderString forKey:CPTextFieldPlaceholderStringKey];
} }
+20 -188
View File
@@ -24,10 +24,8 @@
@import <Foundation/CPString.j> @import <Foundation/CPString.j>
@import <Foundation/CPKeyedUnarchiver.j> @import <Foundation/CPKeyedUnarchiver.j>
var CPThemesByName = { },
var CPThemesByName = { }, CPThemeDefaultTheme = nil;
CPThemeDefaultTheme = nil,
CPThemeDefaultHudTheme = nil;
/*! /*!
@@ -50,27 +48,6 @@ var CPThemesByName = { },
return CPThemeDefaultTheme; 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 + (CPTheme)themeNamed:(CPString)aName
{ {
return CPThemesByName[aName]; return CPThemesByName[aName];
@@ -96,110 +73,9 @@ var CPThemesByName = { },
return _name; 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' +defaultThemeClass method. For example, the name for CPCheckBox is "check-box",
as defined in CPCheckBox::themeClass.
*/
- (CPArray)classNames
{ {
return [_attributes allKeys]; var attributes = [_attributes objectForKey:aClass];
}
/*!
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(defaultThemeClass)])
className = [aClass defaultThemeClass];
else if ([aClass respondsToSelector:@selector(themeClass)])
{
CPLog.warn(@"%@ themeClass is deprecated in favor of defaultThemeClass",CPStringFromClass([anObject class]));
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) if (!attributes)
return nil; return nil;
@@ -207,53 +83,12 @@ var CPThemesByName = { },
return [attributes objectForKey:aName]; 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 - (void)takeThemeFromObject:(id)anObject
{ {
var attributes = [anObject _themeAttributeDictionary], var attributes = [anObject _themeAttributeDictionary],
attributeName = nil, attributeName = nil,
attributeNames = [attributes keyEnumerator], attributeNames = [attributes keyEnumerator],
objectThemeClass = [anObject themeClass]; objectThemeClass = [[anObject class] themeClass];
while (attributeName = [attributeNames nextObject]) while (attributeName = [attributeNames nextObject])
[self _recordAttribute:[attributes objectForKey:attributeName] forClass:objectThemeClass]; [self _recordAttribute:[attributes objectForKey:attributeName] forClass:objectThemeClass];
@@ -407,9 +242,6 @@ CPThemeStateNormal = CPThemeStates["normal"] = 0;
CPThemeStateDisabled = CPThemeState("disabled"); CPThemeStateDisabled = CPThemeState("disabled");
CPThemeStateHighlighted = CPThemeState("highlighted"); CPThemeStateHighlighted = CPThemeState("highlighted");
CPThemeStateSelected = CPThemeState("selected"); CPThemeStateSelected = CPThemeState("selected");
CPThemeStateTableDataView = CPThemeState("tableDataView");
CPThemeStateSelectedDataView = CPThemeStateSelectedTableDataView = CPThemeState("selectedTableDataView");
CPThemeStateGroupRow = CPThemeState("CPThemeStateGroupRow");
CPThemeStateBezeled = CPThemeState("bezeled"); CPThemeStateBezeled = CPThemeState("bezeled");
CPThemeStateBordered = CPThemeState("bordered"); CPThemeStateBordered = CPThemeState("bordered");
CPThemeStateEditable = CPThemeState("editable"); CPThemeStateEditable = CPThemeState("editable");
@@ -422,10 +254,10 @@ CPThemeStateCircular = CPThemeState("circular");
{ {
CPString _name; CPString _name;
id _defaultValue; id _defaultValue;
CPDictionary _values @accessors(readonly, getter=values); CPDictionary _values;
JSObject _cache; JSObject _cache;
_CPThemeAttribute _parentAttribute; CPThemeAttribute _parentAttribute;
} }
- (id)initWithName:(CPString)aName defaultValue:(id)aDefaultValue - (id)initWithName:(CPString)aName defaultValue:(id)aDefaultValue
@@ -546,7 +378,7 @@ CPThemeStateCircular = CPThemeState("circular");
return value; return value;
} }
- (void)setParentAttribute:(_CPThemeAttribute)anAttribute - (void)setParentAttribute:(CPThemeAttribute)anAttribute
{ {
if (_parentAttribute === anAttribute) if (_parentAttribute === anAttribute)
return; return;
@@ -555,7 +387,7 @@ CPThemeStateCircular = CPThemeState("circular");
_parentAttribute = anAttribute; _parentAttribute = anAttribute;
} }
- (_CPThemeAttribute)attributeMergedWithAttribute:(_CPThemeAttribute)anAttribute - (CPThemeAttribute)attributeMergedWithAttribute:(_CPThemeAttribute)anAttribute
{ {
var mergedAttribute = [[_CPThemeAttribute alloc] initWithName:_name defaultValue:_defaultValue]; var mergedAttribute = [[_CPThemeAttribute alloc] initWithName:_name defaultValue:_defaultValue];
@@ -640,15 +472,15 @@ CPThemeStateCircular = CPThemeState("circular");
@end @end
var cachedNumberOfOnes = [ 0 /*000000*/, 1 /*000001*/, 1 /*000010*/, 2 /*000011*/, 1 /*000100*/, 2 /*000101*/, 2 /*000110*/, 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 /*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 /*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 /*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 /*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 /*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 /*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 /*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*/, 3 /*111000*/, 4 /*111001*/, 4 /*111010*/, 5 /*111011*/, 4 /*111100*/, 5 /*111101*/, 5 /*111110*/,
6 /*111111*/ ]; 6 /*111111*/ ];
var numberOfOnes = function(aNumber) var numberOfOnes = function(aNumber)
@@ -719,7 +551,7 @@ function CPThemeAttributeDecode(aCoder, anAttributeName, aDefaultValue, aTheme,
} }
if (aTheme && aClass) if (aTheme && aClass)
[attribute setParentAttribute:[aTheme attributeWithName:anAttributeName forClass:aClass]]; [attribute setParentAttribute:[aTheme _attributeWithName:anAttributeName forClass:aClass]];
return attribute; return attribute;
} }
@@ -753,4 +585,4 @@ for (i = 0;i < Math.pow(2,6);++i)
} }
print(str+']'); print(str+']');
*/ */
+10 -34
View File
@@ -22,10 +22,9 @@
@import <Foundation/CPObject.j> @import <Foundation/CPObject.j>
@import "CPTheme.j" @import <AppKit/CPTheme.j>
@import "_CPCibCustomResource.j" @import <AppKit/_CPCibCustomResource.j>
@import "_CPCibKeyedUnarchiver.j" @import <AppKit/_CPCibKeyedUnarchiver.j>
/*! /*!
@ingroup appkit @ingroup appkit
@@ -34,60 +33,37 @@
@implementation CPThemeBlend : CPObject @implementation CPThemeBlend : CPObject
{ {
CPBundle _bundle; CPBundle _bundle;
CPArray _themes; CPArray _themes @accessors(readonly, getter=themes);
id _loadDelegate; id _loadDelegate;
} }
- (id)initWithContentsOfURL:(CPURL)aURL - (id)initWithContentsOfURL:(CPURL)aURL
{ {
self = [super init]; self = [super init];
if (self) if (self)
{ {
_bundle = [[CPBundle alloc] initWithPath:aURL]; _bundle = [[CPBundle alloc] initWithPath:aURL];
} }
return self; 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 - (void)loadWithDelegate:(id)aDelegate
{ {
_loadDelegate = aDelegate; _loadDelegate = aDelegate;
[_bundle loadWithDelegate:self]; [_bundle loadWithDelegate:self];
} }
- (void)bundleDidFinishLoading:(CPBundle)aBundle - (void)bundleDidFinishLoading:(CPBundle)aBundle
{ {
_themes = [_bundle objectForInfoDictionaryKey:@"CPKeyedThemes"]; var themes = [_bundle objectForInfoDictionaryKey:@"CPKeyedThemes"],
count = themes.length;
var count = _themes.length;
while (count--) while (count--)
{ {
var path = [aBundle pathForResource:_themes[count]], var path = [aBundle pathForResource:themes[count]],
unarchiver = [[_CPThemeKeyedUnarchiver alloc] unarchiver = [[_CPThemeKeyedUnarchiver alloc]
initForReadingWithData:[[CPURL URLWithString:path] staticResourceData] initForReadingWithData:[[CPURL URLWithString:path] staticResourceData]
bundle:_bundle]; bundle:_bundle];
File diff suppressed because it is too large Load Diff
+10 -21
View File
@@ -28,6 +28,8 @@
@import "CPPopUpButton.j" @import "CPPopUpButton.j"
@import "CPToolbarItem.j" @import "CPToolbarItem.j"
#include "CoreGraphics/CGGeometry.h"
/* /*
@global @global
@@ -327,11 +329,7 @@ var CPToolbarConfigurationsByIdentifier = nil;
return _itemsSortedByVisibilityPriority; return _itemsSortedByVisibilityPriority;
} }
/*! - (void)validateVisibleToolbarItems
Validates the visible toolbar items by sending a validate message to
each visible toolbar item.
*/
- (void)validateVisibleItems
{ {
var toolbarItems = [self visibleItems], var toolbarItems = [self visibleItems],
count = [toolbarItems count]; count = [toolbarItems count];
@@ -468,14 +466,7 @@ var CPToolbarIdentifierKey = @"CPToolbarIdentifierKey",
// specified, it will be read later and the resulting call to -setDelegate: // specified, it will be read later and the resulting call to -setDelegate:
// will cause -_reloadToolbarItems] to run again :-( // will cause -_reloadToolbarItems] to run again :-(
// FIXME: Can we make this better? // FIXME: Can we make this better?
[self _reloadToolbarItems];
// Do this at the end of the run loop to allow all the cib-stuff to
// finish (establishing connections, etc.).
[[CPRunLoop currentRunLoop]
performSelector:@selector(_reloadToolbarItems)
target:self
argument:nil
order:0 modes:[CPDefaultRunLoopMode]];
} }
return self; return self;
@@ -568,7 +559,6 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
[_additionalItemsButton setImagePosition:CPImageOnly]; [_additionalItemsButton setImagePosition:CPImageOnly];
[[_additionalItemsButton menu] setShowsStateColumn:NO]; [[_additionalItemsButton menu] setShowsStateColumn:NO];
[[_additionalItemsButton menu] setAutoenablesItems:NO];
[_additionalItemsButton setAlternateImage:_CPToolbarViewExtraItemsAlternateImage]; [_additionalItemsButton setAlternateImage:_CPToolbarViewExtraItemsAlternateImage];
} }
@@ -799,13 +789,14 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
hasNonSeparatorItem = YES; hasNonSeparatorItem = YES;
var menuItem = [[CPMenuItem alloc] initWithTitle:[item label] action:[item action] keyEquivalent:nil]; [_additionalItemsButton addItemWithTitle:[item label]];
var menuItem = [_additionalItemsButton itemArray][index + 1];
[menuItem setImage:[item image]]; [menuItem setImage:[item image]];
[menuItem setTarget:[item target]];
[menuItem setEnabled:[item isEnabled]];
[_additionalItemsButton addItem:menuItem]; [menuItem setTarget:[item target]];
[menuItem setAction:[item action]];
} }
} }
else else
@@ -979,7 +970,7 @@ var TOP_MARGIN = 5.0,
{ {
_imageView = [[CPImageView alloc] initWithFrame:[self bounds]]; _imageView = [[CPImageView alloc] initWithFrame:[self bounds]];
[_imageView setImageScaling:CPScaleProportionally]; [_imageView setImageScaling:CPScaleNone];
[self addSubview:_imageView]; [self addSubview:_imageView];
} }
@@ -1060,8 +1051,6 @@ var TOP_MARGIN = 5.0,
[_imageView setAlphaValue:0.5]; [_imageView setAlphaValue:0.5];
[_labelField setAlphaValue:0.5]; [_labelField setAlphaValue:0.5];
} }
[_toolbar tile];
} }
- (CPColor)FIXME_labelColor - (CPColor)FIXME_labelColor
+6 -6
View File
@@ -23,9 +23,8 @@
@import <Foundation/CPObject.j> @import <Foundation/CPObject.j>
@import <Foundation/CPString.j> @import <Foundation/CPString.j>
@import "CPImage.j" @import <AppKit/CPImage.j>
@import "CPView.j" @import <AppKit/CPView.j>
CPToolbarItemVisibilityPriorityStandard = 0; CPToolbarItemVisibilityPriorityStandard = 0;
CPToolbarItemVisibilityPriorityLow = -1000; CPToolbarItemVisibilityPriorityLow = -1000;
@@ -450,9 +449,6 @@ CPToolbarItemVisibilityPriorityUser
- (void)validate - (void)validate
{ {
var action = [self action],
target = [self target];
// View items do not do any target-action analysis. // View items do not do any target-action analysis.
if (_view) if (_view)
{ {
@@ -462,9 +458,13 @@ CPToolbarItemVisibilityPriorityUser
return; return;
} }
var action = [self action];
if (!action) if (!action)
return [self setEnabled:NO]; return [self setEnabled:NO];
var target = [self target];
if (target && ![target respondsToSelector:action]) if (target && ![target respondsToSelector:action])
return [self setEnabled:NO]; return [self setEnabled:NO];
-197
View File
@@ -87,40 +87,6 @@
[_childNodes[count] sortWithSortDescriptors:sortDescriptors recursively:YES]; [_childNodes[count] sortWithSortDescriptors:sortDescriptors recursively:YES];
} }
- (CPEnumerator)preOrder
{
return [_CPTreeNodeEnumerator enumeratorWithTreeNode:self order:_CPTreeNodeEnumeratorPreOrder];
}
- (CPEnumerator)inOrder
{
return [_CPTreeNodeEnumerator enumeratorWithTreeNode:self order:_CPTreeNodeEnumeratorInOrder];
}
- (CPEnumerator)postOrder
{
return [_CPTreeNodeEnumerator enumeratorWithTreeNode:self order:_CPTreeNodeEnumeratorPostOrder];
}
- (CPEnumerator)levelOrder
{
return [_CPTreeNodeEnumerator enumeratorWithTreeNode:self order:_CPTreeNodeEnumeratorLevelOrder];
}
- (int)countByEnumeratingWithState:(id)aState objects:(id)objects count:(id)aCount
{
if (aState.state !== 0)
return 0;
// FIXME: Change this to inorder when implemented?
var count = [[self preOrder] countByEnumeratingWithState:aState objects:objects count:aCount];
// Dangerous?
aState.state = YES;
return count;
}
@end @end
var CPTreeNodeRepresentedObjectKey = @"CPTreeNodeRepresentedObjectKey", var CPTreeNodeRepresentedObjectKey = @"CPTreeNodeRepresentedObjectKey",
@@ -151,166 +117,3 @@ var CPTreeNodeRepresentedObjectKey = @"CPTreeNodeRepresentedObjectKey",
} }
@end @end
var _CPTreeNodeEnumeratorPreOrder = 0,
_CPTreeNodeEnumeratorInOrder = 1,
_CPTreeNodeEnumeratorPostOrder = 2,
_CPTreeNodeEnumeratorLevelOrder = 3;
@implementation _CPTreeNodeEnumerator : CPEnumerator
{
int _order;
Object _state;
CPTreeNode _treeNode;
}
+ (_CPTreeNodeEnumerator)enumeratorWithTreeNode:(CPTreeNode)aTreeNode order:(int)anOrder
{
return [[self alloc] initWithTreeNode:aTreeNode order:anOrder];
}
- (id)initWithTreeNode:(CPTreeNode)aTreeNode order:(int)anOrder
{
self = [super init];
if (self)
{
_order = anOrder
_state = [self _newState];
_treeNode = aTreeNode;
}
return self;
}
- (id)_newState
{
return { stack:[_treeNode], visited:[CPSet set] };
}
- (id)_preOrderFromState:(Object)state allObjects:(BOOL)shouldReturnAllObjects
{
var stack = state.stack;
if (stack.length <= 0)
return nil;
if (shouldReturnAllObjects)
var allObjects = [];
while (stack.length)
{
var currentNode = stack.pop(),
childNodes = currentNode._childNodes,
count = childNodes.length;
while (count--)
stack.push(childNodes[count]);
if (shouldReturnAllObjects)
allObjects.push(currentNode);
else
return currentNode;
}
return allObjects;
}
- (id)_inOrderFromState:(Object)state allObjects:(BOOL)shouldReturnAllObjects
{
// Implement.
}
- (id)_postOrderFromState:(Object)state allObjects:(BOOL)shouldReturnAllObjects
{
var stack = state.stack;
if (stack.length <= 0)
return nil;
var visited = state.visited;
if (shouldReturnAllObjects)
var allObjects = [];
while (stack.length)
{
var currentNode = [stack lastObject],
childNodes = currentNode._childNodes,
originalCount = stack.length,
count = childNodes.length;
while (count--)
{
var treeNode = childNodes[count];
if ([visited containsObject:treeNode])
continue;
else
stack.push(treeNode);
}
if (originalCount === stack.length)
{
[visited addObject:currentNode];
if (shouldReturnAllObjects)
allObjects.push(stack.pop());
else
return stack.pop();
}
}
return allObjects;
}
- (id)_levelOrderFromState:(Object)state allObjects:(BOOL)shouldReturnAllObjects
{
// Implement.
}
- (id)nextObject
{
if (_order === _CPTreeNodeEnumeratorPreOrder)
return [self _preOrderFromState:[self _newState] allObjects:NO];
else if (_order === _CPTreeNodeEnumeratorInOrder)
return [self _inOrderFromState:[self _newState] allObjects:NO];
else if (_order === _CPTreeNodeEnumeratorPostOrder)
return [self _postOrderFromState:[self _newState] allObjects:NO];
//else if (_order === _CPTreeNodeEnumeratorLevelOrder)
return [self _levelOrderFromState:[self _newState] allObjects:NO];
}
- (CPArray)allObjects
{
if (_order === _CPTreeNodeEnumeratorPreOrder)
return [self _preOrderFromState:[self _newState] allObjects:YES];
else if (_order === _CPTreeNodeEnumeratorInOrder)
return [self _inOrderFromState:[self _newState] allObjects:YES];
else if (_order === _CPTreeNodeEnumeratorPostOrder)
return [self _postOrderFromState:[self _newState] allObjects:YES];
//else if (_order === _CPTreeNodeEnumeratorLevelOrder)
return [self _levelOrderFromState:[self _newState] allObjects:NO];
}
- (int)countByEnumeratingWithState:(id)aState objects:(id)objects count:(id)aCount
{
if (aState.state !== 0)
return 0;
var count = [[self allObjects] countByEnumeratingWithState:aState objects:objects count:aCount];
// Dangerous?
aState.state = YES;
return count;
}
@end
+215 -326
View File
File diff suppressed because it is too large Load Diff
+12 -13
View File
@@ -1,5 +1,5 @@
/* /*
* CPViewAnimation.j * CPFlashView.j
* AppKit * AppKit
* *
* Created by Klaas Pieter Annema on September 3, 2009. * Created by Klaas Pieter Annema on September 3, 2009.
@@ -20,8 +20,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
@import "CPAnimation.j" @import <AppKit/CPAnimation.j>
CPViewAnimationTargetKey = @"CPViewAnimationTarget"; CPViewAnimationTargetKey = @"CPViewAnimationTarget";
CPViewAnimationStartFrameKey = @"CPViewAnimationStartFrame"; CPViewAnimationStartFrameKey = @"CPViewAnimationStartFrame";
@@ -70,7 +69,7 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut";
[super startAnimation]; [super startAnimation];
} }
- (void)setCurrentProgress:(CPAnimationProgress)progress - (void)setCurrentProgress:(NSAnimationProgress)progress
{ {
[super setCurrentProgress:progress]; [super setCurrentProgress:progress];
@@ -78,17 +77,17 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut";
while (animationIndex--) while (animationIndex--)
{ {
var dictionary = [_viewAnimations objectAtIndex:animationIndex], var dictionary = [_viewAnimations objectAtIndex:animationIndex],
view = [self _targetView:dictionary], view = [self _targetView:dictionary]
startFrame = [self _startFrame:dictionary], startFrame = [self _startFrame:dictionary]
endFrame = [self _endFrame:dictionary], endFrame = [self _endFrame:dictionary]
differenceFrame = _CGRectMakeZero(); differenceFrame = CPRectMakeZero();
differenceFrame.origin.x = endFrame.origin.x - startFrame.origin.x; differenceFrame.origin.x = endFrame.origin.x - startFrame.origin.x;
differenceFrame.origin.y = endFrame.origin.y - startFrame.origin.y; differenceFrame.origin.y = endFrame.origin.y - startFrame.origin.y;
differenceFrame.size.width = endFrame.size.width - startFrame.size.width; differenceFrame.size.width = endFrame.size.width - startFrame.size.width;
differenceFrame.size.height = endFrame.size.height - startFrame.size.height; differenceFrame.size.height = endFrame.size.height - startFrame.size.height;
var intermediateFrame = _CGRectMakeZero(); var intermediateFrame = CPRectMakeZero();
intermediateFrame.origin.x = startFrame.origin.x + differenceFrame.origin.x * progress; intermediateFrame.origin.x = startFrame.origin.x + differenceFrame.origin.x * progress;
intermediateFrame.origin.y = startFrame.origin.y + differenceFrame.origin.y * progress; intermediateFrame.origin.y = startFrame.origin.y + differenceFrame.origin.y * progress;
intermediateFrame.size.width = startFrame.size.width + differenceFrame.size.width * progress; intermediateFrame.size.width = startFrame.size.width + differenceFrame.size.width * progress;
@@ -104,7 +103,7 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut";
[view setAlphaValue:1.0 + ( 0.0 - 1.0 ) * progress]; [view setAlphaValue:1.0 + ( 0.0 - 1.0 ) * progress];
if (progress === 1.0) if (progress === 1.0)
[view setHidden:_CGRectIsNull(endFrame) || [view alphaValue] === 0.0]; [view setHidden:CPRectIsNull(endFrame) || [view alphaValue] === 0.0];
} }
} }
@@ -125,7 +124,7 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut";
else if (effect === CPViewAnimationFadeOutEffect) else if (effect === CPViewAnimationFadeOutEffect)
[view setAlphaValue:0.0]; [view setAlphaValue:0.0];
[view setHidden:_CGRectIsNull(endFrame) || [view alphaValue] === 0.0]; [view setHidden:CPRectIsNull(endFrame) || [view alphaValue] === 0.0];
} }
[super stopAnimation]; [super stopAnimation];
@@ -140,7 +139,7 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut";
return targetView; return targetView;
} }
- (CGRect)_startFrame:(CPDictionary)dictionary - (CPRect)_startFrame:(CPDictionary)dictionary
{ {
var startFrame = [dictionary valueForKey:CPViewAnimationStartFrameKey]; var startFrame = [dictionary valueForKey:CPViewAnimationStartFrameKey];
if (!startFrame) if (!startFrame)
@@ -149,7 +148,7 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut";
return startFrame; return startFrame;
} }
- (CGRect)_endFrame:(CPDictionary)dictionary - (CPRect)_endFrame:(CPDictionary)dictionary
{ {
var endFrame = [dictionary valueForKey:CPViewAnimationEndFrameKey]; var endFrame = [dictionary valueForKey:CPViewAnimationEndFrameKey];
if (!endFrame) if (!endFrame)
+61 -27
View File
@@ -20,12 +20,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
@import <Foundation/CPArray.j> @import <AppKit/CPResponder.j>
@import "CPApplication.j"
@import "CPCib.j"
@import "CPResponder.j"
var CPViewControllerCachedCibs; var CPViewControllerCachedCibs;
@@ -52,11 +47,10 @@ var CPViewControllerCachedCibs;
*/ */
@implementation CPViewController : CPResponder @implementation CPViewController : CPResponder
{ {
CPView _view @accessors(property=view); CPView _view;
BOOL _isLoading;
id _representedObject @accessors(property=representedObject); id _representedObject @accessors(property=representedObject);
CPString _title @accessors(property=title); CPString _title;
CPString _cibName @accessors(property=cibName, readonly); CPString _cibName @accessors(property=cibName, readonly);
CPBundle _cibBundle @accessors(property=cibBundle, readonly); CPBundle _cibBundle @accessors(property=cibBundle, readonly);
@@ -84,7 +78,9 @@ var CPViewControllerCachedCibs;
- (id)initWithCibName:(CPString)aCibNameOrNil bundle:(CPBundle)aCibBundleOrNil owner:(id)anOwner - (id)initWithCibName:(CPString)aCibNameOrNil bundle:(CPBundle)aCibBundleOrNil owner:(id)anOwner
{ {
return [self initWithCibName:aCibNameOrNil bundle:aCibBundleOrNil externalNameTable:[CPDictionary dictionaryWithObject:anOwner forKey:CPCibOwner]]; return [self initWithCibName:aCibNameOrNil
bundle:aCibBundleOrNil
externalNameTable:[CPDictionary dictionaryWithObject:anOwner forKey:CPCibOwner]];
} }
/*! /*!
@@ -103,15 +99,34 @@ var CPViewControllerCachedCibs;
{ {
// Don't load the cib until someone actually requests the view. The user may just be intending to use setView:. // Don't load the cib until someone actually requests the view. The user may just be intending to use setView:.
_cibName = aCibNameOrNil; _cibName = aCibNameOrNil;
_cibBundle = aCibBundleOrNil || [CPBundle mainBundle]; _cibBundle = aCibBundleOrNil;
_cibExternalNameTable = anExternalNameTable || [CPDictionary dictionaryWithObject:self forKey:CPCibOwner];
_isLoading = NO; if (!_cibBundle)
{
var owner = [anExternalNameTable objectForKey:CPCibOwner];
_cibBundle = owner ? [CPBundle bundleForClass:[owner class]] : [CPBundle mainBundle];
}
_cibExternalNameTable = anExternalNameTable || [CPDictionary dictionaryWithObject:self forKey:CPCibOwner];
} }
return self; return self;
} }
- (void)setTitle:(CPString)aTitle
{
_title = aTitle;
if (self._navigationItem)
[_navigationItem setTitle:aTitle];
}
- (CPString)title
{
return _title;
}
/*! /*!
Programmatically creates the view that the controller manages. Programmatically creates the view that the controller manages.
You should never call this method directly. The view controller calls this method when the view property is requested but is nil. You should never call this method directly. The view controller calls this method when the view property is requested but is nil.
@@ -119,22 +134,22 @@ 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. 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. 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, you initialize the view using the 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. 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 synchronous. Note: The cib loading system is currently asynchronous.
*/ */
- (void)loadView - (void)loadView
{ {
if (_view) if (_view)
return; return;
// check if a cib is already cached for the current _cibName // check if a cib is already cached for the current _cibName
var cib = [CPViewControllerCachedCibs objectForKey:_cibName]; var cib = [CPViewControllerCachedCibs objectForKey:_cibName];
// If the cib isn't cached yet : fetch it and cache it
if (!cib) if (!cib)
{ {
// if the cib isn't cached yet : fetch it and cache it
cib = [[CPCib alloc] initWithContentsOfURL:[_cibBundle pathForResource:_cibName + @".cib"]]; cib = [[CPCib alloc] initWithContentsOfURL:[_cibBundle pathForResource:_cibName + @".cib"]];
[CPViewControllerCachedCibs setObject:cib forKey:_cibName]; [CPViewControllerCachedCibs setObject:cib forKey:_cibName];
} }
@@ -151,8 +166,6 @@ var CPViewControllerCachedCibs;
{ {
if (!_view) if (!_view)
{ {
_isLoading = YES;
var cibOwner = [_cibExternalNameTable objectForKey:CPCibOwner]; var cibOwner = [_cibExternalNameTable objectForKey:CPCibOwner];
if ([cibOwner respondsToSelector:@selector(viewControllerWillLoadCib:)]) if ([cibOwner respondsToSelector:@selector(viewControllerWillLoadCib:)])
@@ -173,7 +186,6 @@ var CPViewControllerCachedCibs;
if ([cibOwner respondsToSelector:@selector(viewControllerDidLoadCib:)]) if ([cibOwner respondsToSelector:@selector(viewControllerDidLoadCib:)])
[cibOwner viewControllerDidLoadCib:self]; [cibOwner viewControllerDidLoadCib:self];
_isLoading = NO;
[self viewDidLoad]; [self viewDidLoad];
} }
@@ -184,7 +196,7 @@ var CPViewControllerCachedCibs;
/*! /*!
This method is called after the view controller has loaded its associated views into memory. 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 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 cib files. This method is most commonly used to perform additional initialization steps on views that are loaded from nib files.
*/ */
- (void)viewDidLoad - (void)viewDidLoad
{ {
@@ -200,13 +212,35 @@ var CPViewControllerCachedCibs;
*/ */
- (void)setView:(CPView)aView - (void)setView:(CPView)aView
{ {
var viewWasLoaded = !_view;
_view = aView; _view = aView;
}
// Make sure the viewDidLoad method is called if the view is set directly - (CPNavigationItem)navigationItem
if (!_isLoading && viewWasLoaded) {
[self viewDidLoad]; var navigationItem = self._navigationItem;
if (!navigationItem)
navigationItem = [[CPNavigationItem alloc] initWithTitle:[self title]];
self._navigationItem = navigationItem;
return navigationItem;
}
- (void)viewWillAppear:(BOOL)isAnimated
{
}
- (void)viewDidAppear:(BOOL)isAnimated
{
}
- (void)viewWillDisappear:(BOOL)isAnimated
{
}
- (void)viewDidDisappear:(BOOL)isAnimated
{
} }
@end @end
+56 -100
View File
@@ -20,8 +20,9 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
@import "CPView.j" @import <AppKit/CPView.j>
@import "CPScrollView.j"
#include "Platform/Platform.h"
// FIXME: implement these where possible: // FIXME: implement these where possible:
@@ -49,32 +50,30 @@ CPWebViewScrollNative = 2;
{ {
CPScrollView _scrollView; CPScrollView _scrollView;
CPView _frameView; CPView _frameView;
IFrame _iframe; IFrame _iframe;
CPString _mainFrameURL; CPString _mainFrameURL;
CPArray _backwardStack; CPArray _backwardStack;
CPArray _forwardStack; CPArray _forwardStack;
BOOL _ignoreLoadStart; BOOL _ignoreLoadStart;
BOOL _ignoreLoadEnd; BOOL _ignoreLoadEnd;
id _downloadDelegate; id _downloadDelegate;
id _frameLoadDelegate; id _frameLoadDelegate;
id _policyDelegate; id _policyDelegate;
id _resourceLoadDelegate; id _resourceLoadDelegate;
id _UIDelegate; id _UIDelegate;
CPWebScriptObject _wso; CPWebScriptObject _wso;
CPString _url; CPString _url;
CPString _html; CPString _html;
Function _loadCallback; Function _loadCallback;
int _scrollMode; int _scrollMode;
CGSize _scrollSize; CGSize _scrollSize;
int _loadHTMLStringTimer;
} }
- (id)initWithFrame:(CPRect)frameRect frameName:(CPString)frameName groupName:(CPString)groupName - (id)initWithFrame:(CPRect)frameRect frameName:(CPString)frameName groupName:(CPString)groupName
@@ -94,10 +93,10 @@ CPWebViewScrollNative = 2;
_backwardStack = []; _backwardStack = [];
_forwardStack = []; _forwardStack = [];
_scrollMode = CPWebViewScrollNative; _scrollMode = CPWebViewScrollNative;
[self _initDOMWithFrame:aFrame]; [self _initDOMWithFrame:aFrame];
} }
return self; return self;
} }
@@ -105,52 +104,51 @@ CPWebViewScrollNative = 2;
{ {
_ignoreLoadStart = YES; _ignoreLoadStart = YES;
_ignoreLoadEnd = YES; _ignoreLoadEnd = YES;
_iframe = document.createElement("iframe"); _iframe = document.createElement("iframe");
_iframe.name = "iframe_" + Math.floor(Math.random()*10000); _iframe.name = "iframe_" + Math.floor(Math.random()*10000);
_iframe.style.width = "100%"; _iframe.style.width = "100%";
_iframe.style.height = "100%"; _iframe.style.height = "100%";
_iframe.style.borderWidth = "0px"; _iframe.style.borderWidth = "0px";
_iframe.frameBorder = "0";
[self setDrawsBackground:YES]; [self setDrawsBackground:YES];
_loadCallback = function() { _loadCallback = function() {
// HACK: this block handles the case where we don't know about loads initiated by the user clicking a link // HACK: this block handles the case where we don't know about loads initiated by the user clicking a link
if (!_ignoreLoadStart) if (!_ignoreLoadStart)
{ {
// post the start load notification // post the start load notification
[self _startedLoading]; [self _startedLoading];
if (_mainFrameURL) if (_mainFrameURL)
[_backwardStack addObject:_mainFrameURL]; [_backwardStack addObject:_mainFrameURL];
// FIXME: this doesn't actually get the right URL for different domains. Not possible due to browser security restrictions. // 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;
_mainFrameURL = _iframe.src; _mainFrameURL = _iframe.src;
// clear the forward // clear the forward
[_forwardStack removeAllObjects]; [_forwardStack removeAllObjects];
} }
else else
_ignoreLoadStart = NO; _ignoreLoadStart = NO;
if (!_ignoreLoadEnd) if (!_ignoreLoadEnd)
{ {
[self _finishedLoading]; [self _finishedLoading];
} }
else else
_ignoreLoadEnd = NO; _ignoreLoadEnd = NO;
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode]; [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
} }
if (_iframe.addEventListener) if (_iframe.addEventListener)
_iframe.addEventListener("load", _loadCallback, false); _iframe.addEventListener("load", _loadCallback, false);
else if (_iframe.attachEvent) else if (_iframe.attachEvent)
_iframe.attachEvent("onload", _loadCallback); _iframe.attachEvent("onload", _loadCallback);
_frameView = [[CPView alloc] initWithFrame:[self bounds]]; _frameView = [[CPView alloc] initWithFrame:[self bounds]];
[_frameView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable]; [_frameView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
@@ -158,9 +156,9 @@ CPWebViewScrollNative = 2;
[_scrollView setAutohidesScrollers:YES]; [_scrollView setAutohidesScrollers:YES];
[_scrollView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable]; [_scrollView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
[_scrollView setDocumentView:_frameView]; [_scrollView setDocumentView:_frameView];
_frameView._DOMElement.appendChild(_iframe); _frameView._DOMElement.appendChild(_iframe);
[self _setScrollMode:_scrollMode]; [self _setScrollMode:_scrollMode];
[self addSubview:_scrollView]; [self addSubview:_scrollView];
@@ -168,37 +166,12 @@ CPWebViewScrollNative = 2;
- (void)setFrameSize:(CPSize)aSize - (void)setFrameSize:(CPSize)aSize
{ {
[super setFrameSize:aSize]; [super setFrameSize:aSize];
[self _resizeWebFrame]; [self _resizeWebFrame];
} }
- (void)_attachScrollEventIfNecessary - (BOOL)_resizeWebFrame
{
if (_scrollMode !== CPWebViewScrollAppKit)
return;
var win = null;
try { win = [self DOMWindow]; } catch (e) {}
if (win && win.addEventListener)
{
var scrollEventHandler = function(anEvent)
{
var frameBounds = [self bounds],
frameCenter = CGPointMake(CGRectGetMidX(frameBounds), CGRectGetMidY(frameBounds)),
windowOrigin = [self convertPoint:frameCenter toView:nil],
globalOrigin = [[self window] convertBaseToBridge:windowOrigin];
anEvent._overrideLocation = globalOrigin;
[[[self window] platformWindow] scrollEvent:anEvent];
};
win.addEventListener("DOMMouseScroll", scrollEventHandler, false);
}
}
- (void)_resizeWebFrame
{ {
if (_scrollMode === CPWebViewScrollAppKit) if (_scrollMode === CPWebViewScrollAppKit)
{ {
@@ -208,14 +181,13 @@ CPWebViewScrollNative = 2;
} }
else else
{ {
var visibleRect = [_frameView visibleRect]; [_frameView setFrameSize:[_scrollView contentSize]];
[_frameView setFrameSize:CGSizeMake(CGRectGetMaxX(visibleRect), CGRectGetMaxY(visibleRect))];
// try to get the document size so we can correctly set the frame // try to get the document size so we can correctly set the frame
var win = null; var win = null;
try { win = [self DOMWindow]; } catch (e) {} try { win = [self DOMWindow]; } catch (e) {}
if (win && win.document && win.document.body) if (win && win.document)
{ {
var width = win.document.body.scrollWidth, var width = win.document.body.scrollWidth,
height = win.document.body.scrollHeight; height = win.document.body.scrollHeight;
@@ -228,11 +200,9 @@ CPWebViewScrollNative = 2;
else else
{ {
CPLog.warn("using default size 800*1600"); CPLog.warn("using default size 800*1600");
[_frameView setFrameSize:CGSizeMake(800, 1600)]; [_frameView setFrameSize:CGSizeMake(800, 1600)];
} }
[_frameView scrollRectToVisible:visibleRect];
} }
} }
} }
@@ -241,17 +211,14 @@ CPWebViewScrollNative = 2;
{ {
if (_scrollMode == aScrollMode) if (_scrollMode == aScrollMode)
return; return;
[self _setScrollMode:aScrollMode]; [self _setScrollMode:aScrollMode];
} }
- (void)_setScrollMode:(int)aScrollMode - (void)_setScrollMode:(int)aScrollMode
{ {
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine)) _scrollMode = aScrollMode;
_scrollMode = CPWebViewScrollNative;
else
_scrollMode = aScrollMode;
_ignoreLoadStart = YES; _ignoreLoadStart = YES;
_ignoreLoadEnd = YES; _ignoreLoadEnd = YES;
@@ -262,16 +229,16 @@ CPWebViewScrollNative = 2;
{ {
[_scrollView setHasHorizontalScroller:YES]; [_scrollView setHasHorizontalScroller:YES];
[_scrollView setHasVerticalScroller:YES]; [_scrollView setHasVerticalScroller:YES];
_iframe.setAttribute("scrolling", "no"); _iframe.setAttribute("scrolling", "no");
} }
else else
{ {
[_scrollView setHasHorizontalScroller:NO]; [_scrollView setHasHorizontalScroller:NO];
[_scrollView setHasVerticalScroller:NO]; [_scrollView setHasVerticalScroller:NO];
_iframe.setAttribute("scrolling", "auto"); _iframe.setAttribute("scrolling", "auto");
[_frameView setFrameSize:[_scrollView bounds].size]; [_frameView setFrameSize:[_scrollView bounds].size];
} }
@@ -289,16 +256,14 @@ CPWebViewScrollNative = 2;
[self _setScrollMode:CPWebViewScrollAppKit]; [self _setScrollMode:CPWebViewScrollAppKit];
[_frameView setFrameSize:[_scrollView contentSize]];
[self _startedLoading]; [self _startedLoading];
_ignoreLoadStart = YES; _ignoreLoadStart = YES;
_ignoreLoadEnd = NO; _ignoreLoadEnd = NO;
_url = null; _url = null;
_html = aString; _html = aString;
[self _load]; [self _load];
} }
@@ -307,13 +272,13 @@ CPWebViewScrollNative = 2;
[self _setScrollMode:CPWebViewScrollNative]; [self _setScrollMode:CPWebViewScrollNative];
[self _startedLoading]; [self _startedLoading];
_ignoreLoadStart = YES; _ignoreLoadStart = YES;
_ignoreLoadEnd = NO; _ignoreLoadEnd = NO;
_url = _mainFrameURL; _url = _mainFrameURL;
_html = null; _html = null;
[self _load]; [self _load];
} }
@@ -328,19 +293,11 @@ CPWebViewScrollNative = 2;
// clear the iframe // clear the iframe
_iframe.src = ""; _iframe.src = "";
if (_loadHTMLStringTimer !== nil) // need to give the browser a chance to reset iframe, otherwise we'll be document.write()-ing the previous document
{ window.setTimeout(function() {
window.clearTimeout(_loadHTMLStringTimer);
_loadHTMLStringTimer = nil;
}
// 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]; var win = [self DOMWindow];
if (win) win.document.write(_html);
win.document.write(_html);
window.setTimeout(_loadCallback, 1); window.setTimeout(_loadCallback, 1);
}, 0); }, 0);
@@ -358,8 +315,7 @@ CPWebViewScrollNative = 2;
- (void)_finishedLoading - (void)_finishedLoading
{ {
[self _resizeWebFrame]; [self _resizeWebFrame];
[self _attachScrollEventIfNecessary];
[[CPNotificationCenter defaultCenter] postNotificationName:CPWebViewProgressFinishedNotification object:self]; [[CPNotificationCenter defaultCenter] postNotificationName:CPWebViewProgressFinishedNotification object:self];
if ([_frameLoadDelegate respondsToSelector:@selector(webView:didFinishLoadForFrame:)]) if ([_frameLoadDelegate respondsToSelector:@selector(webView:didFinishLoadForFrame:)])
@@ -372,7 +328,7 @@ CPWebViewScrollNative = 2;
} }
- (void)setMainFrameURL:(CPString)URLString - (void)setMainFrameURL:(CPString)URLString
{ {
if (_mainFrameURL) if (_mainFrameURL)
[_backwardStack addObject:_mainFrameURL]; [_backwardStack addObject:_mainFrameURL];
_mainFrameURL = URLString; _mainFrameURL = URLString;
@@ -389,9 +345,9 @@ CPWebViewScrollNative = 2;
[_forwardStack addObject:_mainFrameURL]; [_forwardStack addObject:_mainFrameURL];
_mainFrameURL = [_backwardStack lastObject]; _mainFrameURL = [_backwardStack lastObject];
[_backwardStack removeLastObject]; [_backwardStack removeLastObject];
[self _loadMainFrameURL]; [self _loadMainFrameURL];
return YES; return YES;
} }
return NO; return NO;
@@ -405,9 +361,9 @@ CPWebViewScrollNative = 2;
[_backwardStack addObject:_mainFrameURL]; [_backwardStack addObject:_mainFrameURL];
_mainFrameURL = [_forwardStack lastObject]; _mainFrameURL = [_forwardStack lastObject];
[_forwardStack removeLastObject]; [_forwardStack removeLastObject];
[self _loadMainFrameURL]; [self _loadMainFrameURL];
return YES; return YES;
} }
return NO; return NO;
@@ -630,7 +586,7 @@ CPWebViewScrollNative = 2;
- (id)initWithCoder:(CPCoder)aCoder - (id)initWithCoder:(CPCoder)aCoder
{ {
self = [super initWithCoder:aCoder]; self = [super initWithCoder:aCoder];
if (self) if (self)
{ {
// FIXME: encode/decode these? // FIXME: encode/decode these?
@@ -638,14 +594,14 @@ CPWebViewScrollNative = 2;
_backwardStack = []; _backwardStack = [];
_forwardStack = []; _forwardStack = [];
_scrollMode = CPWebViewScrollNative; _scrollMode = CPWebViewScrollNative;
#if PLATFORM(DOM) #if PLATFORM(DOM)
[self _initDOMWithFrame:[self frame]]; [self _initDOMWithFrame:[self frame]];
#endif #endif
[self setBackgroundColor:[CPColor whiteColor]]; [self setBackgroundColor:[CPColor whiteColor]];
} }
return self; return self;
} }
+130 -304
View File
@@ -26,9 +26,14 @@
@import "CGGeometry.j" @import "CGGeometry.j"
@import "CPAnimation.j" @import "CPAnimation.j"
@import "CPPlatformWindow.j"
@import "CPResponder.j" @import "CPResponder.j"
@import "CPScreen.j" @import "CPScreen.j"
@import "CPPlatformWindow.j"
#include "../Platform/Platform.h"
#include "../Platform/DOM/CPDOMDisplayServer.h"
#include "../CoreGraphics/CGGeometry.h"
/* /*
@@ -189,15 +194,13 @@ var SHADOW_MARGIN_LEFT = 20.0,
SHADOW_MARGIN_TOP = 10.0, SHADOW_MARGIN_TOP = 10.0,
SHADOW_MARGIN_BOTTOM = 10.0, SHADOW_MARGIN_BOTTOM = 10.0,
SHADOW_DISTANCE = 5.0, SHADOW_DISTANCE = 5.0,
_CPWindowShadowColor = nil; _CPWindowShadowColor = nil;
var CPWindowSaveImage = nil, var CPWindowSaveImage = nil,
CPWindowSavingImage = nil; CPWindowSavingImage = nil;
var CPWindowResizeTime = 0.2; /*!
/*!
@ingroup appkit @ingroup appkit
@class CPWindow @class CPWindow
@@ -210,33 +213,33 @@ var CPWindowResizeTime = 0.2;
<p>A window always contains a content view which is the highest level view available for public (application) use. This view fills the area of the window inside any decoration/border. This is the only part of the window that application programmers are allowed to draw in directly.</p> <p>A window always contains a content view which is the highest level view available for public (application) use. This view fills the area of the window inside any decoration/border. This is the only part of the window that application programmers are allowed to draw in directly.</p>
<p>You can convert between view coordinates and window base coordinates using the [CPView -convertPoint:fromView:], [CPView -convertPoint:toView:], [CPView -convertRect:fromView:], and [CPView -convertRect:toView:] methods with a nil view argument. <p>You can convert between view coordinates and window base coordinates using the [CPView -convertPoint:fromView:], [CPView -convertPoint:toView:], [CPView -convertRect:fromView:], and [CPView -convertRect:toView:] methods with a nil view argument.
@par Delegate Methods @par Delegate Methods
@delegate -(void)windowDidResize:(CPNotification)notification; @delegate -(void)windowDidResize:(CPNotification)notification;
Sent from the notification center when the window has been resized. Sent from the notification center when the window has been resized.
@param notification contains information about the resize event @param notification contains information about the resize event
@delegate -(CPUndoManager)windowWillReturnUndoManager:(CPWindow)window; @delegate -(CPUndoManager)windowWillReturnUndoManager:(CPWindow)window;
Called to obtain the undo manager for a window Called to obtain the undo manager for a window
@param window the window for which to return the undo manager @param window the window for which to return the undo manager
@return the window's undo manager @return the window's undo manager
@delegate -(void)windowDidBecomeMain:(CPNotification)notification; @delegate -(void)windowDidBecomeMain:(CPNotification)notification;
Sent from the notification center when the delegate's window becomes Sent from the notification center when the delegate's window becomes
the main window. the main window.
@param notification contains information about the event @param notification contains information about the event
@delegate -(void)windowDidResignMain:(CPNotification)notification; @delegate -(void)windowDidResignMain:(CPNotification)notification;
Sent from the notification center when the delegate's window has Sent from the notification center when the delegate's window has
resigned main window status. resigned main window status.
@param notification contains information about the event @param notification contains information about the event
@delegate -(void)windowDidResignKey:(CPNotification)notification; @delegate -(void)windowDidResignKey:(CPNotification)notification;
Sent from the notification center when the delegate's window has Sent from the notification center when the delegate's window has
resigned key window status. resigned key window status.
@param notification contains information about the event @param notification contains information about the event
@delegate -(BOOL)windowShouldClose:(id)window; @delegate -(BOOL)windowShouldClose:(id)window;
Called when the user tries to close the window. Called when the user tries to close the window.
@param window the window to close @param window the window to close
@@ -308,17 +311,15 @@ var CPWindowResizeTime = 0.2;
#endif #endif
unsigned _autoresizingMask; unsigned _autoresizingMask;
BOOL _delegateRespondsToWindowWillReturnUndoManagerSelector; BOOL _delegateRespondsToWindowWillReturnUndoManagerSelector;
BOOL _isFullPlatformWindow; BOOL _isFullPlatformWindow;
_CPWindowFullPlatformWindowSession _fullPlatformWindowSession; _CPWindowFullPlatformWindowSession _fullPlatformWindowSession;
CPDictionary _sheetContext; CPDictionary _sheetContext;
CPWindow _parentView; CPWindow _parentView;
BOOL _isSheet; BOOL _isSheet;
_CPWindowFrameAnimation _frameAnimation;
} }
/* /*
@@ -329,9 +330,9 @@ var CPWindowResizeTime = 0.2;
{ {
if (self != [CPWindow class]) if (self != [CPWindow class])
return; return;
var bundle = [CPBundle bundleForClass:[CPWindow class]]; var bundle = [CPBundle bundleForClass:[CPWindow class]];
CPWindowSavingImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPProgressIndicator/CPProgressIndicatorSpinningStyleRegular.gif"] size:CGSizeMake(16.0, 16.0)] CPWindowSavingImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPProgressIndicator/CPProgressIndicatorSpinningStyleRegular.gif"] size:CGSizeMake(16.0, 16.0)]
} }
@@ -358,7 +359,7 @@ CPTexturedBackgroundWindowMask
- (id)initWithContentRect:(CGRect)aContentRect styleMask:(unsigned int)aStyleMask - (id)initWithContentRect:(CGRect)aContentRect styleMask:(unsigned int)aStyleMask
{ {
self = [super init]; self = [super init];
if (self) if (self)
{ {
var windowViewClass = [[self class] _windowViewClassForStyleMask:aStyleMask]; var windowViewClass = [[self class] _windowViewClassForStyleMask:aStyleMask];
@@ -371,15 +372,6 @@ CPTexturedBackgroundWindowMask
[self setPlatformWindow:[CPPlatformWindow primaryPlatformWindow]]; [self setPlatformWindow:[CPPlatformWindow primaryPlatformWindow]];
else else
{ {
// give zero sized borderless bridge windows a default size if we're not in the browser so they show up in NativeHost.
if ((aStyleMask & CPBorderlessBridgeWindowMask) && aContentRect.size.width === 0 && aContentRect.size.height === 0)
{
var visibleFrame = [[[CPScreen alloc] init] visibleFrame];
_frame.size.height = MIN(768.0, visibleFrame.size.height);
_frame.size.width = MIN(1024.0, visibleFrame.size.width);
_frame.origin.x = (visibleFrame.size.width - _frame.size.width) / 2;
_frame.origin.y = (visibleFrame.size.height - _frame.size.height) / 2;
}
[self setPlatformWindow:[[CPPlatformWindow alloc] initWithContentRect:_frame]]; [self setPlatformWindow:[[CPPlatformWindow alloc] initWithContentRect:_frame]];
[self platformWindow]._only = self; [self platformWindow]._only = self;
} }
@@ -392,7 +384,7 @@ CPTexturedBackgroundWindowMask
// Set up our window number. // Set up our window number.
_windowNumber = [CPApp._windows count]; _windowNumber = [CPApp._windows count];
CPApp._windows[_windowNumber] = self; CPApp._windows[_windowNumber] = self;
_styleMask = aStyleMask; _styleMask = aStyleMask;
[self setLevel:CPNormalWindowLevel]; [self setLevel:CPNormalWindowLevel];
@@ -407,15 +399,15 @@ CPTexturedBackgroundWindowMask
[_windowView setNextResponder:self]; [_windowView setNextResponder:self];
[self setMovableByWindowBackground:aStyleMask & CPHUDBackgroundWindowMask]; [self setMovableByWindowBackground:aStyleMask & CPHUDBackgroundWindowMask];
// Create a generic content view. // Create a generic content view.
[self setContentView:[[CPView alloc] initWithFrame:CGRectMakeZero()]]; [self setContentView:[[CPView alloc] initWithFrame:CGRectMakeZero()]];
_firstResponder = self; _firstResponder = self;
#if PLATFORM(DOM) #if PLATFORM(DOM)
_DOMElement = document.createElement("div"); _DOMElement = document.createElement("div");
_DOMElement.style.position = "absolute"; _DOMElement.style.position = "absolute";
_DOMElement.style.visibility = "visible"; _DOMElement.style.visibility = "visible";
_DOMElement.style.zIndex = 0; _DOMElement.style.zIndex = 0;
@@ -441,7 +433,7 @@ CPTexturedBackgroundWindowMask
[self setShowsResizeIndicator:_styleMask & CPResizableWindowMask]; [self setShowsResizeIndicator:_styleMask & CPResizableWindowMask];
} }
return self; return self;
} }
@@ -658,10 +650,9 @@ CPTexturedBackgroundWindowMask
if (shouldAnimate) if (shouldAnimate)
{ {
[_frameAnimation stopAnimation]; var animation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame];
_frameAnimation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame];
[animation startAnimation];
[_frameAnimation startAnimation];
} }
else else
{ {
@@ -742,10 +733,8 @@ CPTexturedBackgroundWindowMask
*/ */
- (void)orderFront:(id)aSender - (void)orderFront:(id)aSender
{ {
#if PLATFORM(DOM)
[_platformWindow orderFront:self]; [_platformWindow orderFront:self];
[_platformWindow order:CPWindowAbove window:self relativeTo:nil]; [_platformWindow order:CPWindowAbove window:self relativeTo:nil];
#endif
if (_firstResponder === self || !_firstResponder) if (_firstResponder === self || !_firstResponder)
[self makeFirstResponder:[self initialFirstResponder]]; [self makeFirstResponder:[self initialFirstResponder]];
@@ -773,17 +762,13 @@ CPTexturedBackgroundWindowMask
*/ */
- (void)orderOut:(id)aSender - (void)orderOut:(id)aSender
{ {
#if PLATFORM(DOM)
if ([self _sharesChromeWithPlatformWindow]) if ([self _sharesChromeWithPlatformWindow])
[_platformWindow orderOut:self]; [_platformWindow orderOut:self];
#endif
if ([_delegate respondsToSelector:@selector(windowWillClose:)]) if ([_delegate respondsToSelector:@selector(windowWillClose:)])
[_delegate windowWillClose:self]; [_delegate windowWillClose:self];
#if PLATFORM(DOM)
[_platformWindow order:CPWindowOut window:self relativeTo:nil]; [_platformWindow order:CPWindowOut window:self relativeTo:nil];
#endif
[self _updateMainAndKeyWindows]; [self _updateMainAndKeyWindows];
} }
@@ -795,9 +780,7 @@ CPTexturedBackgroundWindowMask
*/ */
- (void)orderWindow:(CPWindowOrderingMode)aPlace relativeTo:(int)otherWindowNumber - (void)orderWindow:(CPWindowOrderingMode)aPlace relativeTo:(int)otherWindowNumber
{ {
#if PLATFORM(DOM)
[_platformWindow order:aPlace window:self relativeTo:CPApp._windows[otherWindowNumber]]; [_platformWindow order:aPlace window:self relativeTo:CPApp._windows[otherWindowNumber]];
#endif
} }
/*! /*!
@@ -882,12 +865,12 @@ CPTexturedBackgroundWindowMask
{ {
if (_contentView) if (_contentView)
[_contentView removeFromSuperview]; [_contentView removeFromSuperview];
var bounds = CGRectMake(0.0, 0.0, CGRectGetWidth(_frame), CGRectGetHeight(_frame)); var bounds = CGRectMake(0.0, 0.0, CGRectGetWidth(_frame), CGRectGetHeight(_frame));
_contentView = aView; _contentView = aView;
[_contentView setFrame:[self contentRectForFrameRect:bounds]]; [_contentView setFrame:[self contentRectForFrameRect:bounds]];
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]; [_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
[_windowView addSubview:_contentView]; [_windowView addSubview:_contentView];
} }
@@ -900,23 +883,6 @@ CPTexturedBackgroundWindowMask
return _contentView; return _contentView;
} }
/*!
Applies an alpha value to the window.
@param aValue the alpha value to apply
*/
- (void)setAlphaValue:(float)aValue
{
[_windowView setAlphaValue:aValue];
}
/*!
Returns the alpha value of the window.
*/
- (float)alphaValue
{
return [_windowView alphaValue];
}
/*! /*!
Sets the window's background color. Sets the window's background color.
@param aColor the new color for the background @param aColor the new color for the background
@@ -943,24 +909,24 @@ CPTexturedBackgroundWindowMask
{ {
if (CGSizeEqualToSize(_minSize, aSize)) if (CGSizeEqualToSize(_minSize, aSize))
return; return;
_minSize = CGSizeCreateCopy(aSize); _minSize = CGSizeCreateCopy(aSize);
var size = CGSizeMakeCopy([self frame].size), var size = CGSizeMakeCopy([self frame].size),
needsFrameChange = NO; needsFrameChange = NO;
if (size.width < _minSize.width) if (size.width < _minSize.width)
{ {
size.width = _minSize.width; size.width = _minSize.width;
needsFrameChange = YES; needsFrameChange = YES;
} }
if (size.height < _minSize.height) if (size.height < _minSize.height)
{ {
size.height = _minSize.height; size.height = _minSize.height;
needsFrameChange = YES; needsFrameChange = YES;
} }
if (needsFrameChange) if (needsFrameChange)
[self setFrameSize:size]; [self setFrameSize:size];
} }
@@ -983,24 +949,24 @@ CPTexturedBackgroundWindowMask
{ {
if (CGSizeEqualToSize(_maxSize, aSize)) if (CGSizeEqualToSize(_maxSize, aSize))
return; return;
_maxSize = CGSizeCreateCopy(aSize); _maxSize = CGSizeCreateCopy(aSize);
var size = CGSizeMakeCopy([self frame].size), var size = CGSizeMakeCopy([self frame].size),
needsFrameChange = NO; needsFrameChange = NO;
if (size.width > _maxSize.width) if (size.width > _maxSize.width)
{ {
size.width = _maxSize.width; size.width = _maxSize.width;
needsFrameChange = YES; needsFrameChange = YES;
} }
if (size.height > _maxSize.height) if (size.height > _maxSize.height)
{ {
size.height = _maxSize.height; size.height = _maxSize.height;
needsFrameChange = YES; needsFrameChange = YES;
} }
if (needsFrameChange) if (needsFrameChange)
[self setFrameSize:size]; [self setFrameSize:size];
} }
@@ -1041,10 +1007,10 @@ CPTexturedBackgroundWindowMask
if (_hasShadow && !_shadowView) if (_hasShadow && !_shadowView)
{ {
var bounds = [_windowView bounds]; var bounds = [_windowView bounds];
_shadowView = [[CPView alloc] initWithFrame:CGRectMake(-SHADOW_MARGIN_LEFT, -SHADOW_MARGIN_TOP + SHADOW_DISTANCE, _shadowView = [[CPView alloc] initWithFrame:CGRectMake(-SHADOW_MARGIN_LEFT, -SHADOW_MARGIN_TOP + SHADOW_DISTANCE,
SHADOW_MARGIN_LEFT + CGRectGetWidth(bounds) + SHADOW_MARGIN_RIGHT, SHADOW_MARGIN_TOP + CGRectGetHeight(bounds) + SHADOW_MARGIN_BOTTOM)]; SHADOW_MARGIN_LEFT + CGRectGetWidth(bounds) + SHADOW_MARGIN_RIGHT, SHADOW_MARGIN_TOP + CGRectGetHeight(bounds) + SHADOW_MARGIN_BOTTOM)];
if (!_CPWindowShadowColor) if (!_CPWindowShadowColor)
{ {
var bundle = [CPBundle bundleForClass:[CPWindow class]]; var bundle = [CPBundle bundleForClass:[CPWindow class]];
@@ -1067,7 +1033,7 @@ CPTexturedBackgroundWindowMask
[_shadowView setBackgroundColor:_CPWindowShadowColor]; [_shadowView setBackgroundColor:_CPWindowShadowColor];
[_shadowView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]; [_shadowView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
#if PLATFORM(DOM) #if PLATFORM(DOM)
CPDOMDisplayServerInsertBefore(_DOMElement, _shadowView._DOMElement, _windowView._DOMElement); CPDOMDisplayServerInsertBefore(_DOMElement, _shadowView._DOMElement, _windowView._DOMElement);
#endif #endif
@@ -1133,7 +1099,7 @@ CPTexturedBackgroundWindowMask
selector:@selector(windowDidBecomeKey:) selector:@selector(windowDidBecomeKey:)
name:CPWindowDidBecomeKeyNotification name:CPWindowDidBecomeKeyNotification
object:self]; object:self];
if ([_delegate respondsToSelector:@selector(windowDidBecomeMain:)]) if ([_delegate respondsToSelector:@selector(windowDidBecomeMain:)])
[defaultCenter [defaultCenter
addObserver:_delegate addObserver:_delegate
@@ -1229,7 +1195,7 @@ CPTexturedBackgroundWindowMask
if(!aResponder || ![aResponder acceptsFirstResponder] || ![aResponder becomeFirstResponder]) if(!aResponder || ![aResponder acceptsFirstResponder] || ![aResponder becomeFirstResponder])
{ {
_firstResponder = self; _firstResponder = self;
return NO; return NO;
} }
@@ -1282,9 +1248,9 @@ CPTexturedBackgroundWindowMask
- (void)setTitle:(CPString)aTitle - (void)setTitle:(CPString)aTitle
{ {
_title = aTitle; _title = aTitle;
[_windowView setTitle:aTitle]; [_windowView setTitle:aTitle];
[self _synchronizeMenuBarTitleWithWindowTitle]; [self _synchronizeMenuBarTitleWithWindowTitle];
} }
@@ -1359,21 +1325,10 @@ CPTexturedBackgroundWindowMask
*/ */
- (void)center - (void)center
{ {
if (_isFullPlatformWindow)
return;
var size = [self frame].size, var size = [self frame].size,
containerSize = [CPPlatform isBrowser] ? [_platformWindow contentBounds].size : [[self screen] visibleFrame].size; containerSize = [CPPlatform isBrowser] ? [_platformWindow contentBounds].size : [[self screen] visibleFrame].size;
var origin = CGPointMake((containerSize.width - size.width) / 2.0, (containerSize.height - size.height) / 2.0); [self setFrameOrigin: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];
} }
/*! /*!
@@ -1387,37 +1342,8 @@ CPTexturedBackgroundWindowMask
switch (type) switch (type)
{ {
case CPFlagsChanged: return [[self firstResponder] flagsChanged:anEvent];
case CPKeyUp: return [[self firstResponder] keyUp:anEvent]; case CPKeyUp: return [[self firstResponder] keyUp:anEvent];
case CPKeyDown: return [[self firstResponder] keyDown:anEvent];
case CPKeyDown: if ([anEvent charactersIgnoringModifiers] === CPTabCharacter)
{
if ([anEvent modifierFlags] & CPShiftKeyMask)
[self selectPreviousKeyView:self];
else
[self selectNextKeyView:self];
return;
}
else if ([anEvent charactersIgnoringModifiers] === CPBackTabCharacter)
return [self selectPreviousKeyView:self];
[[self firstResponder] keyDown:anEvent];
// Trigger the default button if needed
// FIXME: Is this only applicable in a sheet? See isse: #722.
if (![self disableKeyEquivalentForDefaultButton])
{
var defaultButton = [self defaultButton],
keyEquivalent = [defaultButton keyEquivalent],
modifierMask = [defaultButton keyEquivalentModifierMask];
if ([anEvent _triggersKeyEquivalent:keyEquivalent withModifierMask:modifierMask])
[[self defaultButton] performClick:self];
}
return;
case CPScrollWheel: return [[_windowView hitTest:point] scrollWheel:anEvent]; case CPScrollWheel: return [[_windowView hitTest:point] scrollWheel:anEvent];
@@ -1576,7 +1502,7 @@ CPTexturedBackgroundWindowMask
- (void)makeKeyAndOrderFront:(id)aSender - (void)makeKeyAndOrderFront:(id)aSender
{ {
[self orderFront:self]; [self orderFront:self];
[self makeKeyWindow]; [self makeKeyWindow];
[self makeMainWindow]; [self makeMainWindow];
} }
@@ -1640,7 +1566,7 @@ CPTexturedBackgroundWindowMask
if (!pasteboardTypes) if (!pasteboardTypes)
return; return;
[_inclusiveRegisteredDraggedTypes minusSet:pasteboardTypes]; [_inclusiveRegisteredDraggedTypes minusSet:pasteboardTypes]
if ([_inclusiveRegisteredDraggedTypes count] === 0) if ([_inclusiveRegisteredDraggedTypes count] === 0)
_inclusiveRegisteredDraggedTypes = nil; _inclusiveRegisteredDraggedTypes = nil;
@@ -1671,7 +1597,7 @@ CPTexturedBackgroundWindowMask
return; return;
[self _noteUnregisteredDraggedTypes:_registeredDraggedTypes]; [self _noteUnregisteredDraggedTypes:_registeredDraggedTypes];
[_registeredDraggedTypes addObjectsFromArray:pasteboardTypes]; [_registeredDraggedTypes addObjectsFromArray:pasteboardTypes]
[self _noteRegisteredDraggedTypes:_registeredDraggedTypes]; [self _noteRegisteredDraggedTypes:_registeredDraggedTypes];
_registeredDraggedTypesArray = nil; _registeredDraggedTypesArray = nil;
@@ -1684,7 +1610,7 @@ CPTexturedBackgroundWindowMask
- (CPArray)registeredDraggedTypes - (CPArray)registeredDraggedTypes
{ {
if (!_registeredDraggedTypesArray) if (!_registeredDraggedTypesArray)
_registeredDraggedTypesArray = [_registeredDraggedTypes allObjects]; _registeredDraggedTypesArray = [_registeredDraggedTypes allObjects]
return _registeredDraggedTypesArray; return _registeredDraggedTypesArray;
} }
@@ -1710,9 +1636,9 @@ CPTexturedBackgroundWindowMask
{ {
if (_isDocumentEdited == isDocumentEdited) if (_isDocumentEdited == isDocumentEdited)
return; return;
_isDocumentEdited = isDocumentEdited; _isDocumentEdited = isDocumentEdited;
[CPMenu _setMenuBarIconImageAlphaValue:_isDocumentEdited ? 0.5 : 1.0]; [CPMenu _setMenuBarIconImageAlphaValue:_isDocumentEdited ? 0.5 : 1.0];
[_windowView setDocumentEdited:isDocumentEdited]; [_windowView setDocumentEdited:isDocumentEdited];
@@ -1730,11 +1656,11 @@ CPTexturedBackgroundWindowMask
{ {
if (_isDocumentSaving == isDocumentSaving) if (_isDocumentSaving == isDocumentSaving)
return; return;
_isDocumentSaving = isDocumentSaving; _isDocumentSaving = isDocumentSaving;
[self _synchronizeSaveMenuWithDocumentSaving]; [self _synchronizeSaveMenuWithDocumentSaving];
[_windowView windowDidChangeDocumentSaving]; [_windowView windowDidChangeDocumentSaving];
} }
@@ -1751,16 +1677,16 @@ CPTexturedBackgroundWindowMask
var mainMenu = [CPApp mainMenu], var mainMenu = [CPApp mainMenu],
index = [mainMenu indexOfItemWithTitle:_isDocumentSaving ? @"Save" : @"Saving..."]; index = [mainMenu indexOfItemWithTitle:_isDocumentSaving ? @"Save" : @"Saving..."];
if (index == CPNotFound) if (index == CPNotFound)
return; return;
var item = [mainMenu itemAtIndex:index]; var item = [mainMenu itemAtIndex:index];
if (_isDocumentSaving) if (_isDocumentSaving)
{ {
CPWindowSaveImage = [item image]; CPWindowSaveImage = [item image];
[item setTitle:@"Saving..."]; [item setTitle:@"Saving..."];
[item setImage:CPWindowSavingImage]; [item setImage:CPWindowSavingImage];
[item setEnabled:NO]; [item setEnabled:NO];
@@ -1850,7 +1776,7 @@ CPTexturedBackgroundWindowMask
if (![_delegate windowShouldClose:self]) if (![_delegate windowShouldClose:self])
return; return;
} }
// Only check self is delegate does NOT implement this. This also ensures this when delegate == self (returns true). // Only check self is delegate does NOT implement this. This also ensures this when delegate == self (returns true).
else if ([self respondsToSelector:@selector(windowShouldClose:)] && ![self windowShouldClose:self]) else if ([self respondsToSelector:@selector(windowShouldClose:)] && ![self windowShouldClose:self])
return; return;
@@ -1860,8 +1786,8 @@ CPTexturedBackgroundWindowMask
{ {
var index = [documents indexOfObject:[_windowController document]]; var index = [documents indexOfObject:[_windowController document]];
[documents[index] shouldCloseWindowController:_windowController [documents[index] shouldCloseWindowController:_windowController
delegate:self delegate:self
shouldCloseSelector:@selector(_windowControllerContainingDocument:shouldClose:contextInfo:) shouldCloseSelector:@selector(_windowControllerContainingDocument:shouldClose:contextInfo:)
contextInfo:{documents:[documents copy], visited:0, index:index}]; contextInfo:{documents:[documents copy], visited:0, index:index}];
} }
@@ -1885,8 +1811,8 @@ CPTexturedBackgroundWindowMask
{ {
[windowController setDocument:documents[index]]; [windowController setDocument:documents[index]];
[documents[index] shouldCloseWindowController:_windowController [documents[index] shouldCloseWindowController:_windowController
delegate:self delegate:self
shouldCloseSelector:@selector(_windowControllerContainingDocument:shouldClose:contextInfo:) shouldCloseSelector:@selector(_windowControllerContainingDocument:shouldClose:contextInfo:)
contextInfo:context]; contextInfo:context];
} }
@@ -1923,7 +1849,7 @@ CPTexturedBackgroundWindowMask
// FIXME: Also check if we can resize and titlebar. // FIXME: Also check if we can resize and titlebar.
if ([self isVisible]) if ([self isVisible])
return YES; return YES;
return NO; return NO;
} }
@@ -1981,17 +1907,10 @@ CPTexturedBackgroundWindowMask
[keyWindow makeKeyWindow]; [keyWindow makeKeyWindow];
else else
{ {
var mainMenu = [CPApp mainMenu], var menuWindow = [CPApp mainMenu]._menuWindow;
menuBarClass = objj_getClass("_CPMenuBarWindow"),
menuWindow;
for (var i = 0; i < windowCount; i++) for (var i = 0; i < windowCount; i++)
{ {
var currentWindow = allWindows[i]; var currentWindow = allWindows[i];
if ([currentWindow isKindOfClass:menuBarClass])
menuWindow = currentWindow;
if (currentWindow === self || currentWindow === menuWindow) if (currentWindow === self || currentWindow === menuWindow)
continue; continue;
@@ -2016,17 +1935,10 @@ CPTexturedBackgroundWindowMask
[mainWindow makeMainWindow]; [mainWindow makeMainWindow];
else else
{ {
var mainMenu = [CPApp mainMenu], var menuWindow = [CPApp mainMenu]._menuWindow;
menuBarClass = objj_getClass("_CPMenuBarWindow"),
menuWindow;
for (var i = 0; i < windowCount; i++) for (var i = 0; i < windowCount; i++)
{ {
var currentWindow = allWindows[i]; var currentWindow = allWindows[i];
if ([currentWindow isKindOfClass:menuBarClass])
menuWindow = currentWindow;
if (currentWindow === self || currentWindow === menuWindow) if (currentWindow === self || currentWindow === menuWindow)
continue; continue;
@@ -2057,25 +1969,25 @@ CPTexturedBackgroundWindowMask
{ {
if (_toolbar === aToolbar) if (_toolbar === aToolbar)
return; return;
// If this has an owner, dump it! // If this has an owner, dump it!
[[aToolbar _window] setToolbar:nil]; [[aToolbar _window] setToolbar:nil];
// This is no longer out toolbar. // This is no longer out toolbar.
[_toolbar _setWindow:nil]; [_toolbar _setWindow:nil];
_toolbar = aToolbar; _toolbar = aToolbar;
// THIS is our toolbar. // THIS is our toolbar.
[_toolbar _setWindow:self]; [_toolbar _setWindow:self];
[self _noteToolbarChanged]; [self _noteToolbarChanged];
} }
- (void)toggleToolbarShown:(id)aSender - (void)toggleToolbarShown:(id)aSender
{ {
var toolbar = [self toolbar]; var toolbar = [self toolbar];
[toolbar setVisible:![toolbar isVisible]]; [toolbar setVisible:![toolbar isVisible]];
} }
@@ -2091,10 +2003,10 @@ CPTexturedBackgroundWindowMask
else else
{ {
newFrame = CGRectMakeCopy([self frame]); newFrame = CGRectMakeCopy([self frame]);
newFrame.origin = frame.origin; newFrame.origin = frame.origin;
} }
[self setFrame:newFrame]; [self setFrame:newFrame];
/* /*
[_windowView setAnimatingToolbar:YES]; [_windowView setAnimatingToolbar:YES];
@@ -2106,17 +2018,11 @@ CPTexturedBackgroundWindowMask
- (void)_setFrame:(CGRect)aFrame delegate:(id)delegate duration:(int)duration curve:(CPAnimationCurve)curve - (void)_setFrame:(CGRect)aFrame delegate:(id)delegate duration:(int)duration curve:(CPAnimationCurve)curve
{ {
[_frameAnimation stopAnimation]; var animation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame];
_frameAnimation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame]; [animation setDelegate:delegate];
[_frameAnimation setDelegate:delegate]; [animation setAnimationCurve:curve];
[_frameAnimation setAnimationCurve:curve]; [animation setDuration:duration];
[_frameAnimation setDuration:duration]; [animation startAnimation];
[_frameAnimation startAnimation];
}
- (CPTimeInterval)animationResizeTime:(CGRect)newWindowFrame
{
return CPWindowResizeTime;
} }
/* @ignore */ /* @ignore */
@@ -2126,7 +2032,7 @@ CPTexturedBackgroundWindowMask
var attachedSheet = [self attachedSheet]; var attachedSheet = [self attachedSheet];
var contentRect = [[self contentView] frame], var contentRect = [[self contentView] frame],
sheetFrame = CGRectMakeCopy([attachedSheet frame]); sheetFrame = CGRectMakeCopy([attachedSheet frame]);
sheetFrame.origin.y = CGRectGetMinY(_frame) + CGRectGetMinY(contentRect); sheetFrame.origin.y = CGRectGetMinY(_frame) + CGRectGetMinY(contentRect);
sheetFrame.origin.x = CGRectGetMinX(_frame) + FLOOR((CGRectGetWidth(_frame) - CGRectGetWidth(sheetFrame)) / 2.0); sheetFrame.origin.x = CGRectGetMinX(_frame) + FLOOR((CGRectGetWidth(_frame) - CGRectGetWidth(sheetFrame)) / 2.0);
@@ -2138,8 +2044,8 @@ CPTexturedBackgroundWindowMask
{ {
var sheetFrame = [aSheet frame]; var sheetFrame = [aSheet frame];
_sheetContext = {"sheet":aSheet, "modalDelegate":aModalDelegate, "endSelector":aDidEndSelector, "contextInfo":aContextInfo, "frame":CGRectMakeCopy(sheetFrame), "returnCode":-1, "opened": NO}; _sheetContext = {"sheet":aSheet, "modalDelegate":aModalDelegate, "endSelector":aDidEndSelector, "contextInfo":aContextInfo, "frame":CGRectMakeCopy(sheetFrame), "returnCode":-1, "opened": NO};
[self _attachSheetWindow:aSheet]; [self _attachSheetWindow:aSheet];
} }
@@ -2149,12 +2055,12 @@ CPTexturedBackgroundWindowMask
var sheetFrame = [aSheet frame], var sheetFrame = [aSheet frame],
frame = [self frame], frame = [self frame],
sheetContent = [aSheet contentView]; sheetContent = [aSheet contentView];
[self _setUpMasksForView:sheetContent]; [self _setUpMasksForView:sheetContent];
aSheet._isSheet = YES; aSheet._isSheet = YES;
aSheet._parentView = self; aSheet._parentView = self;
var originx = frame.origin.x + FLOOR((frame.size.width - sheetFrame.size.width)/2), var originx = frame.origin.x + FLOOR((frame.size.width - sheetFrame.size.width)/2),
originy = frame.origin.y + [[self contentView] frame].origin.y, originy = frame.origin.y + [[self contentView] frame].origin.y,
startFrame = CGRectMake(originx, originy, sheetFrame.size.width, 0), startFrame = CGRectMake(originx, originy, sheetFrame.size.width, 0),
@@ -2162,15 +2068,15 @@ CPTexturedBackgroundWindowMask
[[CPNotificationCenter defaultCenter] postNotificationName:CPWindowWillBeginSheetNotification object:self]; [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowWillBeginSheetNotification object:self];
[CPApp runModalForWindow:aSheet]; [CPApp runModalForWindow:aSheet];
[aSheet orderFront:self]; [aSheet orderFront:self];
[aSheet setFrame:startFrame display:YES animate:NO]; [aSheet setFrame:startFrame display:YES animate:NO];
_sheetContext["opened"] = YES; _sheetContext["opened"] = YES;
[aSheet _setFrame:endFrame delegate:self duration:[self animationResizeTime:endFrame] curve:CPAnimationEaseOut]; [aSheet _setFrame:endFrame delegate:self duration:0.2 curve:CPAnimationEaseOut];
// Should run the main loop here until _isAnimating = FALSE // Should run the main loop here until _isAnimating = FALSE
[aSheet becomeKeyWindow]; [aSheet becomeKeyWindow];
} }
/* @ignore */ /* @ignore */
@@ -2181,14 +2087,14 @@ CPTexturedBackgroundWindowMask
endFrame = CGRectMakeCopy(startFrame); endFrame = CGRectMakeCopy(startFrame);
endFrame.size.height = 0; endFrame.size.height = 0;
_sheetContext["frame"] = startFrame; _sheetContext["frame"] = startFrame;
var sheetContent = [sheet contentView]; var sheetContent = [sheet contentView];
[self _setUpMasksForView:sheetContent]; [self _setUpMasksForView:sheetContent];
_sheetContext["opened"] = NO; _sheetContext["opened"] = NO;
[sheet _setFrame:endFrame delegate:self duration:[self animationResizeTime:endFrame] curve:CPAnimationEaseIn]; [sheet _setFrame:endFrame delegate:self duration:0.2 curve:CPAnimationEaseIn];
} }
/* @ignore */ /* @ignore */
@@ -2199,33 +2105,31 @@ CPTexturedBackgroundWindowMask
return; return;
var sheetContent = [sheet contentView]; var sheetContent = [sheet contentView];
if (_sheetContext["opened"] === YES) if (_sheetContext["opened"] === YES)
{ {
[self _restoreMasksForView:sheetContent]; [self _restoreMasksForView:sheetContent];
return; return;
} }
[CPApp stopModal]; [CPApp stopModal];
[[CPNotificationCenter defaultCenter] postNotificationName:CPWindowDidEndSheetNotification object:self]; [[CPNotificationCenter defaultCenter] postNotificationName:CPWindowDidEndSheetNotification object:self];
[sheet orderOut:self]; [sheet orderOut:self];
var lastFrame = _sheetContext["frame"]; var lastFrame = _sheetContext["frame"];
[sheet setFrame:lastFrame]; [sheet setFrame:lastFrame];
[self _restoreMasksForView:sheetContent]; [self _restoreMasksForView:sheetContent];
var delegate = _sheetContext["modalDelegate"], var delegate = _sheetContext["modalDelegate"],
endSelector = _sheetContext["endSelector"], endSelector = _sheetContext["endSelector"];
returnCode = _sheetContext["returnCode"],
contextInfo = _sheetContext["contextInfo"]; if (delegate != nil && endSelector != nil)
objj_msgSend(delegate, endSelector, sheet, _sheetContext["returnCode"], _sheetContext["contextInfo"]);
_sheetContext = nil; _sheetContext = nil;
sheet._parentView = nil; sheet._parentView = nil;
if (delegate != nil && endSelector != nil)
objj_msgSend(delegate, endSelector, sheet, returnCode, contextInfo);
} }
- (void)_setUpMasksForView:(CPView)aView - (void)_setUpMasksForView:(CPView)aView
@@ -2233,7 +2137,7 @@ CPTexturedBackgroundWindowMask
var views = [aView subviews]; var views = [aView subviews];
[views addObject:aView]; [views addObject:aView];
for (var i = 0, count = [views count]; i < count; i++) for (var i = 0, count = [views count]; i < count; i++)
{ {
var view = [views objectAtIndex:i], var view = [views objectAtIndex:i],
@@ -2249,7 +2153,7 @@ CPTexturedBackgroundWindowMask
var views = [aView subviews]; var views = [aView subviews];
[views addObject:aView]; [views addObject:aView];
for (var i = 0, count = [views count]; i < count; i++) for (var i = 0, count = [views count]; i < count; i++)
{ {
var view = [views objectAtIndex:i], var view = [views objectAtIndex:i],
@@ -2267,7 +2171,7 @@ CPTexturedBackgroundWindowMask
{ {
if (_sheetContext === nil) if (_sheetContext === nil)
return nil; return nil;
return _sheetContext["sheet"]; return _sheetContext["sheet"];
} }
@@ -2298,7 +2202,7 @@ CPTexturedBackgroundWindowMask
return NO; return NO;
} }
- (BOOL)performKeyEquivalent:(CPEvent)anEvent - (void)performKeyEquivalent:(CPEvent)anEvent
{ {
// FIXME: should we be starting at the root, in other words _windowView? // FIXME: should we be starting at the root, in other words _windowView?
// The evidence seems to point to no... // The evidence seems to point to no...
@@ -2309,92 +2213,19 @@ CPTexturedBackgroundWindowMask
{ {
// It's not clear why we do performKeyEquivalent again here... // It's not clear why we do performKeyEquivalent again here...
// Perhaps to allow something to happen between sendEvent: and keyDown:? // Perhaps to allow something to happen between sendEvent: and keyDown:?
if ([anEvent _couldBeKeyEquivalent] && [self performKeyEquivalent:anEvent]) if (![anEvent _couldBeKeyEquivalent] || ![self performKeyEquivalent:anEvent])
return; [self interpretKeyEvents:[anEvent]];
// Apple's documentation is inconsistent with their behavior here. According to the docs
// an event going of the responder chain is passed to the input system as a last resort.
// However, the only methods I could get Cocoa to call automatically are
// moveUp: moveDown: moveLeft: moveRight: pageUp: pageDown: and complete:
[self _processKeyboardUIKey:anEvent];
} }
/* - (void)insertNewline:(id)sender
@ignore
Interprets the key event for action messages and sends the action message down the responder chain
Cocoa only sends moveDown:, moveUp:, moveLeft:, moveRight:, pageUp:, pageDown: and complete: messages.
We deviate from this by sending (the default) scrollPageUp: scrollPageDown: for pageUp and pageDown keys.
@param anEvent the event to handle.
@return YES if the key event was handled, NO if no responder handled the key event
*/
- (BOOL)_processKeyboardUIKey:(CPEvent)anEvent
{ {
var character = [anEvent charactersIgnoringModifiers], if (_defaultButton && _defaultButtonEnabled)
uiKeys = [CPLeftArrowFunctionKey, CPRightArrowFunctionKey, CPUpArrowFunctionKey, CPDownArrowFunctionKey, CPPageUpFunctionKey, CPPageDownFunctionKey, CPEscapeFunctionKey]; [_defaultButton performClick:nil];
if (![uiKeys containsObject:character])
return NO;
var selectors = [CPKeyBinding selectorsForKey:character modifierFlags:0];
if ([selectors count] <= 0)
return NO;
if (character !== CPEscapeFunctionKey)
{
var selector = [selectors objectAtIndex:0];
return [[self firstResponder] tryToPerform:selector with:self];
}
else
{
// Cocoa sends complete: for the escape key (in stead of the default cancelOperation:)
// This is also the only action that is not sent directly to the first responder, but through doCommandBySelector.
// The difference is that doCommandBySelector: will also send the action to the window and application delegates.
[[self firstResponder] doCommandBySelector:@selector(complete:)];
}
} }
/* - (void)insertTab:(id)sender
@ignore
Interprets the key event for action messages and sends the action message down the responder chain
Cocoa only sends moveDown:, moveUp:, moveLeft:, moveRight:, pageUp:, pageDown: and complete: messages.
We deviate from this by sending (the default) scrollPageUp: scrollPageDown: for pageUp and pageDown keys.
@param anEvent the event to handle.
@return YES if the key event was handled, NO if no responder handled the key event
*/
- (BOOL)_processKeyboardUIKey:(CPEvent)anEvent
{ {
var character = [anEvent charactersIgnoringModifiers], [self selectNextKeyView:nil];
uiKeys = [
CPLeftArrowFunctionKey,
CPRightArrowFunctionKey,
CPUpArrowFunctionKey,
CPDownArrowFunctionKey,
CPPageUpFunctionKey,
CPPageDownFunctionKey,
CPEscapeFunctionKey
];
if (![uiKeys containsObject:character])
return NO;
var selectors = [CPKeyBinding selectorsForKey:character modifierFlags:0];
if ([selectors count] <= 0)
return NO;
if (character !== CPEscapeFunctionKey)
{
var selector = [selectors objectAtIndex:0];
return [[self firstResponder] tryToPerform:selector with:self];
}
else
{
// Cocoa sends complete: for the escape key (in stead of the default cancelOperation:)
// This is also the only action that is not sent directly to the first responder, but through doCommandBySelector.
// The difference is that doCommandBySelector: will also send the action to the window and application delegates.
[[self firstResponder] doCommandBySelector:@selector(complete:)];
}
} }
- (void)_dirtyKeyViewLoop - (void)_dirtyKeyViewLoop
@@ -2421,7 +2252,7 @@ CPTexturedBackgroundWindowMask
- (void)recalculateKeyViewLoop - (void)recalculateKeyViewLoop
{ {
var subviews = []; var subviews = [];
[self _appendSubviewsOf:_contentView toArray:subviews]; [self _appendSubviewsOf:_contentView toArray:subviews];
var keyViewOrder = [subviews sortedArrayUsingFunction:keyViewComparator context:_contentView], var keyViewOrder = [subviews sortedArrayUsingFunction:keyViewComparator context:_contentView],
@@ -2429,7 +2260,7 @@ CPTexturedBackgroundWindowMask
for (var i=0; i<count; i++) for (var i=0; i<count; i++)
[keyViewOrder[i] setNextKeyView:keyViewOrder[(i+1)%count]]; [keyViewOrder[i] setNextKeyView:keyViewOrder[(i+1)%count]];
_keyViewLoopIsDirty = NO; _keyViewLoopIsDirty = NO;
} }
@@ -2450,7 +2281,7 @@ CPTexturedBackgroundWindowMask
return; return;
_autorecalculatesKeyViewLoop = shouldRecalculate; _autorecalculatesKeyViewLoop = shouldRecalculate;
if (_keyViewLoopIsDirty) if (_keyViewLoopIsDirty)
[self recalculateKeyViewLoop]; [self recalculateKeyViewLoop];
else if (_autorecalculatesKeyViewLoop) else if (_autorecalculatesKeyViewLoop)
@@ -2502,16 +2333,11 @@ CPTexturedBackgroundWindowMask
- (void)setDefaultButton:(CPButton)aButton - (void)setDefaultButton:(CPButton)aButton
{ {
if (_defaultButton === aButton) [_defaultButton setDefaultButton:NO];
return;
if ([_defaultButton keyEquivalent] === CPCarriageReturnCharacter)
[_defaultButton setKeyEquivalent:nil];
_defaultButton = aButton; _defaultButton = aButton;
if ([_defaultButton keyEquivalent] !== CPCarriageReturnCharacter) [_defaultButton setDefaultButton:YES];
[_defaultButton setKeyEquivalent:CPCarriageReturnCharacter];
} }
- (CPButton)defaultButton - (CPButton)defaultButton
@@ -2578,7 +2404,7 @@ var keyViewComparator = function(a, b, context)
{ {
if ([self isFullPlatformWindow]) if ([self isFullPlatformWindow])
return [self setFrame:[_platformWindow visibleFrame]]; return [self setFrame:[_platformWindow visibleFrame]];
if (_autoresizingMask == CPWindowNotSizable) if (_autoresizingMask == CPWindowNotSizable)
return; return;
@@ -2593,7 +2419,7 @@ var keyViewComparator = function(a, b, context)
newFrame.origin.x += dX; newFrame.origin.x += dX;
if (_autoresizingMask & CPWindowWidthSizable) if (_autoresizingMask & CPWindowWidthSizable)
newFrame.size.width += dX; newFrame.size.width += dX;
if (_autoresizingMask & CPWindowMinYMargin) if (_autoresizingMask & CPWindowMinYMargin)
newFrame.origin.y += dY; newFrame.origin.y += dY;
if (_autoresizingMask & CPWindowHeightSizable) if (_autoresizingMask & CPWindowHeightSizable)
@@ -2765,39 +2591,39 @@ var interpolate = function(fromValue, toValue, progress)
@implementation _CPWindowFrameAnimation : CPAnimation @implementation _CPWindowFrameAnimation : CPAnimation
{ {
CPWindow _window; CPWindow _window;
CGRect _startFrame; CGRect _startFrame;
CGRect _targetFrame; CGRect _targetFrame;
} }
- (id)initWithWindow:(CPWindow)aWindow targetFrame:(CGRect)aTargetFrame - (id)initWithWindow:(CPWindow)aWindow targetFrame:(CGRect)aTargetFrame
{ {
self = [super initWithDuration:[aWindow animationResizeTime:aTargetFrame] animationCurve:CPAnimationLinear]; self = [super initWithDuration:0.2 animationCurve:CPAnimationLinear];
if (self) if (self)
{ {
_window = aWindow; _window = aWindow;
_targetFrame = CGRectMakeCopy(aTargetFrame); _targetFrame = CGRectMakeCopy(aTargetFrame);
_startFrame = CGRectMakeCopy([_window frame]); _startFrame = CGRectMakeCopy([_window frame]);
} }
return self; return self;
} }
- (void)startAnimation - (void)startAnimation
{ {
[super startAnimation]; [super startAnimation];
_window._isAnimating = YES; _window._isAnimating = YES;
} }
- (void)setCurrentProgress:(float)aProgress - (void)setCurrentProgress:(float)aProgress
{ {
[super setCurrentProgress:aProgress]; [super setCurrentProgress:aProgress];
var value = [self currentValue]; var value = [self currentValue];
if (value == 1.0) if (value == 1.0)
_window._isAnimating = NO; _window._isAnimating = NO;
+12 -12
View File
@@ -43,21 +43,21 @@ var HUD_TITLEBAR_HEIGHT = 26.0;
_CPHUDWindowViewBackgroundColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices: _CPHUDWindowViewBackgroundColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
[ [
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground0.png"] size:CPSizeMake(7.0, 37.0)], [[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, 37.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(7.0, 37.0)], [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground2.png"] size:CPSizeMake(6.0, 78.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground3.png"] size:CPSizeMake(7.0, 1.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(2.0, 2.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(7.0, 1.0)], [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground5.png"] size:CPSizeMake(6.0, 1.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground6.png"] size:CPSizeMake(7.0, 3.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(1.0, 3.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(7.0, 3.0)] [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground8.png"] size:CPSizeMake(6.0, 6.0)]
]]]; ]]];
_CPHUDWindowViewCloseImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"HUDTheme/WindowClose.png"] size:CPSizeMake(18.0, 18.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(18.0, 18.0)]; _CPHUDWindowViewCloseActiveImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"HUDTheme/WindowCloseActive.png"] size:CPSizeMake(20.0, 20.0)];
} }
+ (CGRect)contentRectForFrameRect:(CGRect)aFrameRect + (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
@@ -148,7 +148,7 @@ var HUD_TITLEBAR_HEIGHT = 26.0;
{ {
var closeSize = [_CPHUDWindowViewCloseImage size]; var closeSize = [_CPHUDWindowViewCloseImage size];
_closeButton = [[CPButton alloc] initWithFrame:CGRectMake(8.0, 5.0, closeSize.width, closeSize.height)]; _closeButton = [[CPButton alloc] initWithFrame:CGRectMake(4.0, 4.0, closeSize.width, closeSize.height)];
[_closeButton setBordered:NO]; [_closeButton setBordered:NO];
-1
View File
@@ -22,7 +22,6 @@
@import "_CPWindowView.j" @import "_CPWindowView.j"
var GRADIENT_HEIGHT = 41.0; var GRADIENT_HEIGHT = 41.0;
var _CPTexturedWindowHeadGradientColor = nil, var _CPTexturedWindowHeadGradientColor = nil,
+3 -1
View File
@@ -20,8 +20,10 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
@import "CPImageView.j"
@import "CPView.j" @import "CPView.j"
@import "CPImageView.j"
#include "../CoreGraphics/CGGeometry.h"
var _CPWindowViewResizeIndicatorImage = nil; var _CPWindowViewResizeIndicatorImage = nil;
+4 -2
View File
@@ -27,6 +27,8 @@
@import "CPWindow.j" @import "CPWindow.j"
@import "CPDocument.j" @import "CPDocument.j"
#include "Platform/Platform.h"
/*! /*!
@ingroup appkit @ingroup appkit
@@ -131,7 +133,7 @@
if (_window) if (_window)
return; return;
[[CPBundle mainBundle] loadCibFile:[self windowCibPath] externalNameTable:[CPDictionary dictionaryWithObject:_cibOwner forKey:CPCibOwner]]; [[CPBundle bundleForClass:[_cibOwner class]] loadCibFile:[self windowCibPath] externalNameTable:[CPDictionary dictionaryWithObject:_cibOwner forKey:CPCibOwner]];
} }
/*! /*!
@@ -422,7 +424,7 @@
if (_windowCibPath) if (_windowCibPath)
return _windowCibPath; return _windowCibPath;
return [[CPBundle mainBundle] pathForResource:_windowCibName + @".cib"]; return [[CPBundle bundleForClass:[_cibOwner class]] pathForResource:_windowCibName + @".cib"];
} }
// Setting and Getting Window Attributes // Setting and Getting Window Attributes
+1 -1
View File
@@ -150,7 +150,7 @@ var CPCibObjectDataKey = @"CPCibObjectDataKey";
var topLevelObjects = [anExternalNameTable objectForKey:CPCibTopLevelObjects]; var topLevelObjects = [anExternalNameTable objectForKey:CPCibTopLevelObjects];
[objectData instantiateWithOwner:owner topLevelObjects:topLevelObjects]; [objectData instantiateWithOwner:owner topLevelObjects:topLevelObjects]
[objectData establishConnectionsWithOwner:owner topLevelObjects:topLevelObjects]; [objectData establishConnectionsWithOwner:owner topLevelObjects:topLevelObjects];
[objectData awakeWithOwner:owner topLevelObjects:topLevelObjects]; [objectData awakeWithOwner:owner topLevelObjects:topLevelObjects];
+3 -9
View File
@@ -39,11 +39,9 @@
// Not having a selector is a fatal error. // Not having a selector is a fatal error.
if (!selector) if (!selector)
{
[CPException [CPException
raise:CPInvalidArgumentException raise:CPInvalidArgumentException
reason:@"-[" + [self className] + ' ' + _cmd + @"] selector " + selectorName + @" does not exist."]; reason:@"-[" + [self className] + ' ' + _cmd + @"] selector " + selectorName + @" does not exist."];
}
// If the destination doesn't respond to this selector, warn but don't die. // If the destination doesn't respond to this selector, warn but don't die.
if (_destination && ![_destination respondsToSelector:selector]) if (_destination && ![_destination respondsToSelector:selector])
@@ -60,7 +58,7 @@
else else
[CPException [CPException
raise:CPInvalidArgumentException 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. // Not being able to set the target is a fatal error.
if ([_source respondsToSelector:@selector(setTarget:)]) if ([_source respondsToSelector:@selector(setTarget:)])
@@ -69,14 +67,10 @@
else else
[CPException [CPException
raise:CPInvalidArgumentException 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 @end
@implementation _CPCibControlConnector : CPCibControlConnector @implementation _CPCibControlConnector : CPCibControlConnector { } @end
{
}
@end
+14 -14
View File
@@ -37,12 +37,12 @@ var CPCibOwner = @"CPCibOwner";
@implementation CPBundle (CPCibLoading) @implementation CPBundle (CPCibLoading)
+ (CPCib)loadCibFile:(CPString)anAbsolutePath externalNameTable:(CPDictionary)aNameTable + (void)loadCibFile:(CPString)anAbsolutePath externalNameTable:(CPDictionary)aNameTable
{ {
return [[[CPCib alloc] initWithContentsOfURL:anAbsolutePath] instantiateCibWithExternalNameTable:aNameTable]; [[[CPCib alloc] initWithContentsOfURL:anAbsolutePath] instantiateCibWithExternalNameTable:aNameTable];
} }
+ (CPCib)loadCibNamed:(CPString)aName owner:(id)anOwner + (void)loadCibNamed:(CPString)aName owner:(id)anOwner
{ {
if (![aName hasSuffix:@".cib"]) if (![aName hasSuffix:@".cib"])
aName = [aName stringByAppendingString:@".cib"]; aName = [aName stringByAppendingString:@".cib"];
@@ -51,24 +51,24 @@ var CPCibOwner = @"CPCibOwner";
var bundle = anOwner ? [CPBundle bundleForClass:[anOwner class]] : [CPBundle mainBundle], var bundle = anOwner ? [CPBundle bundleForClass:[anOwner class]] : [CPBundle mainBundle],
path = [bundle pathForResource:aName]; path = [bundle pathForResource:aName];
return [self loadCibFile:path externalNameTable:[CPDictionary dictionaryWithObject:anOwner forKey:CPCibOwner]]; [self loadCibFile:path externalNameTable:[CPDictionary dictionaryWithObject:anOwner forKey:CPCibOwner]];
} }
- (CPCib)loadCibFile:(CPString)aFileName externalNameTable:(CPDictionary)aNameTable - (void)loadCibFile:(CPString)aFileName externalNameTable:(CPDictionary)aNameTable
{ {
return [[[CPCib alloc] initWithContentsOfURL:aFileName] instantiateCibWithExternalNameTable:aNameTable]; [[[CPCib alloc] initWithContentsOfURL:aFileName] instantiateCibWithExternalNameTable:aNameTable];
} }
+ (CPCib)loadCibFile:(CPString)anAbsolutePath externalNameTable:(CPDictionary)aNameTable loadDelegate:aDelegate + (void)loadCibFile:(CPString)anAbsolutePath externalNameTable:(CPDictionary)aNameTable loadDelegate:aDelegate
{ {
return ([[CPCib alloc] [[CPCib alloc]
initWithContentsOfURL:anAbsolutePath initWithContentsOfURL:anAbsolutePath
loadDelegate:[[_CPCibLoadDelegate alloc] loadDelegate:[[_CPCibLoadDelegate alloc]
initWithLoadDelegate:aDelegate initWithLoadDelegate:aDelegate
externalNameTable:aNameTable]]); externalNameTable:aNameTable]];
} }
+ (CPCib)loadCibNamed:(CPString)aName owner:(id)anOwner loadDelegate:(id)aDelegate + (void)loadCibNamed:(CPString)aName owner:(id)anOwner loadDelegate:(id)aDelegate
{ {
if (![aName hasSuffix:@".cib"]) if (![aName hasSuffix:@".cib"])
aName = [aName stringByAppendingString:@".cib"]; aName = [aName stringByAppendingString:@".cib"];
@@ -77,17 +77,17 @@ var CPCibOwner = @"CPCibOwner";
var bundle = anOwner ? [CPBundle bundleForClass:[anOwner class]] : [CPBundle mainBundle], var bundle = anOwner ? [CPBundle bundleForClass:[anOwner class]] : [CPBundle mainBundle],
path = [bundle pathForResource:aName]; path = [bundle pathForResource:aName];
return [self loadCibFile:path externalNameTable:[CPDictionary dictionaryWithObject:anOwner forKey:CPCibOwner] loadDelegate:aDelegate]; [self loadCibFile:path externalNameTable:[CPDictionary dictionaryWithObject:anOwner forKey:CPCibOwner] loadDelegate:aDelegate];
} }
- (CPCib)loadCibFile:(CPString)aFileName externalNameTable:(CPDictionary)aNameTable loadDelegate:(id)aDelegate - (void)loadCibFile:(CPString)aFileName externalNameTable:(CPDictionary)aNameTable loadDelegate:(id)aDelegate
{ {
return ([[CPCib alloc] [[CPCib alloc]
initWithCibNamed:aFileName initWithCibNamed:aFileName
bundle:self bundle:self
loadDelegate:[[_CPCibLoadDelegate alloc] loadDelegate:[[_CPCibLoadDelegate alloc]
initWithLoadDelegate:aDelegate initWithLoadDelegate:aDelegate
externalNameTable:aNameTable]]); externalNameTable:aNameTable]];
} }
@end @end
+5 -15
View File
@@ -46,28 +46,28 @@ var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey",
- (id)initWithClassName:(CPString)aClassName resourceName:(CPString)aResourceName properties:(CPDictionary)properties - (id)initWithClassName:(CPString)aClassName resourceName:(CPString)aResourceName properties:(CPDictionary)properties
{ {
self = [super init]; self = [super init];
if (self) if (self)
{ {
_className = aClassName; _className = aClassName;
_resourceName = aResourceName; _resourceName = aResourceName;
_properties = properties; _properties = properties;
} }
return self; return self;
} }
- (id)initWithCoder:(CPCoder)aCoder - (id)initWithCoder:(CPCoder)aCoder
{ {
self = [super init]; self = [super init];
if (self) if (self)
{ {
_className = [aCoder decodeObjectForKey:_CPCibCustomResourceClassNameKey]; _className = [aCoder decodeObjectForKey:_CPCibCustomResourceClassNameKey];
_resourceName = [aCoder decodeObjectForKey:_CPCibCustomResourceResourceNameKey]; _resourceName = [aCoder decodeObjectForKey:_CPCibCustomResourceResourceNameKey];
_properties = [aCoder decodeObjectForKey:_CPCibCustomResourcePropertiesKey]; _properties = [aCoder decodeObjectForKey:_CPCibCustomResourcePropertiesKey];
} }
return self; return self;
} }
@@ -80,7 +80,7 @@ var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey",
- (id)awakeAfterUsingCoder:(CPCoder)aCoder - (id)awakeAfterUsingCoder:(CPCoder)aCoder
{ {
if ([aCoder respondsToSelector:@selector(bundle)] && if ([aCoder respondsToSelector:@selector(bundle)] &&
(![aCoder respondsToSelector:@selector(awakenCustomResources)] || [aCoder awakenCustomResources])) (![aCoder respondsToSelector:@selector(awakenCustomResources)] || [aCoder awakenCustomResources]))
if (_className === @"CPImage") if (_className === @"CPImage")
return [[CPImage alloc] initWithContentsOfFile:[[aCoder bundle] pathForResource:_resourceName] size:_properties.valueForKey(@"size")]; return [[CPImage alloc] initWithContentsOfFile:[[aCoder bundle] pathForResource:_resourceName] size:_properties.valueForKey(@"size")];
@@ -112,14 +112,4 @@ var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey",
return NO; return NO;
} }
- (unsigned)loadStatus
{
return CPImageLoadStatusCompleted;
}
- (id)delegate
{
return nil;
}
@end @end
-3
View File
@@ -1,9 +1,6 @@
@import <Foundation/CPObject.j> @import <Foundation/CPObject.j>
@import "CGGeometry.j"
@import "CPWindow.j"
var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinSizeKey", var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinSizeKey",
_CPCibWindowTemplateMaxSizeKey = @"_CPCibWindowTemplateMaxSizeKey", _CPCibWindowTemplateMaxSizeKey = @"_CPCibWindowTemplateMaxSizeKey",
+6 -3
View File
@@ -22,10 +22,13 @@
@import <Foundation/CPObject.j> @import <Foundation/CPObject.j>
@import "CABackingStore.j" @import <AppKit/CABackingStore.j>
@import "CGContext.j" @import <AppKit/CGContext.j>
@import "CGGeometry.j" @import <AppKit/CGGeometry.j>
#include "../CoreGraphics/CGGeometry.h"
#include "../CoreGraphics/CGAffineTransform.j"
#define DOM(aLayer) aLayer._DOMElement #define DOM(aLayer) aLayer._DOMElement
+5 -2
View File
@@ -20,11 +20,14 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
@import "CGGeometry.j" #include "CGGeometry.h"
#include "CGAffineTransform.h"
#define _function(inline) function inline { return _##inline; } #define _function(inline) function inline { return _##inline; }
@import "CGGeometry.j"
_function(CGAffineTransformMake(a, b, c, d, tx, ty)) _function(CGAffineTransformMake(a, b, c, d, tx, ty))
_function(CGAffineTransformMakeIdentity()) _function(CGAffineTransformMakeIdentity())
_function(CGAffineTransformMakeCopy(anAffineTransform)) _function(CGAffineTransformMakeCopy(anAffineTransform))
+5 -4
View File
@@ -20,11 +20,12 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
@import "CGAffineTransform.j" #include "CGGeometry.h"
@import "CPCompatibility.j" #include "CGAffineTransform.h"
@import "CGGeometry.j"
@import "CGPath.j"
@import "CGGeometry.j"
@import "CGAffineTransform.j"
@import "CGPath.j"
kCGLineCapButt = 0; kCGLineCapButt = 0;
kCGLineCapRound = 1; kCGLineCapRound = 1;
-1
View File
@@ -63,7 +63,6 @@
#define _CGInsetMakeCopy(anInset) _CGInsetMake(anInset.top, anInset.right, anInset.bottom, anInset.left) #define _CGInsetMakeCopy(anInset) _CGInsetMake(anInset.top, anInset.right, anInset.bottom, anInset.left)
#define _CGInsetMakeZero() _CGInsetMake(0, 0, 0, 0) #define _CGInsetMakeZero() _CGInsetMake(0, 0, 0, 0)
#define _CGInsetIsEmpty(anInset) ((anInset).top === 0 && (anInset).right === 0 && (anInset).bottom === 0 && (anInset).left === 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 // DEPRECATED
#define _CGPointCreateCopy(aPoint) _CGPointMake(aPoint.x, aPoint.y) #define _CGPointCreateCopy(aPoint) _CGPointMake(aPoint.x, aPoint.y)
+17 -65
View File
@@ -20,6 +20,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include "CGGeometry.h"
#define _function(inline) function inline { return _##inline; } #define _function(inline) function inline { return _##inline; }
_function(CGPointMake(x, y)) _function(CGPointMake(x, y))
@@ -67,12 +69,6 @@ _function(CGInsetMake(top, right, bottom, left))
_function(CGInsetMakeZero()) _function(CGInsetMakeZero())
_function(CGInsetMakeCopy(anInset)) _function(CGInsetMakeCopy(anInset))
_function(CGInsetIsEmpty(anInset)) _function(CGInsetIsEmpty(anInset))
_function(CGInsetEqualToInset(lhsInset, rhsInset))
CGMinXEdge = 0;
CGMinYEdge = 1;
CGMaxXEdge = 2;
CGMaxYEdge = 3;
CGRectNull = _CGRectMake(Infinity, Infinity, 0.0, 0.0); CGRectNull = _CGRectMake(Infinity, Infinity, 0.0, 0.0);
@@ -81,50 +77,6 @@ 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 Returns a \c BOOL indicating whether CGRect \c lhsRect
contains CGRect \c rhsRect. contains CGRect \c rhsRect.
@@ -136,7 +88,7 @@ function CGRectDivide(inRect, slice, rem, amount, edge)
function CGRectContainsRect(lhsRect, rhsRect) function CGRectContainsRect(lhsRect, rhsRect)
{ {
var union = CGRectUnion(lhsRect, rhsRect); var union = CGRectUnion(lhsRect, rhsRect);
return _CGRectEqualToRect(union, lhsRect); return _CGRectEqualToRect(union, lhsRect);
} }
@@ -150,12 +102,12 @@ function CGRectContainsRect(lhsRect, rhsRect)
function CGRectIntersectsRect(lhsRect, rhsRect) function CGRectIntersectsRect(lhsRect, rhsRect)
{ {
var intersection = CGRectIntersection(lhsRect, rhsRect); var intersection = CGRectIntersection(lhsRect, rhsRect);
return !_CGRectIsEmpty(intersection); 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). the southwest corner the origin (rounded down), and the northeast corner a CGSize (rounded up).
@param aRect the rectangle to operate on @param aRect the rectangle to operate on
@return CGRect the modified rectangle (same as the input) @return CGRect the modified rectangle (same as the input)
@@ -168,7 +120,7 @@ function CGRectIntegral(aRect)
// Store these out separately, if not the GetMaxes will return incorrect values. // Store these out separately, if not the GetMaxes will return incorrect values.
var x = FLOOR(_CGRectGetMinX(aRect)), var x = FLOOR(_CGRectGetMinX(aRect)),
y = FLOOR(_CGRectGetMinY(aRect)); y = FLOOR(_CGRectGetMinY(aRect));
aRect.size.width = CEIL(_CGRectGetMaxX(aRect)) - x; aRect.size.width = CEIL(_CGRectGetMaxX(aRect)) - x;
aRect.size.height = CEIL(_CGRectGetMaxY(aRect)) - y; aRect.size.height = CEIL(_CGRectGetMaxY(aRect)) - y;
@@ -188,18 +140,18 @@ function CGRectIntegral(aRect)
function CGRectIntersection(lhsRect, rhsRect) function CGRectIntersection(lhsRect, rhsRect)
{ {
var intersection = _CGRectMake( var intersection = _CGRectMake(
MAX(_CGRectGetMinX(lhsRect), _CGRectGetMinX(rhsRect)), MAX(_CGRectGetMinX(lhsRect), _CGRectGetMinX(rhsRect)),
MAX(_CGRectGetMinY(lhsRect), _CGRectGetMinY(rhsRect)), MAX(_CGRectGetMinY(lhsRect), _CGRectGetMinY(rhsRect)),
0, 0); 0, 0);
intersection.size.width = MIN(_CGRectGetMaxX(lhsRect), _CGRectGetMaxX(rhsRect)) - _CGRectGetMinX(intersection); intersection.size.width = MIN(_CGRectGetMaxX(lhsRect), _CGRectGetMaxX(rhsRect)) - _CGRectGetMinX(intersection);
intersection.size.height = MIN(_CGRectGetMaxY(lhsRect), _CGRectGetMaxY(rhsRect)) - _CGRectGetMinY(intersection); intersection.size.height = MIN(_CGRectGetMaxY(lhsRect), _CGRectGetMaxY(rhsRect)) - _CGRectGetMinY(intersection);
return _CGRectIsEmpty(intersection) ? _CGRectMakeZero() : intersection; return _CGRectIsEmpty(intersection) ? _CGRectMakeZero() : intersection;
} }
/* /*
*/ */
function CGRectStandardize(aRect) function CGRectStandardize(aRect)
{ {
@@ -237,28 +189,28 @@ function CGRectUnion(lhsRect, rhsRect)
minY = MIN(_CGRectGetMinY(lhsRect), _CGRectGetMinY(rhsRect)), minY = MIN(_CGRectGetMinY(lhsRect), _CGRectGetMinY(rhsRect)),
maxX = MAX(_CGRectGetMaxX(lhsRect), _CGRectGetMaxX(rhsRect)), maxX = MAX(_CGRectGetMaxX(lhsRect), _CGRectGetMaxX(rhsRect)),
maxY = MAX(_CGRectGetMaxY(lhsRect), _CGRectGetMaxY(rhsRect)); maxY = MAX(_CGRectGetMaxY(lhsRect), _CGRectGetMaxY(rhsRect));
return _CGRectMake(minX, minY, maxX - minX, maxY - minY); return _CGRectMake(minX, minY, maxX - minX, maxY - minY);
} }
function CGPointFromString(aString) function CGPointFromString(aString)
{ {
var comma = aString.indexOf(','); var comma = aString.indexOf(',');
return { x:parseInt(aString.substr(1, comma - 1)), y:parseInt(aString.substring(comma + 1, aString.length)) }; return { x:parseInt(aString.substr(1, comma - 1)), y:parseInt(aString.substring(comma + 1, aString.length)) };
} }
function CGSizeFromString(aString) function CGSizeFromString(aString)
{ {
var comma = aString.indexOf(','); var comma = aString.indexOf(',');
return { width:parseInt(aString.substr(1, comma - 1)), height:parseInt(aString.substring(comma + 1, aString.length)) }; return { width:parseInt(aString.substr(1, comma - 1)), height:parseInt(aString.substring(comma + 1, aString.length)) };
} }
function CGRectFromString(aString) function CGRectFromString(aString)
{ {
var comma = aString.indexOf(',', aString.indexOf(',') + 1); var comma = aString.indexOf(',', aString.indexOf(',') + 1);
return { origin:CGPointFromString(aString.substr(1, comma - 1)), size:CGSizeFromString(aString.substring(comma + 2, aString.length)) }; return { origin:CGPointFromString(aString.substr(1, comma - 1)), size:CGSizeFromString(aString.substring(comma + 2, aString.length)) };
} }
@@ -281,6 +233,6 @@ function CPStringFromCGInset(anInset)
return '{' + anInset.top + ", " + anInset.left + ", " + anInset.bottom + ", " + anInset.right + '}'; return '{' + anInset.top + ", " + anInset.left + ", " + anInset.bottom + ", " + anInset.right + '}';
} }
/*! /*!
@} @}
*/ */

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