mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-09-09 12:17:13 +00:00
Compare commits
900
Commits
+9
-4
@@ -36,8 +36,8 @@
|
||||
@import "CPCibLoading.j"
|
||||
@import "CPCibOutletConnector.j"
|
||||
@import "CPClipView.j"
|
||||
@import "CPCollectionViewItem.j"
|
||||
@import "CPCollectionView.j"
|
||||
@import "CPCollectionViewItem.j"
|
||||
@import "CPColor.j"
|
||||
@import "CPColorPanel.j"
|
||||
@import "CPColorWell.j"
|
||||
@@ -53,8 +53,10 @@
|
||||
@import "CPFont.j"
|
||||
@import "CPFontManager.j"
|
||||
@import "CPGeometry.j"
|
||||
@import "CPGraphics.j"
|
||||
@import "CPImage.j"
|
||||
@import "CPImageView.j"
|
||||
@import "CPKeyBinding.j"
|
||||
@import "CPMenu.j"
|
||||
@import "CPMenuItem.j"
|
||||
@import "CPOpenPanel.j"
|
||||
@@ -65,20 +67,22 @@
|
||||
@import "CPProgressIndicator.j"
|
||||
@import "CPRadio.j"
|
||||
@import "CPResponder.j"
|
||||
@import "CPSearchField.j"
|
||||
@import "CPScrollView.j"
|
||||
@import "CPScroller.j"
|
||||
@import "CPScrollView.j"
|
||||
@import "CPSearchField.j"
|
||||
@import "CPSecureTextField.j"
|
||||
@import "CPSegmentedControl.j"
|
||||
@import "CPShadow.j"
|
||||
@import "CPSlider.j"
|
||||
@import "CPSplitView.j"
|
||||
@import "CPTabView.j"
|
||||
@import "CPTableColumn.j"
|
||||
@import "CPTableView.j"
|
||||
@import "CPTabView.j"
|
||||
@import "CPText.j"
|
||||
@import "CPTextField.j"
|
||||
@import "CPToolbar.j"
|
||||
@import "CPToolbarItem.j"
|
||||
@import "CPTokenField.j"
|
||||
@import "CPTreeNode.j"
|
||||
@import "CPView.j"
|
||||
@import "CPViewAnimation.j"
|
||||
@@ -86,3 +90,4 @@
|
||||
@import "CPWebView.j"
|
||||
@import "CPWindow.j"
|
||||
@import "CPWindowController.j"
|
||||
@import "CPArrayController.j"
|
||||
|
||||
+46
-11
@@ -26,11 +26,16 @@
|
||||
@import <Foundation/CPIndexSet.j>
|
||||
@import <Foundation/CPString.j>
|
||||
|
||||
@import <AppKit/CPView.j>
|
||||
|
||||
#import "CoreGraphics/CGGeometry.h"
|
||||
@import "CPView.j"
|
||||
@import "CPButton.j"
|
||||
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPAccordionViewItem
|
||||
|
||||
<p>A CPAccordionViewItem represents a single section of a CPAccordionView.</p>
|
||||
*/
|
||||
@implementation CPAccordionViewItem : CPObject
|
||||
{
|
||||
CPString _identifier @accessors(property=identifier);
|
||||
@@ -43,6 +48,10 @@
|
||||
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
|
||||
{
|
||||
self = [super init];
|
||||
@@ -55,6 +64,25 @@
|
||||
|
||||
@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
|
||||
{
|
||||
CPInteger _dirtyItemIndex;
|
||||
@@ -64,7 +92,10 @@
|
||||
CPMutableArray _itemViews;
|
||||
CPIndexSet _expandedItemIndexes;
|
||||
}
|
||||
|
||||
/*!
|
||||
Initializes the receiver for usage with the specified bounding rectangle
|
||||
@return the initialized view
|
||||
*/
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
@@ -95,7 +126,11 @@
|
||||
{
|
||||
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
|
||||
{
|
||||
[self insertItem:anItem atIndex:_items.length];
|
||||
@@ -178,7 +213,7 @@
|
||||
|
||||
if ([itemView isCollapsed])
|
||||
[self expandItemAtIndex:anIndex];
|
||||
|
||||
|
||||
else
|
||||
[self collapseItemAtIndex:anIndex];
|
||||
}
|
||||
@@ -202,12 +237,12 @@
|
||||
var itemView = _itemViews[anIndex];
|
||||
if (!itemView)
|
||||
return;
|
||||
|
||||
|
||||
if (!isEnabled)
|
||||
[self collapseItemAtIndex:anIndex];
|
||||
else
|
||||
[self expandItemAtIndex:anIndex];
|
||||
|
||||
|
||||
[itemView setEnabled:isEnabled];
|
||||
}
|
||||
|
||||
@@ -235,7 +270,7 @@
|
||||
{
|
||||
if (_items.length <= 0)
|
||||
return [self setFrameSize:_CGSizeMake(_CGRectGetWidth([self frame]), 0.0)];
|
||||
|
||||
|
||||
if (_dirtyItemIndex === CPNotFound)
|
||||
return;
|
||||
|
||||
@@ -356,7 +391,7 @@
|
||||
|
||||
[_contentView setFrameSize:_CGSizeMake(aWidth, contentHeight)];
|
||||
[self setFrame:_CGRectMake(0.0, aY, aWidth, contentHeight + headerHeight)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)resizeSubviewsWithOldSize:(CGSize)aSize
|
||||
@@ -373,7 +408,7 @@
|
||||
/*
|
||||
else if (aKeyPath === "itemHeaderPrototype")
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
+258
-104
@@ -26,39 +26,34 @@
|
||||
@import <Foundation/CPObject.j>
|
||||
@import <Foundation/CPString.j>
|
||||
|
||||
@import <AppKit/CPApplication.j>
|
||||
@import <AppKit/CPButton.j>
|
||||
@import <AppKit/CPColor.j>
|
||||
@import <AppKit/CPFont.j>
|
||||
@import <AppKit/CPImage.j>
|
||||
@import <AppKit/CPImageView.j>
|
||||
@import <AppKit/CPPanel.j>
|
||||
@import <AppKit/CPTextField.j>
|
||||
@import "CPApplication.j"
|
||||
@import "CPButton.j"
|
||||
@import "CPColor.j"
|
||||
@import "CPFont.j"
|
||||
@import "CPImage.j"
|
||||
@import "CPImageView.j"
|
||||
@import "CPPanel.j"
|
||||
@import "CPTextField.j"
|
||||
|
||||
/*
|
||||
@global
|
||||
@group CPAlertStyle
|
||||
*/
|
||||
CPWarningAlertStyle = 0;
|
||||
CPWarningAlertStyle = 0;
|
||||
/*
|
||||
@global
|
||||
@group CPAlertStyle
|
||||
*/
|
||||
CPInformationalAlertStyle = 1;
|
||||
CPInformationalAlertStyle = 1;
|
||||
/*
|
||||
@global
|
||||
@group CPAlertStyle
|
||||
*/
|
||||
CPCriticalAlertStyle = 2;
|
||||
|
||||
|
||||
var CPAlertWarningImage,
|
||||
CPAlertInformationImage,
|
||||
CPAlertErrorImage;
|
||||
CPCriticalAlertStyle = 2;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
|
||||
|
||||
CPAlert is an alert panel that can be displayed modally to present the
|
||||
user with a message and one or more options.
|
||||
|
||||
@@ -74,41 +69,51 @@ var CPAlertWarningImage,
|
||||
@delegate -(void)alertDidEnd:(CPAlert)theAlert returnCode:(int)returnCode;
|
||||
Called when the user dismisses the alert by clicking one of the buttons.
|
||||
@param theAlert the alert panel that the user dismissed
|
||||
@param returnCode the index of the button that the user clicked (starting from 0,
|
||||
@param returnCode the index of the button that the user clicked (starting from 0,
|
||||
representing the first button added to the alert which appears on the
|
||||
right, 1 representing the next button to the left and so on)
|
||||
*/
|
||||
@implementation CPAlert : CPObject
|
||||
@implementation CPAlert : CPView
|
||||
{
|
||||
CPPanel _alertPanel;
|
||||
|
||||
CPTextField _messageLabel;
|
||||
CPTextField _informativeLabel;
|
||||
CPImageView _alertImageView;
|
||||
|
||||
CPAlertStyle _alertStyle;
|
||||
CPString _windowTitle;
|
||||
int _windowStyle;
|
||||
int _buttonCount;
|
||||
CPArray _buttons;
|
||||
|
||||
id _delegate;
|
||||
SEL _didEndSelector;
|
||||
id _modalDelegate;
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
+ (CPString)defaultThemeClass
|
||||
{
|
||||
if (self != CPAlert)
|
||||
return;
|
||||
return @"alert";
|
||||
}
|
||||
|
||||
var bundle = [CPBundle bundleForClass:[self class]];
|
||||
|
||||
CPAlertWarningImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPAlert/dialog-warning.png"]
|
||||
size:CGSizeMake(32.0, 32.0)];
|
||||
|
||||
CPAlertInformationImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPAlert/dialog-information.png"]
|
||||
size:CGSizeMake(32.0, 32.0)];
|
||||
|
||||
CPAlertErrorImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPAlert/dialog-error.png"]
|
||||
size:CGSizeMake(32.0, 32.0)];
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[CGSizeMake(400.0, 110.0), CGInsetMake(15, 15, 15, 50), 6, 10,
|
||||
CPJustifiedTextAlignment, [CPColor blackColor], [CPFont boldSystemFontOfSize:13.0], [CPNull null], CGSizeMakeZero(),
|
||||
CPJustifiedTextAlignment, [CPColor blackColor], [CPFont systemFontOfSize:12.0], [CPNull null], CGSizeMakeZero(),
|
||||
CGPointMake(15, 12),
|
||||
[CPNull null],
|
||||
[CPNull null],
|
||||
[CPNull null]
|
||||
]
|
||||
forKeys:[@"size", @"content-inset", @"informative-offset", @"button-offset",
|
||||
@"message-text-alignment", @"message-text-color", @"message-text-font", @"message-text-shadow-color", @"message-text-shadow-offset",
|
||||
@"informative-text-alignment", @"informative-text-color", @"informative-text-font", @"informative-text-shadow-color", @"informative-text-shadow-offset",
|
||||
@"image-offset",
|
||||
@"information-image",
|
||||
@"warning-image",
|
||||
@"error-image"
|
||||
]];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -118,57 +123,56 @@ var CPAlertWarningImage,
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
_buttonCount = 0;
|
||||
_buttons = [CPArray array];
|
||||
_alertStyle = CPWarningAlertStyle;
|
||||
_alertPanel = nil;
|
||||
_windowStyle = nil;
|
||||
_didEndSelector = nil;
|
||||
|
||||
[self setWindowStyle:nil];
|
||||
_messageLabel = [CPTextField labelWithTitle:@"Alert"];
|
||||
_alertImageView = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
|
||||
_informativeLabel = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the window appearance.
|
||||
Sets the window appearance. If CPHUDBackgroundWindowMask is set, the default HUD theme
|
||||
will be activated.
|
||||
|
||||
@param styleMask - Either CPHUDBackgroundWindowMask or nil for standard.
|
||||
*/
|
||||
- (void)setWindowStyle:(int)styleMask
|
||||
{
|
||||
_windowStyle = styleMask;
|
||||
|
||||
_alertPanel = [[CPPanel alloc] initWithContentRect:CGRectMake(0.0, 0.0, 400.0, 110.0) styleMask:styleMask ? styleMask | CPTitledWindowMask : CPTitledWindowMask];
|
||||
[_alertPanel setFloatingPanel:YES];
|
||||
[_alertPanel center];
|
||||
|
||||
[_messageLabel setTextColor:(styleMask & CPHUDBackgroundWindowMask) ? [CPColor whiteColor] : [CPColor blackColor]];
|
||||
[self setTheme:(_windowStyle & CPHUDBackgroundWindowMask) ? [CPTheme defaultHudTheme] : [CPTheme defaultTheme]];
|
||||
|
||||
var count = [_buttons count];
|
||||
for(var i=0; i < count; i++)
|
||||
// We'll need to recreate the panel to get the new window style.
|
||||
_alertPanel = nil;
|
||||
}
|
||||
|
||||
- (void)_createPanel
|
||||
{
|
||||
var frame = CGRectMakeZero();
|
||||
frame.size = [self currentValueForThemeAttribute:@"size"];
|
||||
_alertPanel = [[CPPanel alloc] initWithContentRect:frame styleMask:_windowStyle ? _windowStyle | CPTitledWindowMask : CPTitledWindowMask];
|
||||
|
||||
var contentView = [_alertPanel contentView],
|
||||
count = [_buttons count];
|
||||
|
||||
if (count)
|
||||
{
|
||||
var button = _buttons[i];
|
||||
|
||||
[button setFrameSize:CGSizeMake([button frame].size.width, (styleMask == CPHUDBackgroundWindowMask) ? 20.0 : 24.0)];
|
||||
|
||||
[button setTheme:(_windowStyle === CPHUDBackgroundWindowMask) ? [CPTheme themeNamed:"Aristo-HUD"] : [CPTheme defaultTheme]];
|
||||
|
||||
[[_alertPanel contentView] addSubview:button];
|
||||
while (count--)
|
||||
[contentView addSubview:_buttons[count]];
|
||||
}
|
||||
|
||||
if (!_messageLabel)
|
||||
{
|
||||
var bounds = [[_alertPanel contentView] bounds];
|
||||
else
|
||||
[self addButtonWithTitle:@"OK"];
|
||||
|
||||
_messageLabel = [[CPTextField alloc] initWithFrame:CGRectMake(57.0, 10.0, CGRectGetWidth(bounds) - 73.0, 62.0)];
|
||||
[_messageLabel setFont:[CPFont boldSystemFontOfSize:13.0]];
|
||||
[_messageLabel setLineBreakMode:CPLineBreakByWordWrapping];
|
||||
[_messageLabel setAlignment:CPJustifiedTextAlignment];
|
||||
[_messageLabel setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
|
||||
|
||||
_alertImageView = [[CPImageView alloc] initWithFrame:CGRectMake(15.0, 12.0, 32.0, 32.0)];
|
||||
}
|
||||
|
||||
[[_alertPanel contentView] addSubview:_messageLabel];
|
||||
[[_alertPanel contentView] addSubview:_alertImageView];
|
||||
[contentView addSubview:_messageLabel];
|
||||
[contentView addSubview:_alertImageView];
|
||||
[contentView addSubview:_informativeLabel];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -231,7 +235,7 @@ var CPAlertWarningImage,
|
||||
}
|
||||
|
||||
/*!
|
||||
Set’s the receiver’s message text, or title, to a given text.
|
||||
Sets the receiver’s message text, or title, to a given text.
|
||||
@param messageText - Message text for the alert.
|
||||
*/
|
||||
- (void)setMessageText:(CPString)messageText
|
||||
@@ -239,41 +243,157 @@ var CPAlertWarningImage,
|
||||
[_messageLabel setStringValue:messageText];
|
||||
}
|
||||
|
||||
/*!
|
||||
Return's the receiver's message text body.
|
||||
/*!
|
||||
Returns the receiver's message text body.
|
||||
*/
|
||||
- (CPString)messageText
|
||||
{
|
||||
return [_messageLabel stringValue];
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the receiver's informative text, shown below the message text.
|
||||
@param informativeText - The informative text.
|
||||
*/
|
||||
- (void)setInformativeText:(CPString)informativeText
|
||||
{
|
||||
[_informativeLabel setStringValue:informativeText];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the receiver's informative text.
|
||||
*/
|
||||
- (CPString)informativeText
|
||||
{
|
||||
return [_informativeLabel stringValue];
|
||||
}
|
||||
|
||||
/*!
|
||||
Adds a button with a given title to the receiver.
|
||||
Buttons will be added starting from the right hand side of the \c CPAlert panel.
|
||||
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.
|
||||
*/
|
||||
- (void)addButtonWithTitle:(CPString)title
|
||||
{
|
||||
var bounds = [[_alertPanel contentView] bounds],
|
||||
button = [[CPButton alloc] initWithFrame:CGRectMake(CGRectGetWidth(bounds) - ((_buttonCount + 1) * 90.0), CGRectGetHeight(bounds) - 34.0, 80.0, (_windowStyle == CPHUDBackgroundWindowMask) ? 20.0 : 24.0)];
|
||||
|
||||
button = [[CPButton alloc] initWithFrame:CGRectMakeZero()],
|
||||
_buttonCount = [_buttons count];
|
||||
|
||||
[button setTitle:title];
|
||||
[button setTarget:self];
|
||||
[button setTag:_buttonCount];
|
||||
[button setAction:@selector(_notifyDelegate:)];
|
||||
|
||||
[button setTheme:(_windowStyle === CPHUDBackgroundWindowMask) ? [CPTheme themeNamed:"Aristo-HUD"] : [CPTheme defaultTheme]];
|
||||
[button setAutoresizingMask:CPViewMinXMargin | CPViewMinYMargin];
|
||||
[button setAction:@selector(_dismissAlert:)];
|
||||
|
||||
[[_alertPanel contentView] addSubview:button];
|
||||
|
||||
if (_buttonCount == 0)
|
||||
[_alertPanel setDefaultButton:button];
|
||||
|
||||
_buttonCount++;
|
||||
[_buttons addObject:button];
|
||||
if (_buttonCount == 0)
|
||||
[button setKeyEquivalent:CPCarriageReturnCharacter];
|
||||
else if ([title lowercaseString] === "cancel")
|
||||
[button setKeyEquivalent:CPEscapeFunctionKey];
|
||||
else
|
||||
[button setKeyEquivalent:nil];
|
||||
|
||||
[_buttons insertObject:button atIndex:0];
|
||||
}
|
||||
|
||||
- (void)layoutPanel
|
||||
{
|
||||
if (!_alertPanel)
|
||||
[self _createPanel];
|
||||
|
||||
var inset = [self currentValueForThemeAttribute:@"content-inset"],
|
||||
iconOffset = [self currentValueForThemeAttribute:@"image-offset"],
|
||||
theTitle,
|
||||
theImage;
|
||||
|
||||
switch (_alertStyle)
|
||||
{
|
||||
case CPWarningAlertStyle: theImage = [self currentValueForThemeAttribute:@"warning-image"];
|
||||
theTitle = @"Warning";
|
||||
break;
|
||||
case CPInformationalAlertStyle: theImage = [self currentValueForThemeAttribute:@"information-image"];
|
||||
theTitle = @"Information";
|
||||
break;
|
||||
case CPCriticalAlertStyle: theImage = [self currentValueForThemeAttribute:@"error-image"];
|
||||
theTitle = @"Error";
|
||||
break;
|
||||
}
|
||||
|
||||
[_alertImageView setImage:theImage];
|
||||
|
||||
var imageSize = theImage ? [theImage size] : CGSizeMakeZero();
|
||||
[_alertImageView setFrame:CGRectMake(iconOffset.x, iconOffset.y, imageSize.width, imageSize.height)];
|
||||
|
||||
[_alertPanel setTitle:_windowTitle ? _windowTitle : theTitle];
|
||||
[_alertPanel setFloatingPanel:YES];
|
||||
[_alertPanel center];
|
||||
|
||||
[_messageLabel setTextColor:[self currentValueForThemeAttribute:@"message-text-color"]];
|
||||
[_messageLabel setFont:[self currentValueForThemeAttribute:@"message-text-font"]];
|
||||
[_messageLabel setTextShadowColor:[self currentValueForThemeAttribute:@"message-text-shadow-color"]];
|
||||
[_messageLabel setTextShadowOffset:[self currentValueForThemeAttribute:@"message-text-shadow-offset"]];
|
||||
[_messageLabel setAlignment:[self currentValueForThemeAttribute:@"message-text-alignment"]];
|
||||
[_messageLabel setLineBreakMode:CPLineBreakByWordWrapping];
|
||||
|
||||
[_informativeLabel setTextColor:[self currentValueForThemeAttribute:@"informative-text-color"]];
|
||||
[_informativeLabel setFont:[self currentValueForThemeAttribute:@"informative-text-font"]];
|
||||
[_informativeLabel setTextShadowColor:[self currentValueForThemeAttribute:@"informative-text-shadow-color"]];
|
||||
[_informativeLabel setTextShadowOffset:[self currentValueForThemeAttribute:@"informative-text-shadow-offset"]];
|
||||
[_informativeLabel setLineBreakMode:CPLineBreakByWordWrapping];
|
||||
|
||||
// FIXME sizeWithFontCorrection shouldn't be needed.
|
||||
var bounds = [[_alertPanel contentView] bounds],
|
||||
offsetX = CGRectGetWidth(bounds) - inset.right,
|
||||
informativeOffset = [self currentValueForThemeAttribute:@"informative-offset"],
|
||||
buttonOffset = [self currentValueForThemeAttribute:@"button-offset"],
|
||||
|
||||
textWidth = offsetX - inset.left,
|
||||
messageSize = [([_messageLabel stringValue] || " ") sizeWithFont:[_messageLabel font] inWidth:textWidth],
|
||||
informationString = [_informativeLabel stringValue],
|
||||
informativeSize = [(informationString || " ") sizeWithFont:[_informativeLabel font] inWidth:textWidth],
|
||||
sizeWithFontCorrection = 6.0;
|
||||
|
||||
[_messageLabel setFrame:CGRectMake(inset.left, inset.top, textWidth, messageSize.height + sizeWithFontCorrection)];
|
||||
[_informativeLabel setFrame:CGRectMake(inset.left, CGRectGetMaxY([_messageLabel frame]) + informativeOffset, textWidth, informativeSize.height + sizeWithFontCorrection)];
|
||||
// Don't let an empty informative label partially cover the buttons.
|
||||
[_informativeLabel setHidden:!informationString];
|
||||
|
||||
var aRepresentativeButton = _buttons[0],
|
||||
buttonY = MAX(CGRectGetMaxY([_alertImageView frame]), CGRectGetMaxY(informationString ? [_informativeLabel frame] : [_messageLabel frame])) + buttonOffset; // the lower of the bottom of the text and the bottom of the icon.
|
||||
|
||||
[aRepresentativeButton setTheme:[self theme]];
|
||||
[aRepresentativeButton sizeToFit];
|
||||
|
||||
// Make the window just tall enough to fit everything. Bit of a hack really.
|
||||
var minimumSize = [self currentValueForThemeAttribute:@"size"],
|
||||
desiredHeight = MAX(minimumSize.height, buttonY + CGRectGetHeight([aRepresentativeButton bounds]) + inset.bottom),
|
||||
deltaY = desiredHeight - CGRectGetHeight(bounds),
|
||||
frameSize = CGSizeMakeCopy([_alertPanel frame].size);
|
||||
|
||||
frameSize.height += deltaY;
|
||||
[_alertPanel setFrameSize:frameSize];
|
||||
|
||||
var count = [_buttons count];
|
||||
|
||||
while (count--)
|
||||
{
|
||||
var button = _buttons[count];
|
||||
[button setTheme:[self theme]];
|
||||
[button sizeToFit];
|
||||
|
||||
var buttonBounds = [button bounds],
|
||||
width = MAX(80.0, CGRectGetWidth(buttonBounds)),
|
||||
height = CGRectGetHeight(buttonBounds);
|
||||
|
||||
offsetX -= width;
|
||||
[button setFrame:CGRectMake(offsetX, buttonY, width, height)];
|
||||
offsetX -= 10;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -283,34 +403,68 @@ var CPAlertWarningImage,
|
||||
*/
|
||||
- (void)runModal
|
||||
{
|
||||
var theTitle;
|
||||
|
||||
switch (_alertStyle)
|
||||
{
|
||||
case CPWarningAlertStyle: [_alertImageView setImage:CPAlertWarningImage];
|
||||
theTitle = @"Warning";
|
||||
break;
|
||||
case CPInformationalAlertStyle: [_alertImageView setImage:CPAlertInformationImage];
|
||||
theTitle = @"Information";
|
||||
break;
|
||||
case CPCriticalAlertStyle: [_alertImageView setImage:CPAlertErrorImage];
|
||||
theTitle = @"Error";
|
||||
break;
|
||||
}
|
||||
|
||||
[_alertPanel setTitle:_windowTitle ? _windowTitle : theTitle];
|
||||
|
||||
[self layoutPanel];
|
||||
[CPApp runModalForWindow:_alertPanel];
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (void)_notifyDelegate:(id)button
|
||||
{
|
||||
[CPApp abortModal];
|
||||
[_alertPanel close];
|
||||
/*!
|
||||
Runs the receiver modally as an alert sheet attached to a specified window.
|
||||
|
||||
if (_delegate && [_delegate respondsToSelector:@selector(alertDidEnd:returnCode:)])
|
||||
[_delegate alertDidEnd:self returnCode:[button tag]];
|
||||
@param window The parent window for the sheet.
|
||||
@param modalDelegate The delegate for the modal-dialog session.
|
||||
@param alertDidEndSelector Message the alert sends to modalDelegate after the sheet is dismissed.
|
||||
@param contextInfo Contextual data passed to modalDelegate in didEndSelector message.
|
||||
*/
|
||||
- (void)beginSheetModalForWindow:(CPWindow)window modalDelegate:(id)modalDelegate didEndSelector:(SEL)alertDidEndSelector contextInfo:(void)contextInfo
|
||||
{
|
||||
if (!(_windowStyle & CPDocModalWindowMask))
|
||||
[self setWindowStyle:CPDocModalWindowMask];
|
||||
[self layoutPanel];
|
||||
|
||||
_didEndSelector = alertDidEndSelector;
|
||||
_modalDelegate = modalDelegate;
|
||||
|
||||
[CPApp beginSheet:_alertPanel modalForWindow:window modalDelegate:self didEndSelector:@selector(_alertDidEnd:returnCode:contextInfo:) contextInfo:contextInfo];
|
||||
}
|
||||
|
||||
/*!
|
||||
Runs the receiver modally as an alert sheet attached to a specified window.
|
||||
|
||||
@param window The parent window for the sheet.
|
||||
*/
|
||||
- (void)beginSheetModalForWindow:(CPWindow)window
|
||||
{
|
||||
if (!(_windowStyle & CPDocModalWindowMask))
|
||||
[self setWindowStyle:CPDocModalWindowMask];
|
||||
[self layoutPanel];
|
||||
|
||||
[CPApp beginSheet:_alertPanel modalForWindow:window modalDelegate:self didEndSelector:@selector(_alertDidEnd:returnCode:contextInfo:) contextInfo:nil];
|
||||
}
|
||||
|
||||
- (void)_alertDidEnd:(CPWindow)aSheet returnCode:(CPInteger)returnCode contextInfo:(id)contextInfo
|
||||
{
|
||||
if ([_delegate respondsToSelector:@selector(alertDidEnd:returnCode:)])
|
||||
[_delegate alertDidEnd:self returnCode:returnCode];
|
||||
|
||||
if (_didEndSelector)
|
||||
objj_msgSend(_modalDelegate, _didEndSelector, self, returnCode, contextInfo);
|
||||
|
||||
_didEndSelector = nil;
|
||||
_modalDelegate = nil;
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (void)_dismissAlert:(CPButton)button
|
||||
{
|
||||
if ([_alertPanel isSheet])
|
||||
[CPApp endSheet:_alertPanel returnCode:[button tag]];
|
||||
else
|
||||
{
|
||||
[CPApp abortModal];
|
||||
[_alertPanel close];
|
||||
|
||||
[self _alertDidEnd:nil returnCode:[button tag] contextInfo:nil];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+27
-27
@@ -48,14 +48,14 @@ CPAnimationLinear = 3;
|
||||
|
||||
ACTUAL_FRAME_RATE = 0;
|
||||
|
||||
/*!
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPAnimation
|
||||
|
||||
Manages an animation. Contains timing and progress information.
|
||||
|
||||
@par Delegate Methods
|
||||
|
||||
|
||||
@delegate -(BOOL)animationShouldStart:(CPAnimation)animation;
|
||||
Called at the beginning of \c -startAnimation.
|
||||
@param animation the animation that will start
|
||||
@@ -81,13 +81,13 @@ ACTUAL_FRAME_RATE = 0;
|
||||
{
|
||||
CPTimeInterval _lastTime;
|
||||
CPTimeInterval _duration;
|
||||
|
||||
|
||||
CPAnimationCurve _animationCurve;
|
||||
CAMediaTimingFunction _timingFunction;
|
||||
|
||||
|
||||
float _frameRate;
|
||||
float _progress;
|
||||
|
||||
|
||||
id _delegate;
|
||||
CPTimer _timer;
|
||||
}
|
||||
@@ -101,7 +101,7 @@ ACTUAL_FRAME_RATE = 0;
|
||||
- (id)initWithDuration:(float)aDuration animationCurve:(CPAnimationCurve)anAnimationCurve
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_progress = 0.0;
|
||||
@@ -110,14 +110,14 @@ ACTUAL_FRAME_RATE = 0;
|
||||
|
||||
[self setAnimationCurve:anAnimationCurve];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets 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
|
||||
{
|
||||
@@ -125,13 +125,13 @@ ACTUAL_FRAME_RATE = 0;
|
||||
{
|
||||
case CPAnimationEaseInOut: timingFunctionName = kCAMediaTimingFunctionEaseInEaseOut;
|
||||
break;
|
||||
|
||||
|
||||
case CPAnimationEaseIn: timingFunctionName = kCAMediaTimingFunctionEaseIn;
|
||||
break;
|
||||
|
||||
|
||||
case CPAnimationEaseOut: timingFunctionName = kCAMediaTimingFunctionEaseOut;
|
||||
break;
|
||||
|
||||
|
||||
case CPAnimationLinear: timingFunctionName = kCAMediaTimingFunctionLinear;
|
||||
break;
|
||||
|
||||
@@ -139,7 +139,7 @@ ACTUAL_FRAME_RATE = 0;
|
||||
reason:"Invalid value provided for animation curve"];
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
_animationCurve = anAnimationCurve;
|
||||
_timingFunction = [CAMediaTimingFunction functionWithName:timingFunctionName];
|
||||
}
|
||||
@@ -161,7 +161,7 @@ ACTUAL_FRAME_RATE = 0;
|
||||
{
|
||||
if (aDuration < 0)
|
||||
[CPException raise:CPInvalidArgumentException reason:"aDuration can't be negative"];
|
||||
|
||||
|
||||
_duration = aDuration;
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@ ACTUAL_FRAME_RATE = 0;
|
||||
{
|
||||
if (frameRate < 0)
|
||||
[CPException raise:CPInvalidArgumentException reason:"frameRate can't be negative"];
|
||||
|
||||
|
||||
_frameRate = frameRate;
|
||||
}
|
||||
|
||||
@@ -221,13 +221,13 @@ ACTUAL_FRAME_RATE = 0;
|
||||
// If we're already animating, or our delegate stops us, animate.
|
||||
if (_timer || _delegate && [_delegate respondsToSelector:@selector(animationShouldStart:)] && ![_delegate animationShouldStart:self])
|
||||
return;
|
||||
|
||||
|
||||
if (_progress === 1.0)
|
||||
_progress = 0.0;
|
||||
|
||||
|
||||
ACTUAL_FRAME_RATE = 0;
|
||||
_lastTime = new Date();
|
||||
|
||||
|
||||
_timer = [CPTimer scheduledTimerWithTimeInterval:0.0 target:self selector:@selector(animationTimerDidFire:) userInfo:nil repeats:YES];
|
||||
}
|
||||
|
||||
@@ -242,14 +242,14 @@ ACTUAL_FRAME_RATE = 0;
|
||||
_lastTime = currentTime;
|
||||
|
||||
++ACTUAL_FRAME_RATE;
|
||||
|
||||
|
||||
[self setCurrentProgress:progress];
|
||||
|
||||
|
||||
if (progress === 1.0)
|
||||
{
|
||||
[_timer invalidate];
|
||||
_timer = nil;
|
||||
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(animationDidEnd:)])
|
||||
[_delegate animationDidEnd:self];
|
||||
}
|
||||
@@ -262,10 +262,10 @@ ACTUAL_FRAME_RATE = 0;
|
||||
{
|
||||
if (!_timer)
|
||||
return;
|
||||
|
||||
|
||||
[_timer invalidate];
|
||||
_timer = nil;
|
||||
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(animationDidStop:)])
|
||||
[_delegate animationDidStop:self];
|
||||
}
|
||||
@@ -302,16 +302,16 @@ ACTUAL_FRAME_RATE = 0;
|
||||
- (float)currentValue
|
||||
{
|
||||
var t = [self currentProgress];
|
||||
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(animation:valueForProgress:)])
|
||||
return [_delegate animation:self valueForProgress:t];
|
||||
|
||||
|
||||
var c1 = [],
|
||||
c2 = [];
|
||||
|
||||
|
||||
[_timingFunction getControlPointAtIndex:1 values:c1];
|
||||
[_timingFunction getControlPointAtIndex:2 values:c2];
|
||||
|
||||
|
||||
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));};
|
||||
// Given an x value, find a parametric value it came from.
|
||||
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.
|
||||
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.
|
||||
|
||||
+171
-146
@@ -31,7 +31,6 @@
|
||||
@import "CPCibLoading.j"
|
||||
@import "CPPlatform.j"
|
||||
|
||||
#include "Platform/Platform.h"
|
||||
|
||||
var CPMainCibFile = @"CPMainCibFile",
|
||||
CPMainCibFileHumanFriendly = @"Main cib file base name";
|
||||
@@ -54,7 +53,7 @@ CPRunStoppedResponse = -1000;
|
||||
CPRunAbortedResponse = -1001;
|
||||
CPRunContinuesResponse = -1002;
|
||||
|
||||
/*!
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPApplication
|
||||
|
||||
@@ -62,7 +61,7 @@ CPRunContinuesResponse = -1002;
|
||||
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
|
||||
\c CPApplicationMain function. A simple example looks like this:
|
||||
|
||||
|
||||
<pre>
|
||||
function main(args, namedArgs)
|
||||
{
|
||||
@@ -82,25 +81,25 @@ CPRunContinuesResponse = -1002;
|
||||
@implementation CPApplication : CPResponder
|
||||
{
|
||||
CPArray _eventListeners;
|
||||
|
||||
|
||||
CPEvent _currentEvent;
|
||||
|
||||
|
||||
CPArray _windows;
|
||||
CPWindow _keyWindow;
|
||||
CPWindow _mainWindow;
|
||||
CPWindow _previousKeyWindow;
|
||||
CPWindow _previousMainWindow;
|
||||
|
||||
|
||||
CPMenu _mainMenu;
|
||||
CPDocumentController _documentController;
|
||||
|
||||
|
||||
CPModalSession _currentSession;
|
||||
|
||||
|
||||
//
|
||||
id _delegate;
|
||||
BOOL _finishedLaunching;
|
||||
BOOL _isActive;
|
||||
|
||||
|
||||
CPDictionary _namedArgs;
|
||||
CPArray _args;
|
||||
CPString _fullArgsString;
|
||||
@@ -108,6 +107,8 @@ CPRunContinuesResponse = -1002;
|
||||
CPImage _applicationIconImage;
|
||||
|
||||
CPPanel _aboutPanel;
|
||||
|
||||
CPThemeBlend _themeBlend @accessors(property=themeBlend);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -119,7 +120,7 @@ CPRunContinuesResponse = -1002;
|
||||
{
|
||||
if (!CPApp)
|
||||
CPApp = [[CPApplication alloc] init];
|
||||
|
||||
|
||||
return CPApp;
|
||||
}
|
||||
|
||||
@@ -131,73 +132,18 @@ CPRunContinuesResponse = -1002;
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
CPApp = self;
|
||||
|
||||
if (self)
|
||||
{
|
||||
_eventListeners = [];
|
||||
|
||||
|
||||
_windows = [];
|
||||
|
||||
|
||||
[_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;
|
||||
}
|
||||
|
||||
@@ -278,28 +224,28 @@ CPRunContinuesResponse = -1002;
|
||||
|
||||
// We also want to set the default cursor on the body, so that buttons and things don't have an iBeam
|
||||
[[CPCursor arrowCursor] set];
|
||||
|
||||
|
||||
var bundle = [CPBundle mainBundle],
|
||||
types = [bundle objectForInfoDictionaryKey:@"CPBundleDocumentTypes"];
|
||||
|
||||
|
||||
if ([types count] > 0)
|
||||
_documentController = [CPDocumentController sharedDocumentController];
|
||||
|
||||
|
||||
var delegateClassName = [bundle objectForInfoDictionaryKey:@"CPApplicationDelegateClass"];
|
||||
|
||||
|
||||
if (delegateClassName)
|
||||
{
|
||||
var delegateClass = objj_getClass(delegateClassName);
|
||||
|
||||
|
||||
if (delegateClass)
|
||||
if ([_documentController class] == delegateClass)
|
||||
[self setDelegate:_documentController];
|
||||
else
|
||||
[self setDelegate:[[delegateClass alloc] init]];
|
||||
}
|
||||
|
||||
|
||||
var defaultCenter = [CPNotificationCenter defaultCenter];
|
||||
|
||||
|
||||
[defaultCenter
|
||||
postNotificationName:CPApplicationWillFinishLaunchingNotification
|
||||
object:self];
|
||||
@@ -380,7 +326,9 @@ CPRunContinuesResponse = -1002;
|
||||
applicationVersion = [options objectForKey:@"ApplicationVersion"] || [mainInfo objectForKey:@"CPBundleShortVersionString"],
|
||||
copyright = [options objectForKey:@"Copyright"] || [mainInfo objectForKey:@"CPHumanReadableCopyright"];
|
||||
|
||||
var aboutPanelController = [[CPWindowController alloc] initWithWindowCibName:@"AboutPanel"],
|
||||
var aboutPanelPath = [[CPBundle bundleForClass:[CPWindowController class]] pathForResource:@"AboutPanel.cib"],
|
||||
aboutPanelController = [CPWindowController alloc],
|
||||
aboutPanelController = [aboutPanelController initWithWindowCibPath:aboutPanelPath owner:aboutPanelController],
|
||||
aboutPanel = [aboutPanelController window],
|
||||
contentView = [aboutPanel contentView],
|
||||
imageView = [contentView viewWithTag:1],
|
||||
@@ -388,14 +336,14 @@ CPRunContinuesResponse = -1002;
|
||||
versionLabel = [contentView viewWithTag:3],
|
||||
copyrightLabel = [contentView viewWithTag:4],
|
||||
standardPath = [[CPBundle bundleForClass:[self class]] pathForResource:@"standardApplicationIcon.png"];
|
||||
|
||||
|
||||
// FIXME move this into the CIB eventually
|
||||
[applicationLabel setFont:[CPFont boldSystemFontOfSize:14.0]];
|
||||
[applicationLabel setAlignment:CPCenterTextAlignment];
|
||||
[versionLabel setAlignment:CPCenterTextAlignment];
|
||||
[copyrightLabel setAlignment:CPCenterTextAlignment];
|
||||
|
||||
[imageView setImage:applicationIcon || [[CPImage alloc] initWithContentsOfFile:standardPath
|
||||
[imageView setImage:applicationIcon || [[CPImage alloc] initWithContentsOfFile:standardPath
|
||||
size:CGSizeMake(256, 256)]];
|
||||
|
||||
[applicationLabel setStringValue:applicationTitle || ""];
|
||||
@@ -499,10 +447,10 @@ CPRunContinuesResponse = -1002;
|
||||
return;
|
||||
// raise exception;
|
||||
}
|
||||
|
||||
|
||||
_currentSession._state = aCode;
|
||||
_currentSession = _currentSession._previous;
|
||||
|
||||
|
||||
// if (aCode == CPRunAbortedResponse)
|
||||
[self _removeRunModalLoop];
|
||||
}
|
||||
@@ -511,12 +459,12 @@ CPRunContinuesResponse = -1002;
|
||||
- (void)_removeRunModalLoop
|
||||
{
|
||||
var count = _eventListeners.length;
|
||||
|
||||
|
||||
while (count--)
|
||||
if (_eventListeners[count]._callback === _CPRunModalLoop)
|
||||
{
|
||||
_eventListeners.splice(count, 1);
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -554,12 +502,13 @@ CPRunContinuesResponse = -1002;
|
||||
{
|
||||
aModalSession._previous = _currentSession;
|
||||
_currentSession = aModalSession;
|
||||
|
||||
|
||||
var theWindow = aModalSession._window;
|
||||
|
||||
[theWindow center];
|
||||
[theWindow makeKeyAndOrderFront:self];
|
||||
|
||||
[theWindow makeKeyWindow];
|
||||
[theWindow orderFront:self];
|
||||
|
||||
// [theWindow._bridge _obscureWindowsBelowModalWindow];
|
||||
|
||||
[CPApp setCallback:_CPRunModalLoop forNextEventMatchingMask:CPAnyEventMask untilDate:nil inMode:0 dequeue:NO];
|
||||
@@ -573,7 +522,7 @@ CPRunContinuesResponse = -1002;
|
||||
{
|
||||
if (!_currentSession)
|
||||
return nil;
|
||||
|
||||
|
||||
return _currentSession._window;
|
||||
}
|
||||
|
||||
@@ -618,7 +567,7 @@ CPRunContinuesResponse = -1002;
|
||||
{
|
||||
if (_eventListeners[_eventListeners.length - 1]._mask & (1 << [anEvent type]))
|
||||
_eventListeners.pop()._callback(anEvent);
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -670,7 +619,11 @@ CPRunContinuesResponse = -1002;
|
||||
*/
|
||||
- (CPArray)orderedWindows
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
return CPWindowObjectList();
|
||||
#else
|
||||
return [];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)hide:(id)aSender
|
||||
@@ -729,11 +682,11 @@ CPRunContinuesResponse = -1002;
|
||||
|
||||
if ([super tryToPerform:anAction with:anObject])
|
||||
return YES;
|
||||
|
||||
if([_delegate respondsToSelector:anAction])
|
||||
|
||||
if ([_delegate respondsToSelector:anAction])
|
||||
{
|
||||
[_delegate performSelector:anAction withObject:anObject];
|
||||
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
@@ -753,9 +706,9 @@ CPRunContinuesResponse = -1002;
|
||||
|
||||
if (!target)
|
||||
return NO;
|
||||
|
||||
|
||||
[target performSelector:anAction withObject:aSender];
|
||||
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
@@ -774,10 +727,10 @@ CPRunContinuesResponse = -1002;
|
||||
{
|
||||
if (!anAction)
|
||||
return nil;
|
||||
|
||||
|
||||
if (aTarget)
|
||||
return aTarget;
|
||||
|
||||
|
||||
return [self targetForAction:anAction];
|
||||
}
|
||||
|
||||
@@ -802,28 +755,28 @@ CPRunContinuesResponse = -1002;
|
||||
{
|
||||
var responder = [aWindow firstResponder],
|
||||
checkWindow = YES;
|
||||
|
||||
|
||||
while (responder)
|
||||
{
|
||||
if ([responder respondsToSelector:anAction])
|
||||
return responder;
|
||||
|
||||
|
||||
if (responder == aWindow)
|
||||
checkWindow = NO;
|
||||
|
||||
|
||||
responder = [responder nextResponder];
|
||||
}
|
||||
|
||||
|
||||
if (checkWindow && [aWindow respondsToSelector:anAction])
|
||||
return aWindow;
|
||||
|
||||
|
||||
var delegate = [aWindow delegate];
|
||||
|
||||
|
||||
if ([delegate respondsToSelector:anAction])
|
||||
return delegate;
|
||||
|
||||
var windowController = [aWindow windowController];
|
||||
|
||||
|
||||
if ([windowController respondsToSelector:anAction])
|
||||
return windowController;
|
||||
|
||||
@@ -852,26 +805,26 @@ CPRunContinuesResponse = -1002;
|
||||
{
|
||||
if (!anAction)
|
||||
return nil;
|
||||
|
||||
|
||||
var target = [self _targetForWindow:[self keyWindow] action:anAction];
|
||||
|
||||
|
||||
if (target)
|
||||
return target;
|
||||
|
||||
|
||||
target = [self _targetForWindow:[self mainWindow] action:anAction];
|
||||
|
||||
|
||||
if (target)
|
||||
return target;
|
||||
|
||||
|
||||
if ([self respondsToSelector:anAction])
|
||||
return self;
|
||||
|
||||
|
||||
if ([_delegate respondsToSelector:anAction])
|
||||
return _delegate;
|
||||
|
||||
|
||||
if ([_documentController respondsToSelector:anAction])
|
||||
return _documentController;
|
||||
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
@@ -901,30 +854,31 @@ CPRunContinuesResponse = -1002;
|
||||
@param aContextInfo
|
||||
*/
|
||||
- (void)beginSheet:(CPWindow)aSheet modalForWindow:(CPWindow)aWindow modalDelegate:(id)aModalDelegate didEndSelector:(SEL)aDidEndSelector contextInfo:(id)aContextInfo
|
||||
{
|
||||
{
|
||||
var styleMask = [aSheet styleMask];
|
||||
if (!(styleMask & CPDocModalWindowMask))
|
||||
{
|
||||
[CPException raise:CPInternalInconsistencyException reason:@"Currently only CPDocModalWindowMask style mask is supported for attached sheets"];
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
[aWindow orderFront:self];
|
||||
[aSheet setPlatformWindow:[aWindow platformWindow]];
|
||||
[aWindow _attachSheet:aSheet modalDelegate:aModalDelegate didEndSelector:aDidEndSelector contextInfo:aContextInfo];
|
||||
}
|
||||
|
||||
- (void)endSheet:(CPWindow)sheet returnCode:(int)returnCode
|
||||
{
|
||||
var count = [_windows count];
|
||||
|
||||
|
||||
while (--count >= 0)
|
||||
{
|
||||
var aWindow = [_windows objectAtIndex:count];
|
||||
var context = aWindow._sheetContext;
|
||||
|
||||
var aWindow = [_windows objectAtIndex:count],
|
||||
context = aWindow._sheetContext;
|
||||
|
||||
if (context != nil && context["sheet"] === sheet)
|
||||
{
|
||||
context["returnCode"] = returnCode;
|
||||
context["returnCode"] = returnCode;
|
||||
[aWindow _detachSheetWindow];
|
||||
return;
|
||||
}
|
||||
@@ -938,40 +892,40 @@ CPRunContinuesResponse = -1002;
|
||||
|
||||
- (CPArray)arguments
|
||||
{
|
||||
if(_fullArgsString !== window.location.hash)
|
||||
if (_fullArgsString !== window.location.hash)
|
||||
[self _reloadArguments];
|
||||
|
||||
|
||||
return _args;
|
||||
}
|
||||
|
||||
- (void)setArguments:(CPArray)args
|
||||
{
|
||||
if(!args || args.length == 0)
|
||||
if (!args || args.length == 0)
|
||||
{
|
||||
_args = [];
|
||||
window.location.hash = @"#";
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if([args class] != CPArray)
|
||||
|
||||
if ([args class] != CPArray)
|
||||
args = [CPArray arrayWithObject:args];
|
||||
|
||||
|
||||
_args = args;
|
||||
|
||||
|
||||
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]);
|
||||
|
||||
|
||||
var hash = [toEncode componentsJoinedByString:@"/"];
|
||||
|
||||
|
||||
window.location.hash = @"#" + hash;
|
||||
}
|
||||
|
||||
- (void)_reloadArguments
|
||||
{
|
||||
_fullArgsString = window.location.hash;
|
||||
|
||||
|
||||
if (_fullArgsString.length)
|
||||
{
|
||||
var args = _fullArgsString.substring(1).split("/");
|
||||
@@ -1006,18 +960,18 @@ CPRunContinuesResponse = -1002;
|
||||
|
||||
- (void)_willBecomeActive
|
||||
{
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationWillBecomeActiveNotification
|
||||
object:self
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationWillBecomeActiveNotification
|
||||
object:self
|
||||
userInfo:nil];
|
||||
}
|
||||
|
||||
- (void)_didBecomeActive
|
||||
{
|
||||
if (![self keyWindow] && _previousKeyWindow &&
|
||||
if (![self keyWindow] && _previousKeyWindow &&
|
||||
[[self windows] indexOfObjectIdenticalTo:_previousKeyWindow] !== CPNotFound)
|
||||
[_previousKeyWindow makeKeyWindow];
|
||||
|
||||
if (![self mainWindow] && _previousMainWindow &&
|
||||
if (![self mainWindow] && _previousMainWindow &&
|
||||
[[self windows] indexOfObjectIdenticalTo:_previousMainWindow] !== CPNotFound)
|
||||
[_previousMainWindow makeMainWindow];
|
||||
|
||||
@@ -1031,15 +985,15 @@ CPRunContinuesResponse = -1002;
|
||||
_previousKeyWindow = nil;
|
||||
_previousMainWindow = nil;
|
||||
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationDidBecomeActiveNotification
|
||||
object:self
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationDidBecomeActiveNotification
|
||||
object:self
|
||||
userInfo:nil];
|
||||
}
|
||||
|
||||
- (void)_willResignActive
|
||||
{
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationWillResignActiveNotification
|
||||
object:self
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationWillResignActiveNotification
|
||||
object:self
|
||||
userInfo:nil];
|
||||
}
|
||||
|
||||
@@ -1060,14 +1014,13 @@ CPRunContinuesResponse = -1002;
|
||||
[_previousMainWindow resignMainWindow];
|
||||
}
|
||||
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationDidResignActiveNotification
|
||||
object:self
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPApplicationDidResignActiveNotification
|
||||
object:self
|
||||
userInfo:nil];
|
||||
}
|
||||
|
||||
+ (CPString)defaultThemeName
|
||||
{
|
||||
// FIXME: don't hardcode
|
||||
return ([[CPBundle mainBundle] objectForInfoDictionaryKey:"CPDefaultTheme"] || @"Aristo");
|
||||
}
|
||||
|
||||
@@ -1083,13 +1036,14 @@ var _CPEventListenerMake = function(anEventMask, aCallback)
|
||||
return { _mask:anEventMask, _callback:aCallback };
|
||||
}
|
||||
|
||||
var _CPRunModalLoop = function(anEvent)
|
||||
// Make this a global for use in CPPlatformWindow+DOM.j.
|
||||
_CPRunModalLoop = function(anEvent)
|
||||
{
|
||||
[CPApp setCallback:_CPRunModalLoop forNextEventMatchingMask:CPAnyEventMask untilDate:nil inMode:0 dequeue:NO];
|
||||
|
||||
var theWindow = [anEvent window],
|
||||
modalSession = CPApp._currentSession;
|
||||
|
||||
|
||||
if (theWindow == modalSession._window || [theWindow worksWhenModal])
|
||||
[theWindow sendEvent:anEvent];
|
||||
}
|
||||
@@ -1161,8 +1115,15 @@ var _CPAppBootstrapperActions = nil;
|
||||
|
||||
+ (BOOL)loadDefaultTheme
|
||||
{
|
||||
var blend = [[CPThemeBlend alloc] initWithContentsOfURL:[[CPBundle bundleForClass:[CPApplication class]] pathForResource:[CPApplication defaultThemeName] + ".blend"]];
|
||||
var defaultThemeName = [CPApplication defaultThemeName],
|
||||
themeURL = nil;
|
||||
|
||||
if (defaultThemeName === @"Aristo")
|
||||
themeURL = [[CPBundle bundleForClass:[CPApplication class]] pathForResource:defaultThemeName + @".blend"];
|
||||
else
|
||||
themeURL = [[CPBundle mainBundle] pathForResource:defaultThemeName + @".blend"];
|
||||
|
||||
var blend = [[CPThemeBlend alloc] initWithContentsOfURL:themeURL];
|
||||
[blend loadWithDelegate:self];
|
||||
|
||||
return YES;
|
||||
@@ -1170,6 +1131,7 @@ var _CPAppBootstrapperActions = nil;
|
||||
|
||||
+ (void)blendDidFinishLoading:(CPThemeBlend)aThemeBlend
|
||||
{
|
||||
[[CPApplication sharedApplication] setThemeBlend:aThemeBlend];
|
||||
[CPTheme setDefaultTheme:[CPTheme themeNamed:[CPApplication defaultThemeName]]];
|
||||
|
||||
[self performActions];
|
||||
@@ -1188,10 +1150,73 @@ var _CPAppBootstrapperActions = nil;
|
||||
|
||||
return YES;
|
||||
}
|
||||
else
|
||||
[self loadCiblessBrowserMainMenu];
|
||||
|
||||
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
|
||||
{
|
||||
[self performActions];
|
||||
@@ -1204,7 +1229,7 @@ var _CPAppBootstrapperActions = nil;
|
||||
|
||||
+ (void)reset
|
||||
{
|
||||
_CPAppBootstrapperActions = nil;
|
||||
_CPAppBootstrapperActions = nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,675 @@
|
||||
|
||||
|
||||
/*
|
||||
* 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
|
||||
+11
-10
@@ -4,7 +4,7 @@
|
||||
* Created by Ross Boucher.
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -20,26 +20,27 @@
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
* Copyright 2009 280 North, Inc.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
@import <AppKit/CPGraphicsContext.j>
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
@import "CPGraphicsContext.j"
|
||||
|
||||
|
||||
// Class defaults
|
||||
|
||||
var DefaultLineWidth = 1.0;
|
||||
|
||||
|
||||
/*!
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPBezierPath
|
||||
|
||||
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
|
||||
line segments.
|
||||
|
||||
line segments.
|
||||
|
||||
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).
|
||||
*/
|
||||
@@ -64,9 +65,9 @@ var DefaultLineWidth = 1.0;
|
||||
+ (CPBezierPath)bezierPathWithOvalInRect:(CGRect)rect
|
||||
{
|
||||
var path = [self bezierPath];
|
||||
|
||||
|
||||
[path appendBezierPathWithOvalInRect:rect];
|
||||
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
@@ -76,9 +77,9 @@ var DefaultLineWidth = 1.0;
|
||||
+ (CPBezierPath)bezierPathWithRect:(CGRect)rect
|
||||
{
|
||||
var path = [self bezierPath];
|
||||
|
||||
|
||||
[path appendBezierPathWithRect:rect];
|
||||
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
+176
-52
@@ -19,25 +19,33 @@
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
@import "CPView.j"
|
||||
|
||||
// CPBoxType
|
||||
CPBoxPrimary = 0;
|
||||
CPBoxSecondary = 1;
|
||||
CPBoxSeperator = 2;
|
||||
CPBoxOldStyle = 3;
|
||||
CPBoxCustom = 4;
|
||||
|
||||
// CPBorderType
|
||||
CPNoBorder = 0;
|
||||
CPLineBorder = 1;
|
||||
CPLineBorder = 1;
|
||||
CPBezelBorder = 2;
|
||||
CPGrooveBorder = 3;
|
||||
|
||||
@implementation CPBox : CPView
|
||||
{
|
||||
CPBoxType _boxType;
|
||||
CPBorderType _borderType;
|
||||
|
||||
|
||||
CPColor _borderColor;
|
||||
CPColor _fillColor;
|
||||
|
||||
|
||||
float _cornerRadius;
|
||||
float _borderWidth;
|
||||
|
||||
|
||||
CPSize _contentMargin;
|
||||
CPView _contentView;
|
||||
}
|
||||
@@ -50,18 +58,19 @@ CPGrooveBorder = 3;
|
||||
[box setFrameFromContentFrame:[aView frame]];
|
||||
|
||||
[enclosingView replaceSubview:aView with:box];
|
||||
|
||||
|
||||
[box setContentView:aView];
|
||||
|
||||
|
||||
return box;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CPRect)frameRect
|
||||
{
|
||||
self = [super initWithFrame:frameRect];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_borderType = CPBezelBorder;
|
||||
_fillColor = [CPColor clearColor];
|
||||
_borderColor = [CPColor blackColor];
|
||||
|
||||
@@ -69,7 +78,9 @@ CPGrooveBorder = 3;
|
||||
_contentMargin = CGSizeMake(0.0, 0.0);
|
||||
|
||||
_contentView = [[CPView alloc] initWithFrame:[self bounds]];
|
||||
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
|
||||
[self setAutoresizesSubviews:YES];
|
||||
[self addSubview:_contentView];
|
||||
}
|
||||
|
||||
@@ -88,9 +99,26 @@ CPGrooveBorder = 3;
|
||||
return _borderType;
|
||||
}
|
||||
|
||||
- (void)setBorderType:(CPBorderType)value
|
||||
- (void)setBorderType:(CPBorderType)aBorderType
|
||||
{
|
||||
_borderType = value;
|
||||
if (_borderType === aBorderType)
|
||||
return;
|
||||
|
||||
_borderType = aBorderType;
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (CPBoxType)boxType
|
||||
{
|
||||
return _boxType;
|
||||
}
|
||||
|
||||
- (void)setBoxType:(CPBoxType)aBoxType
|
||||
{
|
||||
if (_boxType === aBoxType)
|
||||
return;
|
||||
|
||||
_boxType = aBoxType;
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
@@ -161,9 +189,10 @@ CPGrooveBorder = 3;
|
||||
return;
|
||||
|
||||
[aView setFrame:CGRectInset([self bounds], _contentMargin.width + _borderWidth, _contentMargin.height + _borderWidth)];
|
||||
[aView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
[self replaceSubview:_contentView with:aView];
|
||||
|
||||
_contentView = aView;
|
||||
|
||||
_contentView = aView;
|
||||
}
|
||||
|
||||
- (CPSize)contentViewMargins
|
||||
@@ -173,9 +202,9 @@ CPGrooveBorder = 3;
|
||||
|
||||
- (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"];
|
||||
|
||||
|
||||
_contentMargin = CGSizeMakeCopy(size);
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
@@ -189,56 +218,151 @@ CPGrooveBorder = 3;
|
||||
- (void)sizeToFit
|
||||
{
|
||||
var contentFrame = [_contentView frame];
|
||||
|
||||
[self setFrameSize:CGSizeMake(contentFrame.size.width + _contentMargin.width * 2,
|
||||
|
||||
[self setFrameSize:CGSizeMake(contentFrame.size.width + _contentMargin.width * 2,
|
||||
contentFrame.size.height + _contentMargin.height * 2)];
|
||||
|
||||
|
||||
[_contentView setFrameOrigin:CGPointMake(_contentMargin.width, _contentMargin.height)];
|
||||
}
|
||||
|
||||
- (void)drawRect:(CPRect)rect
|
||||
{
|
||||
var bounds = [self bounds],
|
||||
aContext = [[CPGraphicsContext currentContext] graphicsPort],
|
||||
border2 = _borderWidth/2,
|
||||
if (_borderType === CPNoBorder)
|
||||
return;
|
||||
|
||||
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);
|
||||
var bounds = [self bounds];
|
||||
|
||||
CGContextSetFillColor(aContext, [self fillColor]);
|
||||
CGContextSetStrokeColor(aContext, [self borderColor]);
|
||||
CGContextSetLineWidth(aContext, _borderWidth);
|
||||
|
||||
switch(_borderType)
|
||||
switch (_boxType)
|
||||
{
|
||||
case CPLineBorder: CGContextFillRoundedRectangleInRect(aContext, fillRect, _cornerRadius, YES, YES, YES, YES);
|
||||
CGContextStrokeRoundedRectangleInRect(aContext, strokeRect, _cornerRadius, YES, YES, YES, YES);
|
||||
break;
|
||||
case CPBoxSeperator:
|
||||
// NSBox does not include a horitontal flag for the seperator type. We have to determine
|
||||
// the type of seperator to draw by the width and height of the frame.
|
||||
if (CGRectGetWidth(bounds) === 5.0)
|
||||
return [self _drawVerticalSeperatorInRect:bounds];
|
||||
else if (CGRectGetHeight(bounds) === 5.0)
|
||||
return [self _drawHorizontalSeperatorInRect:bounds];
|
||||
|
||||
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;
|
||||
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
|
||||
|
||||
+104
-45
@@ -20,14 +20,17 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <Foundation/CPIndexSet.j>
|
||||
|
||||
@import "CPControl.j"
|
||||
@import "CPImage.j"
|
||||
@import "CPTableView.j"
|
||||
@import "CPTextField.j"
|
||||
@import "CPScrollView.j"
|
||||
|
||||
/*!
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPBrowser
|
||||
@class CPBrowser
|
||||
*/
|
||||
|
||||
@implementation CPBrowser : CPControl
|
||||
@@ -64,14 +67,14 @@
|
||||
|
||||
+ (CPImage)branchImage
|
||||
{
|
||||
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[self class]]
|
||||
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPBrowser class]]
|
||||
pathForResource:"browser-leaf.png"]
|
||||
size:CGSizeMake(9,9)];
|
||||
}
|
||||
|
||||
+ (CPImage)highlightedBranchImage
|
||||
{
|
||||
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[self class]]
|
||||
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPBrowser class]]
|
||||
pathForResource:"browser-leaf-highlighted.png"]
|
||||
size:CGSizeMake(9,9)];
|
||||
}
|
||||
@@ -96,18 +99,18 @@
|
||||
|
||||
_prototypeView = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
|
||||
[_prototypeView setVerticalAlignment:CPCenterVerticalTextAlignment];
|
||||
[_prototypeView setValue:[CPColor whiteColor] forThemeAttribute:"text-color" inState:CPThemeStateSelected];
|
||||
[_prototypeView setValue:[CPColor whiteColor] forThemeAttribute:"text-color" inState:CPThemeStateSelectedDataView];
|
||||
[_prototypeView setLineBreakMode:CPLineBreakByTruncatingTail];
|
||||
|
||||
_horizontalScrollView = [[CPScrollView alloc] initWithFrame:[self bounds]];
|
||||
|
||||
[_horizontalScrollView setHasVerticalScroller:NO];
|
||||
[_horizontalScrollView setAutohidesScrollers:YES];
|
||||
[_horizontalScrollView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
|
||||
|
||||
[_horizontalScrollView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
|
||||
_contentView = [[CPView alloc] initWithFrame:CGRectMake(0, 0, 0, CGRectGetHeight([self bounds]))];
|
||||
[_contentView setAutoresizingMask:CPViewHeightSizable];
|
||||
|
||||
|
||||
[_horizontalScrollView setDocumentView:_contentView];
|
||||
|
||||
[self addSubview:_horizontalScrollView];
|
||||
@@ -129,7 +132,7 @@
|
||||
}
|
||||
|
||||
- (void)setDelegate:(id)anObject
|
||||
{
|
||||
{
|
||||
_delegate = anObject;
|
||||
_delegateSupportsImages = [_delegate respondsToSelector:@selector(browser:imageValueForItem:)];
|
||||
|
||||
@@ -167,12 +170,10 @@
|
||||
if (columnIndex >= _tableViews.length)
|
||||
return;
|
||||
|
||||
var oldValue = _tableViews.length - 1;
|
||||
var oldValue = _tableViews.length - 1,
|
||||
indexPlusOne = columnIndex + 1; // unloads all later columns.
|
||||
|
||||
// unloads all later columns.
|
||||
var indexPlusOne = columnIndex + 1;
|
||||
|
||||
[[_tableViews.slice(indexPlusOne) valueForKey:"enclosingScrollView"]
|
||||
[[_tableViews.slice(indexPlusOne) valueForKey:"enclosingScrollView"]
|
||||
makeObjectsPerformSelector:@selector(removeFromSuperview)];
|
||||
|
||||
_tableViews = _tableViews.slice(0, indexPlusOne);
|
||||
@@ -196,10 +197,10 @@
|
||||
selectionIndexes = [lastColumn selectedRowIndexes];
|
||||
|
||||
if (lastIndex >= 0 && [selectionIndexes count] > 1)
|
||||
[CPException raise:CPInvalidArgumentException
|
||||
[CPException raise:CPInvalidArgumentException
|
||||
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]];
|
||||
|
||||
if (index > 0 && item && [self isLeafItem:item])
|
||||
@@ -213,8 +214,6 @@
|
||||
[table setAllowsEmptySelection:_allowsEmptySelection];
|
||||
[table registerForDraggedTypes:[self registeredDraggedTypes]];
|
||||
|
||||
[self setNextResponder:table];
|
||||
|
||||
[self _addTableColumnsToTableView:table forColumnIndex:index];
|
||||
|
||||
var delegate = [[_CPBrowserTableDelegate alloc] init];
|
||||
@@ -233,7 +232,7 @@
|
||||
[table setAction:@selector(_tableViewClicked:)];
|
||||
[table setDoubleAction:@selector(_tableViewDoubleClicked:)];
|
||||
[table setDraggingDestinationFeedbackStyle:CPTableViewDraggingDestinationFeedbackStyleRegular];
|
||||
|
||||
|
||||
var scrollView = [[_CPBrowserScrollView alloc] initWithFrame:CGRectMakeZero()];
|
||||
[scrollView _setBrowser:self];
|
||||
[scrollView setDocumentView:table];
|
||||
@@ -274,10 +273,10 @@
|
||||
|
||||
[view setBranchImage:[[self class] branchImage]];
|
||||
[view setHighlightedBranchImage:[[self class] highlightedBranchImage]];
|
||||
|
||||
|
||||
[column setDataView:view];
|
||||
[column setResizingMask:CPTableColumnNoResizing];
|
||||
|
||||
|
||||
[aTableView addTableColumn:column];
|
||||
}
|
||||
|
||||
@@ -314,6 +313,39 @@
|
||||
[_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
|
||||
|
||||
- (id)itemAtRow:(int)row inColumn:(int)column
|
||||
@@ -357,6 +389,10 @@
|
||||
|
||||
// CLICK EVENTS
|
||||
|
||||
- (void)trackMouse:(CPEvent)anEvent
|
||||
{
|
||||
}
|
||||
|
||||
- (void)_column:(unsigned)columnIndex clickedRow:(unsigned)rowIndex
|
||||
{
|
||||
[self setLastColumn:columnIndex];
|
||||
@@ -382,6 +418,15 @@
|
||||
[self sendAction:_doubleAction to:_target];
|
||||
}
|
||||
|
||||
- (void)keyDown:(CPEvent)anEvent
|
||||
{
|
||||
var column = [self selectedColumn];
|
||||
if (column === -1)
|
||||
return;
|
||||
|
||||
[_tableViews[column] keyDown:anEvent];
|
||||
}
|
||||
|
||||
// SIZING
|
||||
|
||||
- (float)columnContentWidthForColumnWidth:(float)aWidth
|
||||
@@ -453,7 +498,7 @@
|
||||
[_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 tableViewInColumn:columnIndex] scrollRowToVisible:rowIndex];
|
||||
@@ -526,6 +571,9 @@
|
||||
|
||||
- (CPIndexSet)selectedRowIndexesInColumn:(unsigned)column
|
||||
{
|
||||
if (column < 0 || column > [self lastColumn] +1)
|
||||
return [CPIndexSet indexSet];
|
||||
|
||||
return [[self tableViewInColumn:column] selectedRowIndexes];
|
||||
}
|
||||
|
||||
@@ -537,7 +585,7 @@
|
||||
if ([_delegate respondsToSelector:@selector(browser:selectionIndexesForProposedSelection:inColumn:)])
|
||||
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])
|
||||
return;
|
||||
|
||||
@@ -551,8 +599,6 @@
|
||||
|
||||
[[self tableViewInColumn:column] selectRowIndexes:indexSet byExtendingSelection:NO];
|
||||
|
||||
[self setNextResponder:[self tableViewInColumn:[self lastColumn]]];
|
||||
|
||||
[self scrollColumnToVisible:column];
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(browserSelectionDidChange:)])
|
||||
@@ -604,6 +650,8 @@
|
||||
|
||||
@end
|
||||
|
||||
var _CPBrowserResizeControlBackgroundImage = nil;
|
||||
|
||||
@implementation _CPBrowserResizeControl : CPView
|
||||
{
|
||||
CGPoint _mouseDownX;
|
||||
@@ -612,6 +660,26 @@
|
||||
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
|
||||
{
|
||||
_mouseDownX = [anEvent locationInWindow].x;
|
||||
@@ -626,9 +694,11 @@
|
||||
[_browser setWidth:_width + deltaX ofColumn:_index];
|
||||
}
|
||||
|
||||
@end
|
||||
- (void)mouseUp:(CPEvent)anEvent
|
||||
{
|
||||
}
|
||||
|
||||
var _CPBrowserResizeControlBackgroundImage = nil;
|
||||
@end
|
||||
|
||||
@implementation _CPBrowserScrollView : CPScrollView
|
||||
{
|
||||
@@ -636,24 +706,11 @@ var _CPBrowserResizeControlBackgroundImage = nil;
|
||||
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
|
||||
{
|
||||
if (self = [super initWithFrame:aFrame])
|
||||
{
|
||||
_resizeControl = [[_CPBrowserResizeControl alloc] initWithFrame:CGRectMakeZero()];
|
||||
[_resizeControl setBackgroundColor:[CPColor colorWithPatternImage:[[self class] backgroundImage]]];
|
||||
[self addSubview:_resizeControl];
|
||||
}
|
||||
|
||||
@@ -740,7 +797,7 @@ var _CPBrowserResizeControlBackgroundImage = nil;
|
||||
}
|
||||
|
||||
- (void)moveLeft:(id)sender
|
||||
{
|
||||
{
|
||||
var previousColumn = [_browser selectedColumn] - 1,
|
||||
selectedRow = [_browser selectedRowInColumn:previousColumn];
|
||||
|
||||
@@ -748,12 +805,14 @@ var _CPBrowserResizeControlBackgroundImage = nil;
|
||||
}
|
||||
|
||||
- (void)moveRight:(id)sender
|
||||
{
|
||||
{
|
||||
[_browser selectRow:0 inColumn:[_browser selectedColumn] + 1];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
@implementation _CPBrowserTableDelegate : CPObject
|
||||
{
|
||||
CPBrowser _browser @accessors;
|
||||
@@ -804,7 +863,7 @@ var _CPBrowserResizeControlBackgroundImage = nil;
|
||||
- (CPDragOperation)tableView:(CPTableView)aTableView validateDrop:(id)info proposedRow:(int)row proposedDropOperation:(CPTableViewDropOperation)operation
|
||||
{
|
||||
if ([_delegate respondsToSelector:@selector(browser:validateDrop:proposedRow:column:dropOperation:)])
|
||||
[_delegate browser:_browser validateDrop:info proposedRow:row column:_index dropOperation:operation];
|
||||
return [_delegate browser:_browser validateDrop:info proposedRow:row column:_index dropOperation:operation];
|
||||
else
|
||||
return CPDragOperationNone;
|
||||
}
|
||||
@@ -865,9 +924,9 @@ var _CPBrowserResizeControlBackgroundImage = nil;
|
||||
{
|
||||
var imageView = [self layoutEphemeralSubviewNamed:@"image-view"
|
||||
positioned:CPWindowAbove
|
||||
relativeToEphemeralSubviewNamed:nil];
|
||||
relativeToEphemeralSubviewNamed:nil],
|
||||
isHighlighted = [self themeState] & CPThemeStateSelectedDataView;
|
||||
|
||||
var isHighlighted = [self themeState] & CPThemeStateSelected;
|
||||
[imageView setImage: _isLeaf ? (isHighlighted ? _highlightedBranchImage : _branchImage) : nil];
|
||||
[imageView setImageScaling:CPScaleNone];
|
||||
}
|
||||
|
||||
+174
-69
@@ -26,8 +26,6 @@
|
||||
@import "CPControl.j"
|
||||
@import "CPStringDrawing.j"
|
||||
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
|
||||
|
||||
/* @group CPBezelStyle */
|
||||
|
||||
@@ -74,7 +72,10 @@ CPChangeBackgroundCellMask = CPBackgroundButtonMask;
|
||||
|
||||
CPButtonStateMixed = CPThemeState("mixed");
|
||||
|
||||
/*!
|
||||
CPButtonDefaultHeight = 24.0;
|
||||
CPButtonImageOffset = 3.0;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPButton
|
||||
|
||||
@@ -85,12 +86,9 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
@implementation CPButton : CPControl
|
||||
{
|
||||
BOOL _allowsMixedState;
|
||||
|
||||
|
||||
CPString _title;
|
||||
CPString _alternateTitle;
|
||||
|
||||
CPImage _image;
|
||||
CPImage _alternateImage;
|
||||
|
||||
CPInteger _showsStateBy;
|
||||
CPInteger _highlightsBy;
|
||||
@@ -99,6 +97,9 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
// NS-style Display Properties
|
||||
CPBezelStyle _bezelStyle;
|
||||
CPControlSize _controlSize;
|
||||
|
||||
CPString _keyEquivalent;
|
||||
unsigned _keyEquivalentModifierMask;
|
||||
}
|
||||
|
||||
+ (id)buttonWithTitle:(CPString)aTitle
|
||||
@@ -117,21 +118,21 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
return button;
|
||||
}
|
||||
|
||||
+ (CPString)themeClass
|
||||
+ (CPString)defaultThemeClass
|
||||
{
|
||||
return @"button";
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[_CGInsetMakeZero(), _CGInsetMakeZero(), [CPNull null]]
|
||||
forKeys:[@"bezel-inset", @"content-inset", @"bezel-color"]];
|
||||
return [CPDictionary dictionaryWithObjects:[[CPNull null], 0.0, _CGInsetMakeZero(), _CGInsetMakeZero(), [CPNull null]]
|
||||
forKeys:[@"image", @"image-offset", @"bezel-inset", @"content-inset", @"bezel-color"]];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
// Should we instead override the defaults?
|
||||
@@ -139,13 +140,16 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
[self setValue:CPCenterVerticalTextAlignment forThemeAttribute:@"vertical-alignment"];
|
||||
[self setValue:CPImageLeft forThemeAttribute:@"image-position"];
|
||||
[self setValue:CPScaleNone forThemeAttribute:@"image-scaling"];
|
||||
|
||||
|
||||
_controlSize = CPRegularControlSize;
|
||||
|
||||
|
||||
_keyEquivalent = @"";
|
||||
_keyEquivalentModifierMask = 0;
|
||||
|
||||
// [self setBezelStyle:CPRoundRectBezelStyle];
|
||||
[self setBordered:YES];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -248,9 +252,9 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
{
|
||||
if (_title === aTitle)
|
||||
return;
|
||||
|
||||
|
||||
_title = aTitle;
|
||||
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
@@ -264,7 +268,7 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
{
|
||||
if (_alternateTitle === aTitle)
|
||||
return;
|
||||
|
||||
|
||||
_alternateTitle = aTitle;
|
||||
|
||||
[self setNeedsLayout];
|
||||
@@ -278,18 +282,12 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
|
||||
- (void)setImage:(CPImage)anImage
|
||||
{
|
||||
if (_image === anImage)
|
||||
return;
|
||||
|
||||
_image = anImage;
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
[self setValue:anImage forThemeAttribute:@"image"];
|
||||
}
|
||||
|
||||
- (CPImage)image
|
||||
{
|
||||
return _image;
|
||||
return [self valueForThemeAttribute:@"image" inState:CPThemeStateNormal];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -298,13 +296,7 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
*/
|
||||
- (void)setAlternateImage:(CPImage)anImage
|
||||
{
|
||||
if (_alternateImage === anImage)
|
||||
return;
|
||||
|
||||
_alternateImage = anImage;
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
[self setValue:anImage forThemeAttribute:@"image" inState:CPThemeStateHighlighted];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -312,7 +304,17 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
*/
|
||||
- (CPImage)alternateImage
|
||||
{
|
||||
return _alternateImage;
|
||||
return [self valueForThemeAttribute:@"image" inState:CPThemeStateHighlighted];
|
||||
}
|
||||
|
||||
- (void)setImageOffset:(float)theImageOffset
|
||||
{
|
||||
[self setValue:theImageOffset forThemeAttribute:@"image-offset"];
|
||||
}
|
||||
|
||||
- (float)imageOffset
|
||||
{
|
||||
return [self valueForThemeAttribute:@"image-offset"];
|
||||
}
|
||||
|
||||
- (void)setShowsStateBy:(CPInteger)aMask
|
||||
@@ -373,13 +375,13 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
[self setShowsStateBy:CPContentsCellMask];
|
||||
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."];
|
||||
|
||||
case CPRadioButton: [CPException raise:CPInvalidArgumentException
|
||||
case CPRadioButton: [CPException raise:CPInvalidArgumentException
|
||||
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."];
|
||||
}
|
||||
|
||||
@@ -395,7 +397,7 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
|
||||
_imageDimsWhenDisabled = imageShouldDimWhenDisabled;
|
||||
|
||||
if (_imageDimsWhenDisabled)
|
||||
if ([self hasThemeState:CPThemeStateDisabled])
|
||||
{
|
||||
[self setNeedsDisplay:YES];
|
||||
[self setNeedsLayout];
|
||||
@@ -410,7 +412,7 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
- (BOOL)startTrackingAt:(CGPoint)aPoint
|
||||
{
|
||||
[self highlight:YES];
|
||||
|
||||
|
||||
return [super startTrackingAt:aPoint];
|
||||
}
|
||||
|
||||
@@ -431,11 +433,12 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
if (_CGInsetIsEmpty(contentInset))
|
||||
return bounds;
|
||||
|
||||
bounds = _CGRectMakeCopy(bounds);
|
||||
bounds.origin.x += contentInset.left;
|
||||
bounds.origin.y += contentInset.top;
|
||||
bounds.size.width -= contentInset.left + contentInset.right;
|
||||
bounds.size.height -= contentInset.top + contentInset.bottom;
|
||||
|
||||
|
||||
return bounds;
|
||||
}
|
||||
|
||||
@@ -449,6 +452,7 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
if (_CGInsetIsEmpty(bezelInset))
|
||||
return bounds;
|
||||
|
||||
bounds = _CGRectMakeCopy(bounds);
|
||||
bounds.origin.x += bezelInset.left;
|
||||
bounds.origin.y += bezelInset.top;
|
||||
bounds.size.width -= bezelInset.left + bezelInset.right;
|
||||
@@ -462,8 +466,20 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
*/
|
||||
- (void)sizeToFit
|
||||
{
|
||||
var size = [([self title] || " ") sizeWithFont:[self currentValueForThemeAttribute:@"font"]],
|
||||
contentInset = [self currentValueForThemeAttribute:@"content-inset"],
|
||||
[self layoutSubviews];
|
||||
|
||||
var size,
|
||||
contentView = [self ephemeralSubviewNamed:@"content-view"];
|
||||
|
||||
if (contentView)
|
||||
{
|
||||
[contentView sizeToFit];
|
||||
size = [contentView frameSize];
|
||||
}
|
||||
else
|
||||
size = [([self title] || " ") sizeWithFont:[self currentValueForThemeAttribute:@"font"]];
|
||||
|
||||
var contentInset = [self currentValueForThemeAttribute:@"content-inset"],
|
||||
minSize = [self currentValueForThemeAttribute:@"min-size"],
|
||||
maxSize = [self currentValueForThemeAttribute:@"max-size"];
|
||||
|
||||
@@ -483,10 +499,10 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
{
|
||||
if (aName === "bezel-view")
|
||||
return [self bezelRectForBounds:[self bounds]];
|
||||
|
||||
|
||||
else if (aName === "content-view")
|
||||
return [self contentRectForBounds:[self bounds]];
|
||||
|
||||
|
||||
return [super rectForEphemeralSubviewNamed:aName];
|
||||
}
|
||||
|
||||
@@ -497,7 +513,7 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
|
||||
[view setHitTests:NO];
|
||||
|
||||
|
||||
return view;
|
||||
}
|
||||
else
|
||||
@@ -519,7 +535,8 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
if (contentView)
|
||||
{
|
||||
[contentView setText:([self hasThemeState:CPThemeStateHighlighted] && _alternateTitle) ? _alternateTitle : _title];
|
||||
[contentView setImage:([self hasThemeState:CPThemeStateHighlighted] && _alternateImage) ? _alternateImage : _image];
|
||||
[contentView setImage:[self currentValueForThemeAttribute:@"image"]];
|
||||
[contentView setImageOffset:[self currentValueForThemeAttribute:@"image-offset"]];
|
||||
|
||||
[contentView setFont:[self currentValueForThemeAttribute:@"font"]];
|
||||
[contentView setTextColor:[self currentValueForThemeAttribute:@"text-color"]];
|
||||
@@ -530,17 +547,10 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
[contentView setTextShadowOffset:[self currentValueForThemeAttribute:@"text-shadow-offset"]];
|
||||
[contentView setImagePosition:[self currentValueForThemeAttribute:@"image-position"]];
|
||||
[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
|
||||
{
|
||||
if (shouldBeBordered)
|
||||
@@ -554,6 +564,79 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
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
|
||||
|
||||
@implementation CPButton (NS)
|
||||
@@ -569,11 +652,16 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
@end
|
||||
|
||||
|
||||
var CPButtonImageKey = @"CPButtonImageKey",
|
||||
CPButtonAlternateImageKey = @"CPButtonAlternateImageKey",
|
||||
CPButtonTitleKey = @"CPButtonTitleKey",
|
||||
CPButtonAlternateTitleKey = @"CPButtonAlternateTitleKey",
|
||||
CPButtonIsBorderedKey = @"CPButtonIsBorderedKey";
|
||||
var CPButtonImageKey = @"CPButtonImageKey",
|
||||
CPButtonAlternateImageKey = @"CPButtonAlternateImageKey",
|
||||
CPButtonTitleKey = @"CPButtonTitleKey",
|
||||
CPButtonAlternateTitleKey = @"CPButtonAlternateTitleKey",
|
||||
CPButtonIsBorderedKey = @"CPButtonIsBorderedKey",
|
||||
CPButtonAllowsMixedStateKey = @"CPButtonAllowsMixedStateKey",
|
||||
CPButtonImageDimsWhenDisabledKey = @"CPButtonImageDimsWhenDisabledKey",
|
||||
CPButtonImagePositionKey = @"CPButtonImagePositionKey",
|
||||
CPButtonKeyEquivalentKey = @"CPButtonKeyEquivalentKey",
|
||||
CPButtonKeyEquivalentMaskKey = @"CPButtonKeyEquivalentMaskKey";
|
||||
|
||||
@implementation CPButton (CPCoding)
|
||||
|
||||
@@ -584,21 +672,31 @@ var CPButtonImageKey = @"CPButtonImageKey",
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_controlSize = CPRegularControlSize;
|
||||
|
||||
[self setImage:[aCoder decodeObjectForKey:CPButtonImageKey]];
|
||||
[self setAlternateImage:[aCoder decodeObjectForKey:CPButtonAlternateImageKey]];
|
||||
|
||||
[self setTitle:[aCoder decodeObjectForKey:CPButtonTitleKey]];
|
||||
[self setAlternateTitle:[aCoder decodeObjectForKey:CPButtonAlternateTitleKey]];
|
||||
|
||||
_title = [aCoder decodeObjectForKey:CPButtonTitleKey];
|
||||
_alternateTitle = [aCoder decodeObjectForKey:CPButtonAlternateTitleKey];
|
||||
|
||||
if ([aCoder containsValueForKey:CPButtonAllowsMixedStateKey])
|
||||
_allowsMixedState = [aCoder decodeBoolForKey:CPButtonAllowsMixedStateKey];
|
||||
|
||||
[self setImageDimsWhenDisabled:[aCoder decodeObjectForKey:CPButtonImageDimsWhenDisabledKey]];
|
||||
|
||||
if ([aCoder containsValueForKey:CPButtonImagePositionKey])
|
||||
[self setImagePosition:[aCoder decodeIntForKey:CPButtonImagePositionKey]];
|
||||
|
||||
if ([aCoder containsValueForKey:CPButtonKeyEquivalentKey])
|
||||
[self setKeyEquivalent:CFData.decodeBase64ToUtf16String([aCoder decodeObjectForKey:CPButtonKeyEquivalentKey])];
|
||||
|
||||
_keyEquivalentModifierMask = [aCoder decodeIntForKey:CPButtonKeyEquivalentMaskKey];
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -610,11 +708,18 @@ var CPButtonImageKey = @"CPButtonImageKey",
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[aCoder encodeObject:_image forKey:CPButtonImageKey];
|
||||
[aCoder encodeObject:_alternateImage forKey:CPButtonAlternateImageKey];
|
||||
|
||||
[aCoder encodeObject:_title forKey:CPButtonTitleKey];
|
||||
[aCoder encodeObject:_alternateTitle forKey:CPButtonAlternateTitleKey];
|
||||
|
||||
[aCoder 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
|
||||
|
||||
+57
-29
@@ -1,7 +1,5 @@
|
||||
|
||||
@import <AppKit/CPView.j>
|
||||
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
@import "CPView.j"
|
||||
|
||||
|
||||
@implementation CPButtonBar : CPView
|
||||
@@ -14,8 +12,9 @@
|
||||
+ (id)plusButton
|
||||
{
|
||||
var button = [[CPButton alloc] initWithFrame:CGRectMake(0, 0, 35, 25)],
|
||||
image = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:self] pathForResource:@"plus_button.png"] size:CGSizeMake(11, 12)];
|
||||
image = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPButtonBar class]] pathForResource:@"plus_button.png"] size:CGSizeMake(11, 12)];
|
||||
|
||||
[button setBordered:NO];
|
||||
[button setImage:image];
|
||||
[button setImagePosition:CPImageOnly];
|
||||
|
||||
@@ -25,23 +24,39 @@
|
||||
+ (id)minusButton
|
||||
{
|
||||
var button = [[CPButton alloc] initWithFrame:CGRectMake(0, 0, 35, 25)],
|
||||
image = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:self] pathForResource:@"minus_button.png"] size:CGSizeMake(11, 4)];
|
||||
image = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPButtonBar class]] pathForResource:@"minus_button.png"] size:CGSizeMake(11, 4)];
|
||||
|
||||
[button setBordered:NO];
|
||||
[button setImage:image];
|
||||
[button setImagePosition:CPImageOnly];
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
+ (CPString)themeClass
|
||||
+ (id)actionPopupButton
|
||||
{
|
||||
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";
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
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"]];
|
||||
return [CPDictionary dictionaryWithObjects:[CGInsetMake(0.0, 0.0, 0.0, 0.0), CGSizeMakeZero(), [CPNull null], [CPNull null], [CPNull null], [CPNull null]]
|
||||
forKeys:[@"resize-control-inset", @"resize-control-size", @"resize-control-color", @"bezel-color", @"button-bezel-color", @"button-text-color"]];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
@@ -82,25 +97,8 @@
|
||||
_buttons = [CPArray arrayWithArray:buttons];
|
||||
|
||||
for (var i = 0, count = [_buttons count]; i < count; i++)
|
||||
{
|
||||
var button = _buttons[i];
|
||||
[_buttons[i] setBordered:YES];
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
@@ -176,6 +174,11 @@
|
||||
{
|
||||
[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],
|
||||
count = [buttonsNotHidden count];
|
||||
|
||||
@@ -184,13 +187,23 @@
|
||||
[buttonsNotHidden removeObject:buttonsNotHidden[count]];
|
||||
|
||||
var currentButtonOffset = _resizeControlIsLeftAligned ? CGRectGetMaxX([self bounds]) + 1 : -1,
|
||||
height = CGRectGetHeight([self bounds]) - 1;
|
||||
bounds = [self bounds],
|
||||
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++)
|
||||
{
|
||||
{
|
||||
var button = buttonsNotHidden[i],
|
||||
width = CGRectGetWidth([button frame]);
|
||||
|
||||
if (availableWidth > width)
|
||||
availableWidth -= width;
|
||||
else
|
||||
break;
|
||||
|
||||
if (_resizeControlIsLeftAligned)
|
||||
{
|
||||
[button setFrame:CGRectMake(currentButtonOffset - width, 1, width, height)];
|
||||
@@ -202,6 +215,16 @@
|
||||
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];
|
||||
}
|
||||
|
||||
@@ -216,6 +239,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setFrameSize:(CGSize)aSize
|
||||
{
|
||||
[super setFrameSize:aSize];
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPButtonBarHasResizeControlKey = @"CPButtonBarHasResizeControlKey",
|
||||
@@ -246,4 +275,3 @@ var CPButtonBarHasResizeControlKey = @"CPButtonBarHasResizeControlKey",
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
+27
-2
@@ -23,6 +23,8 @@
|
||||
@import "CPButton.j"
|
||||
|
||||
|
||||
CPCheckBoxImageOffset = 4.0;
|
||||
|
||||
@implementation CPCheckBox : CPButton
|
||||
{
|
||||
}
|
||||
@@ -37,7 +39,7 @@
|
||||
return [self buttonWithTitle:aTitle];
|
||||
}
|
||||
|
||||
+ (CPString)themeClass
|
||||
+ (CPString)defaultThemeClass
|
||||
{
|
||||
return @"check-box";
|
||||
}
|
||||
@@ -55,10 +57,33 @@
|
||||
[self setImagePosition:CPImageLeft];
|
||||
[self setAlignment:CPLeftTextAlignment];
|
||||
|
||||
[self setBordered:YES];
|
||||
[self setBordered:NO];
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
+51
-31
@@ -22,14 +22,12 @@
|
||||
|
||||
@import "CPView.j"
|
||||
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
|
||||
|
||||
/*!
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@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.
|
||||
*/
|
||||
@implementation CPClipView : CPView
|
||||
@@ -47,7 +45,7 @@
|
||||
return;
|
||||
|
||||
var defaultCenter = [CPNotificationCenter defaultCenter];
|
||||
|
||||
|
||||
if (_documentView)
|
||||
{
|
||||
[defaultCenter
|
||||
@@ -59,29 +57,29 @@
|
||||
removeObserver:self
|
||||
name:CPViewBoundsDidChangeNotification
|
||||
object:_documentView];
|
||||
|
||||
|
||||
[_documentView removeFromSuperview];
|
||||
}
|
||||
|
||||
|
||||
_documentView = aView;
|
||||
|
||||
|
||||
if (_documentView)
|
||||
{
|
||||
[self addSubview:_documentView];
|
||||
|
||||
[_documentView setPostsFrameChangedNotifications:YES];
|
||||
[_documentView setPostsBoundsChangedNotifications:YES];
|
||||
|
||||
[defaultCenter
|
||||
[_documentView setPostsFrameChangedNotifications:YES];
|
||||
[_documentView setPostsBoundsChangedNotifications:YES];
|
||||
|
||||
[defaultCenter
|
||||
addObserver:self
|
||||
selector:@selector(viewFrameChanged:)
|
||||
name:CPViewFrameDidChangeNotification
|
||||
name:CPViewFrameDidChangeNotification
|
||||
object:_documentView];
|
||||
|
||||
[defaultCenter
|
||||
[defaultCenter
|
||||
addObserver:self
|
||||
selector:@selector(viewBoundsChanged:)
|
||||
name:CPViewBoundsDidChangeNotification
|
||||
name:CPViewBoundsDidChangeNotification
|
||||
object:_documentView];
|
||||
}
|
||||
}
|
||||
@@ -106,7 +104,7 @@
|
||||
return _CGPointMakeZero();
|
||||
|
||||
var documentFrame = [_documentView frame];
|
||||
|
||||
|
||||
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)));
|
||||
|
||||
@@ -117,7 +115,7 @@
|
||||
{
|
||||
if (_CGPointEqualToPoint(_bounds.origin, aPoint))
|
||||
return;
|
||||
|
||||
|
||||
[super setBoundsOrigin:aPoint];
|
||||
|
||||
var superview = [self superview],
|
||||
@@ -126,7 +124,7 @@
|
||||
// FIXME: Should CPScrollView be finding out about this on its own somehow?
|
||||
scrollViewClass = objj_getClass("CPScrollView");
|
||||
|
||||
if([superview isKindOfClass:scrollViewClass])
|
||||
if ([superview isKindOfClass:scrollViewClass])
|
||||
[superview reflectScrolledClipView:self];
|
||||
}
|
||||
|
||||
@@ -166,12 +164,12 @@
|
||||
- (void)_constrainScrollPoint
|
||||
{
|
||||
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.
|
||||
[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).
|
||||
if (!CGPointEqualToPoint(oldScrollPoint, [self bounds].origin))
|
||||
return;
|
||||
@@ -187,20 +185,42 @@
|
||||
[superview reflectScrolledClipView:self];
|
||||
}
|
||||
|
||||
- (BOOL)autoscroll:(CPEvent)anEvent
|
||||
- (BOOL)autoscroll:(CPEvent)anEvent
|
||||
{
|
||||
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 (CPRectContainsPoint(bounds, eventLocation))
|
||||
if (CGRectContainsPoint(bounds, eventLocation))
|
||||
return NO;
|
||||
|
||||
var newRect = CGRectMakeZero();
|
||||
if (![superview isKindOfClass:[CPScrollView class]] || [superview hasVerticalScroller])
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
newRect.origin = eventLocation;
|
||||
newRect.size = CPSizeMake(10, 10);
|
||||
if (![superview isKindOfClass:[CPScrollView class]] || [superview hasHorizontalScroller])
|
||||
{
|
||||
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 [_documentView scrollRectToVisible:newRect];
|
||||
return [self scrollToPoint:CGPointMake(bounds.origin.x - deltaX, bounds.origin.y - deltaY)];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -214,14 +234,14 @@ var CPClipViewDocumentViewKey = @"CPScrollViewDocumentView";
|
||||
{
|
||||
if (self = [super initWithCoder:aCoder])
|
||||
[self setDocumentView:[aCoder decodeObjectForKey:CPClipViewDocumentViewKey]];
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
|
||||
[aCoder encodeObject:_documentView forKey:CPClipViewDocumentViewKey];
|
||||
}
|
||||
|
||||
|
||||
+196
-100
@@ -30,16 +30,16 @@
|
||||
@import "CPCollectionViewItem.j"
|
||||
|
||||
|
||||
/*!
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPCollectionView
|
||||
|
||||
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
|
||||
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
|
||||
setting that item as the collection view prototype.
|
||||
|
||||
|
||||
@par Delegate Methods
|
||||
|
||||
|
||||
@delegate -(void)collectionViewDidChangeSelection:(CPCollectionView)collectionView;
|
||||
Called when the selection in the collection view has changed.
|
||||
@param collectionView the collection view who's selection changed
|
||||
@@ -67,35 +67,35 @@
|
||||
{
|
||||
CPArray _content;
|
||||
CPArray _items;
|
||||
|
||||
|
||||
CPData _itemData;
|
||||
CPCollectionViewItem _itemPrototype;
|
||||
CPCollectionViewItem _itemForDragging;
|
||||
CPMutableArray _cachedItems;
|
||||
|
||||
|
||||
unsigned _maxNumberOfRows;
|
||||
unsigned _maxNumberOfColumns;
|
||||
|
||||
|
||||
CGSize _minItemSize;
|
||||
CGSize _maxItemSize;
|
||||
|
||||
CPArray _backgroundColors;
|
||||
|
||||
float _tileWidth;
|
||||
|
||||
|
||||
BOOL _isSelectable;
|
||||
BOOL _allowsMultipleSelection;
|
||||
BOOL _allowsEmptySelection;
|
||||
CPIndexSet _selectionIndexes;
|
||||
|
||||
|
||||
CGSize _itemSize;
|
||||
|
||||
|
||||
float _horizontalMargin;
|
||||
float _verticalMargin;
|
||||
|
||||
|
||||
unsigned _numberOfRows;
|
||||
unsigned _numberOfColumns;
|
||||
|
||||
|
||||
id _delegate;
|
||||
|
||||
CPEvent _mouseDownEvent;
|
||||
@@ -104,14 +104,14 @@
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_items = [];
|
||||
_content = [];
|
||||
|
||||
|
||||
_cachedItems = [];
|
||||
|
||||
|
||||
_itemSize = CGSizeMakeZero();
|
||||
_minItemSize = CGSizeMakeZero();
|
||||
_maxItemSize = CGSizeMakeZero();
|
||||
@@ -120,12 +120,12 @@
|
||||
|
||||
_verticalMargin = 5.0;
|
||||
_tileWidth = -1.0;
|
||||
|
||||
|
||||
_selectionIndexes = [CPIndexSet indexSet];
|
||||
_allowsEmptySelection = YES;
|
||||
_isSelectable = YES;
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -196,8 +196,8 @@
|
||||
|
||||
// Setting the Content
|
||||
/*!
|
||||
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.
|
||||
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.
|
||||
It's the responsibility of your custom collection view item to interpret the object.
|
||||
@param anArray the content array
|
||||
*/
|
||||
@@ -205,9 +205,9 @@
|
||||
{
|
||||
if (_content == anArray)
|
||||
return;
|
||||
|
||||
|
||||
_content = anArray;
|
||||
|
||||
|
||||
[self reloadContent];
|
||||
}
|
||||
|
||||
@@ -236,13 +236,13 @@
|
||||
{
|
||||
if (_isSelectable == isSelectable)
|
||||
return;
|
||||
|
||||
|
||||
_isSelectable = isSelectable;
|
||||
|
||||
|
||||
if (!_isSelectable)
|
||||
{
|
||||
var index = CPNotFound;
|
||||
|
||||
|
||||
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound)
|
||||
[_items[index] setSelected:NO];
|
||||
}
|
||||
@@ -297,23 +297,25 @@
|
||||
*/
|
||||
- (void)setSelectionIndexes:(CPIndexSet)anIndexSet
|
||||
{
|
||||
if (_selectionIndexes == anIndexSet || !_isSelectable)
|
||||
if ([_selectionIndexes isEqual:anIndexSet] || !_isSelectable)
|
||||
return;
|
||||
|
||||
|
||||
var index = CPNotFound;
|
||||
|
||||
|
||||
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound)
|
||||
[_items[index] setSelected:NO];
|
||||
|
||||
|
||||
_selectionIndexes = anIndexSet;
|
||||
|
||||
|
||||
var index = CPNotFound;
|
||||
|
||||
|
||||
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound)
|
||||
[_items[index] setSelected:YES];
|
||||
|
||||
|
||||
[[CPKeyValueBinding getBinding:@"selectionIndexes" forObject:self] reverseSetValueFor:@"selectionIndexes"];
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(collectionViewDidChangeSelection:)])
|
||||
[_delegate collectionViewDidChangeSelection:self]
|
||||
[_delegate collectionViewDidChangeSelection:self];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -326,10 +328,10 @@
|
||||
|
||||
/* @ignore */
|
||||
- (void)reloadContent
|
||||
{
|
||||
{
|
||||
// Remove current views
|
||||
var count = _items.length;
|
||||
|
||||
|
||||
while (count--)
|
||||
{
|
||||
[[_items[count] view] removeFromSuperview];
|
||||
@@ -337,7 +339,7 @@
|
||||
|
||||
_cachedItems.push(_items[count]);
|
||||
}
|
||||
|
||||
|
||||
_items = [];
|
||||
|
||||
if (!_itemPrototype || !_content)
|
||||
@@ -350,7 +352,7 @@
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
_items.push([self newItemForRepresentedObject:_content[index]]);
|
||||
|
||||
|
||||
[self addSubview:[_items[index] view]];
|
||||
}
|
||||
|
||||
@@ -365,49 +367,49 @@
|
||||
- (void)tile
|
||||
{
|
||||
var width = CGRectGetWidth([self bounds]);
|
||||
|
||||
|
||||
if (![_content count] || width == _tileWidth)
|
||||
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
|
||||
// margin
|
||||
var itemSize = CGSizeMakeCopy(_minItemSize);
|
||||
|
||||
|
||||
_numberOfColumns = MAX(1.0, FLOOR(width / itemSize.width));
|
||||
|
||||
|
||||
if (_maxNumberOfColumns > 0)
|
||||
_numberOfColumns = MIN(_maxNumberOfColumns, _numberOfColumns);
|
||||
|
||||
|
||||
var remaining = width - _numberOfColumns * itemSize.width,
|
||||
itemsNeedSizeUpdate = NO;
|
||||
|
||||
|
||||
if (remaining > 0 && itemSize.width < _maxItemSize.width)
|
||||
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.
|
||||
if (_maxNumberOfColumns == 1 && itemSize.width < _maxItemSize.width && itemSize.width < width)
|
||||
itemSize.width = MIN(_maxItemSize.width, width);
|
||||
|
||||
|
||||
if (!CGSizeEqualToSize(_itemSize, itemSize))
|
||||
{
|
||||
_itemSize = itemSize;
|
||||
itemsNeedSizeUpdate = YES;
|
||||
}
|
||||
|
||||
|
||||
var index = 0,
|
||||
count = _items.length;
|
||||
|
||||
|
||||
if (_maxNumberOfColumns > 0 && _maxNumberOfRows > 0)
|
||||
count = MIN(count, _maxNumberOfColumns * _maxNumberOfRows);
|
||||
|
||||
|
||||
_numberOfRows = CEIL(count / _numberOfColumns);
|
||||
|
||||
_horizontalMargin = FLOOR((width - _numberOfColumns * itemSize.width) / (_numberOfColumns + 1));
|
||||
|
||||
|
||||
var x = _horizontalMargin,
|
||||
y = -itemSize.height;
|
||||
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
if (index % _numberOfColumns == 0)
|
||||
@@ -415,19 +417,28 @@
|
||||
x = _horizontalMargin;
|
||||
y += _verticalMargin + itemSize.height;
|
||||
}
|
||||
|
||||
|
||||
var view = [_items[index] view];
|
||||
|
||||
|
||||
[view setFrameOrigin:CGPointMake(x, y)];
|
||||
|
||||
|
||||
if (itemsNeedSizeUpdate)
|
||||
[view setFrameSize:_itemSize];
|
||||
|
||||
|
||||
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;
|
||||
[self setFrameSize:CGSizeMake(width, y + itemSize.height + _verticalMargin)];
|
||||
[self setFrameSize:CGSizeMake(width, proposedHeight)];
|
||||
_tileWidth = -1.0;
|
||||
}
|
||||
|
||||
@@ -445,9 +456,9 @@
|
||||
{
|
||||
if (_maxNumberOfRows == aMaxNumberOfRows)
|
||||
return;
|
||||
|
||||
|
||||
_maxNumberOfRows = aMaxNumberOfRows;
|
||||
|
||||
|
||||
[self tile];
|
||||
}
|
||||
|
||||
@@ -467,9 +478,9 @@
|
||||
{
|
||||
if (_maxNumberOfColumns == aMaxNumberOfColumns)
|
||||
return;
|
||||
|
||||
|
||||
_maxNumberOfColumns = aMaxNumberOfColumns;
|
||||
|
||||
|
||||
[self tile];
|
||||
}
|
||||
|
||||
@@ -506,9 +517,9 @@
|
||||
{
|
||||
if (CGSizeEqualToSize(_minItemSize, aSize))
|
||||
return;
|
||||
|
||||
|
||||
_minItemSize = CGSizeMakeCopy(aSize);
|
||||
|
||||
|
||||
[self tile];
|
||||
}
|
||||
|
||||
@@ -528,9 +539,9 @@
|
||||
{
|
||||
if (CGSizeEqualToSize(_maxItemSize, aSize))
|
||||
return;
|
||||
|
||||
|
||||
_maxItemSize = CGSizeMakeCopy(aSize);
|
||||
|
||||
|
||||
[self tile];
|
||||
}
|
||||
|
||||
@@ -582,14 +593,51 @@
|
||||
index = row * _numberOfColumns + column;
|
||||
|
||||
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)
|
||||
[self setSelectionIndexes:[CPIndexSet indexSet]];
|
||||
}
|
||||
|
||||
- (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:)])
|
||||
return;
|
||||
|
||||
@@ -606,8 +654,6 @@
|
||||
|
||||
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:dragTypes owner:self];
|
||||
|
||||
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||
|
||||
if (!_itemForDragging)
|
||||
_itemForDragging = [self newItemForRepresentedObject:_content[[_selectionIndexes firstIndex]]];
|
||||
else
|
||||
@@ -648,9 +694,9 @@
|
||||
{
|
||||
if (_verticalMargin == aVerticalMargin)
|
||||
return;
|
||||
|
||||
|
||||
_verticalMargin = aVerticalMargin;
|
||||
|
||||
|
||||
[self tile];
|
||||
}
|
||||
|
||||
@@ -701,7 +747,7 @@
|
||||
count = [indexArray count];
|
||||
|
||||
for (; index < count; ++index)
|
||||
frame = CGRectUnion(frame, [self rectForItemAtIndex:indexArray[index]]);
|
||||
frame = CGRectUnion(frame, [self frameForItemAtIndex:indexArray[index]]);
|
||||
|
||||
return frame;
|
||||
}
|
||||
@@ -710,6 +756,29 @@
|
||||
|
||||
@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
|
||||
{
|
||||
var frame = [self frameForItemsAtIndexes:[self selectionIndexes]];
|
||||
@@ -721,41 +790,57 @@
|
||||
- (void)moveLeft:(id)sender
|
||||
{
|
||||
var index = [[self selectionIndexes] firstIndex];
|
||||
if (index === CPNotFound)
|
||||
if (index === CPNotFound)
|
||||
index = [[self items] count];
|
||||
|
||||
index = MAX(index - 1, 0);
|
||||
[self _modifySelectionWithNewIndex:index - 1 direction:-1 expand:NO];
|
||||
}
|
||||
|
||||
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
|
||||
[self _scrollToSelection];
|
||||
- (void)moveLeftAndModifySelection:(id)sender
|
||||
{
|
||||
var index = [[self selectionIndexes] firstIndex];
|
||||
if (index === CPNotFound)
|
||||
index = [[self items] count];
|
||||
|
||||
[self _modifySelectionWithNewIndex:index - 1 direction:-1 expand:YES];
|
||||
}
|
||||
|
||||
- (void)moveRight:(id)sender
|
||||
{
|
||||
var index = MIN([[self selectionIndexes] firstIndex] + 1, [[self items] count]-1);
|
||||
[self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + 1 direction:1 expand:NO];
|
||||
}
|
||||
|
||||
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
|
||||
[self _scrollToSelection];
|
||||
- (void)moveRightAndModifySelection:(id)sender
|
||||
{
|
||||
[self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + 1 direction:1 expand:YES];
|
||||
}
|
||||
|
||||
- (void)moveDown:(id)sender
|
||||
{
|
||||
var index = MIN([[self selectionIndexes] firstIndex] + [self numberOfColumns], [[self items] count]-1);
|
||||
[self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + [self numberOfColumns] direction:1 expand:NO];
|
||||
}
|
||||
|
||||
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
|
||||
[self _scrollToSelection];
|
||||
- (void)moveDownAndModifySelection:(id)sender
|
||||
{
|
||||
[self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + [self numberOfColumns] direction:1 expand:YES];
|
||||
}
|
||||
|
||||
- (void)moveUp:(id)sender
|
||||
{
|
||||
var index = [[self selectionIndexes] firstIndex];
|
||||
if (index == CPNotFound)
|
||||
if (index == CPNotFound)
|
||||
index = [[self items] count];
|
||||
|
||||
index = MAX(0, index - [self numberOfColumns]);
|
||||
[self _modifySelectionWithNewIndex:index - [self numberOfColumns] direction:-1 expand:NO];
|
||||
}
|
||||
|
||||
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
|
||||
[self _scrollToSelection];
|
||||
- (void)moveUpAndModifySelection:(id)sender
|
||||
{
|
||||
var index = [[self selectionIndexes] firstIndex];
|
||||
if (index == CPNotFound)
|
||||
index = [[self items] count];
|
||||
|
||||
[self _modifySelectionWithNewIndex:index - [self numberOfColumns] direction:-1 expand:YES];
|
||||
}
|
||||
|
||||
- (void)deleteBackward:(id)sender
|
||||
@@ -765,8 +850,8 @@
|
||||
[[self delegate] collectionView:self shouldDeleteItemsAtIndexes:[self selectionIndexes]];
|
||||
|
||||
var index = [[self selectionIndexes] firstIndex];
|
||||
if (index > [[self content] count]-1)
|
||||
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:[[self content] count]-1]];
|
||||
if (index > [[self content] count] - 1)
|
||||
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:[[self content] count] - 1]];
|
||||
|
||||
[self _scrollToSelection];
|
||||
[self setNeedsDisplay:YES];
|
||||
@@ -800,11 +885,14 @@
|
||||
|
||||
@end
|
||||
|
||||
var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
|
||||
CPCollectionViewMaxItemSizeKey = @"CPCollectionViewMaxItemSizeKey",
|
||||
CPCollectionViewVerticalMarginKey = @"CPCollectionViewVerticalMarginKey",
|
||||
CPCollectionViewSelectableKey = @"CPCollectionViewSelectableKey",
|
||||
CPCollectionViewBackgroundColorsKey = @"CPCollectionViewBackgroundColorsKey";
|
||||
var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
|
||||
CPCollectionViewMaxItemSizeKey = @"CPCollectionViewMaxItemSizeKey",
|
||||
CPCollectionViewVerticalMarginKey = @"CPCollectionViewVerticalMarginKey",
|
||||
CPCollectionViewMaxNumberOfRowsKey = @"CPCollectionViewMaxNumberOfRowsKey",
|
||||
CPCollectionViewMaxNumberOfColumnsKey = @"CPCollectionViewMaxNumberOfColumnsKey",
|
||||
CPCollectionViewSelectableKey = @"CPCollectionViewSelectableKey",
|
||||
CPCollectionViewAllowsMultipleSelectionKey = @"CPCollectionViewAllowsMultipleSelectionKey",
|
||||
CPCollectionViewBackgroundColorsKey = @"CPCollectionViewBackgroundColorsKey";
|
||||
|
||||
|
||||
@implementation CPCollectionView (CPCoding)
|
||||
@@ -821,20 +909,24 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
|
||||
_cachedItems = [];
|
||||
|
||||
_itemSize = CGSizeMakeZero();
|
||||
|
||||
|
||||
_minItemSize = [aCoder decodeSizeForKey:CPCollectionViewMinItemSizeKey] || CGSizeMakeZero();
|
||||
_maxItemSize = [aCoder decodeSizeForKey:CPCollectionViewMaxItemSizeKey] || CGSizeMakeZero();
|
||||
|
||||
|
||||
_maxNumberOfRows = [aCoder decodeIntForKey:CPCollectionViewMaxNumberOfRowsKey] || 0;
|
||||
_maxNumberOfColumns = [aCoder decodeIntForKey:CPCollectionViewMaxNumberOfColumnsKey] || 0;
|
||||
|
||||
_verticalMargin = [aCoder decodeFloatForKey:CPCollectionViewVerticalMarginKey];
|
||||
|
||||
|
||||
_isSelectable = [aCoder decodeBoolForKey:CPCollectionViewSelectableKey];
|
||||
_allowsMultipleSelection = [aCoder decodeBoolForKey:CPCollectionViewAllowsMultipleSelectionKey];
|
||||
|
||||
[self setBackgroundColors:[aCoder decodeObjectForKey:CPCollectionViewBackgroundColorsKey]];
|
||||
|
||||
|
||||
_tileWidth = -1.0;
|
||||
|
||||
_selectionIndexes = [CPIndexSet indexSet];
|
||||
|
||||
|
||||
_allowsEmptySelection = YES;
|
||||
}
|
||||
|
||||
@@ -847,12 +939,16 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
|
||||
|
||||
if (!CGSizeEqualToSize(_minItemSize, CGSizeMakeZero()))
|
||||
[aCoder encodeSize:_minItemSize forKey:CPCollectionViewMinItemSizeKey];
|
||||
|
||||
|
||||
if (!CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero()))
|
||||
[aCoder encodeSize:_maxItemSize forKey:CPCollectionViewMaxItemSizeKey];
|
||||
|
||||
|
||||
[aCoder encodeInt:_maxNumberOfRows forKey:CPCollectionViewMaxNumberOfRowsKey];
|
||||
[aCoder encodeInt:_maxNumberOfColumns forKey:CPCollectionViewMaxNumberOfColumnsKey];
|
||||
|
||||
[aCoder encodeBool:_isSelectable forKey:CPCollectionViewSelectableKey];
|
||||
|
||||
[aCoder encodeBool:_allowsMultipleSelection forKey:CPCollectionViewAllowsMultipleSelectionKey];
|
||||
|
||||
[aCoder encodeFloat:_verticalMargin forKey:CPCollectionViewVerticalMarginKey];
|
||||
|
||||
[aCoder encodeObject:_backgroundColors forKey:CPCollectionViewBackgroundColorsKey];
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
@import "CPViewController.j"
|
||||
|
||||
|
||||
/*!
|
||||
Represents an object inside a CPCollectionView.
|
||||
*/
|
||||
|
||||
+87
-91
@@ -32,7 +32,7 @@ var _redComponent = 0,
|
||||
_greenComponent = 1,
|
||||
_blueComponent = 2,
|
||||
_alphaCompnent = 3;
|
||||
|
||||
|
||||
var _hueComponent = 0,
|
||||
_saturationComponent = 1,
|
||||
_brightnessComponent = 2;
|
||||
@@ -54,27 +54,21 @@ var cachedBlackColor,
|
||||
cachedShadowColor,
|
||||
cachedClearColor;
|
||||
|
||||
/*!
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@code CPColor
|
||||
|
||||
\c CPColor can be used to represent color
|
||||
in an RGB or HSB model with an optional transparency value.</p>
|
||||
|
||||
<p>It also provides some class helper methods that
|
||||
returns instances of commonly used colors.</p>
|
||||
|
||||
<p>The class does not have a \c -set: method
|
||||
like NextStep based frameworks to change the color of
|
||||
the current context. To change the color of the current
|
||||
context, use CGContextSetFillColor().
|
||||
*/
|
||||
@implementation CPColor : CPObject
|
||||
{
|
||||
CPArray _components;
|
||||
|
||||
CPImage _patternImage;
|
||||
CPString _cssString;
|
||||
CPString _cssString;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -82,12 +76,12 @@ var cachedBlackColor,
|
||||
Each component should be between the range of 0.0 to 1.0. For
|
||||
the alpha component, a value of 1.0 is opaque, and 0.0 means
|
||||
completely transparent.
|
||||
|
||||
|
||||
@param red the red component of the color
|
||||
@param green the green component of the color
|
||||
@param blue the blue component of the color
|
||||
@param alpha the alpha component
|
||||
|
||||
|
||||
@return a color initialized to the values specified
|
||||
*/
|
||||
+ (CPColor)colorWithRed:(float)red green:(float)green blue:(float)blue alpha:(float)alpha
|
||||
@@ -97,17 +91,17 @@ var cachedBlackColor,
|
||||
|
||||
/*!
|
||||
@deprecated in favor of colorWithRed:green:blue:alpha:
|
||||
|
||||
|
||||
Creates a color in the RGB color space, with an alpha value.
|
||||
Each component should be between the range of 0.0 to 1.0. For
|
||||
the alpha component, a value of 1.0 is opaque, and 0.0 means
|
||||
completely transparent.
|
||||
|
||||
|
||||
@param red the red component of the color
|
||||
@param green the green component of the color
|
||||
@param blue the blue component of the color
|
||||
@param alpha the alpha component
|
||||
|
||||
|
||||
@return a color initialized to the values specified
|
||||
*/
|
||||
+ (CPColor)colorWithCalibratedRed:(float)red green:(float)green blue:(float)blue alpha:(float)alpha
|
||||
@@ -119,10 +113,10 @@ var cachedBlackColor,
|
||||
/*!
|
||||
Creates a new color object with \c white for the RGB components.
|
||||
For the alpha component, a value of 1.0 is opaque, and 0.0 means completely transparent.
|
||||
|
||||
|
||||
@param white a float between 0.0 and 1.0
|
||||
@param alpha the alpha component between 0.0 and 1.0
|
||||
|
||||
|
||||
@return a color initialized to the values specified
|
||||
*/
|
||||
+ (CPColor)colorWithWhite:(float)white alpha:(float)alpha
|
||||
@@ -132,13 +126,13 @@ var cachedBlackColor,
|
||||
|
||||
/*!
|
||||
@deprecated in favor of colorWithWhite:apha:
|
||||
|
||||
|
||||
Creates a new color object with \c white for the RGB components.
|
||||
For the alpha component, a value of 1.0 is opaque, and 0.0 means completely transparent.
|
||||
|
||||
|
||||
@param white a float between 0.0 and 1.0
|
||||
@param alpha the alpha component between 0.0 and 1.0
|
||||
|
||||
|
||||
@return a color initialized to the values specified
|
||||
*/
|
||||
+ (CPColor)colorWithCalibratedWhite:(float)white alpha:(float)alpha
|
||||
@@ -148,11 +142,11 @@ var cachedBlackColor,
|
||||
|
||||
/*!
|
||||
Creates a new color in HSB space.
|
||||
|
||||
|
||||
@param hue the hue value
|
||||
@param saturation the saturation value
|
||||
@param brightness the brightness value
|
||||
|
||||
|
||||
@return the initialized color
|
||||
*/
|
||||
+ (CPColor)colorWithHue:(float)hue saturation:(float)saturation brightness:(float)brightness
|
||||
@@ -162,16 +156,16 @@ var cachedBlackColor,
|
||||
|
||||
+ (CPColor)colorWithHue:(float)hue saturation:(float)saturation brightness:(float)brightness alpha:(float)alpha
|
||||
{
|
||||
if(saturation === 0.0)
|
||||
if (saturation === 0.0)
|
||||
return [CPColor colorWithCalibratedWhite:brightness / 100.0 alpha:alpha];
|
||||
|
||||
|
||||
var f = hue % 60,
|
||||
p = (brightness * (100 - saturation)) / 10000,
|
||||
q = (brightness * (6000 - saturation * f)) / 600000,
|
||||
t = (brightness * (6000 - saturation * (60 -f))) / 600000,
|
||||
b = brightness / 100.0;
|
||||
|
||||
switch(FLOOR(hue / 60))
|
||||
|
||||
switch (FLOOR(hue / 60))
|
||||
{
|
||||
case 0: return [CPColor colorWithCalibratedRed: b green: t blue: p alpha: alpha];
|
||||
case 1: return [CPColor colorWithCalibratedRed: q green: b blue: p alpha: alpha];
|
||||
@@ -186,7 +180,7 @@ var cachedBlackColor,
|
||||
Creates an RGB color from a hexadecimal string. For example,
|
||||
the a string of "FFFFFF" would return a white CPColor.
|
||||
"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
|
||||
|
||||
@@ -194,7 +188,8 @@ var cachedBlackColor,
|
||||
*/
|
||||
+ (CPColor)colorWithHexString:(string)hex
|
||||
{
|
||||
return [[CPColor alloc] _initWithRGBA: hexToRGB(hex)];
|
||||
var rgba = hexToRGB(hex);
|
||||
return rgba ? [[CPColor alloc] _initWithRGBA: rgba] : null;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -397,7 +392,7 @@ var cachedBlackColor,
|
||||
|
||||
/*!
|
||||
Creates a CPColor from a valid CSS RGB string. Example, "rgb(32,64,129)".
|
||||
|
||||
|
||||
@param aString a CSS color string
|
||||
@return a color initialized to the value in the css string
|
||||
*/
|
||||
@@ -409,23 +404,23 @@ var cachedBlackColor,
|
||||
/* @ignore */
|
||||
- (id)_initWithCSSString:(CPString)aString
|
||||
{
|
||||
if(aString.indexOf("rgb") == CPNotFound)
|
||||
if (aString.indexOf("rgb") == CPNotFound)
|
||||
return nil;
|
||||
|
||||
|
||||
self = [super init];
|
||||
|
||||
var startingIndex = aString.indexOf("(");
|
||||
var parts = aString.substring(startingIndex+1).split(',');
|
||||
|
||||
|
||||
var startingIndex = aString.indexOf("("),
|
||||
parts = aString.substring(startingIndex + 1).split(',');
|
||||
|
||||
_components = [
|
||||
parseInt(parts[0], 10) / 255.0,
|
||||
parseInt(parts[1], 10) / 255.0,
|
||||
parseInt(parts[2], 10) / 255.0,
|
||||
parts[3] ? parseInt(parts[3], 10) / 255.0 : 1.0
|
||||
]
|
||||
|
||||
parts[3] ? parseInt(parts[3], 10) / 255.0 : 1.0
|
||||
];
|
||||
|
||||
_cssString = aString;
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -433,7 +428,7 @@ var cachedBlackColor,
|
||||
- (id)_initWithRGBA:(CPArray)components
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_components = components;
|
||||
@@ -454,14 +449,14 @@ var cachedBlackColor,
|
||||
- (id)_initWithPatternImage:(CPImage)anImage
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_patternImage = anImage;
|
||||
_cssString = "url(\"" + [_patternImage filename] + "\")";
|
||||
_components = [0.0, 0.0, 0.0, 1.0];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -523,17 +518,17 @@ var cachedBlackColor,
|
||||
|
||||
/*!
|
||||
Returns a new color with the same RGB as the receiver but a new alpha component.
|
||||
|
||||
|
||||
@param anAlphaComponent the alpha component for the new color
|
||||
|
||||
|
||||
@return a new color object
|
||||
*/
|
||||
- (CPColor)colorWithAlphaComponent:(float)anAlphaComponent
|
||||
{
|
||||
var components = _components.slice();
|
||||
|
||||
|
||||
components[components.length - 1] = anAlphaComponent;
|
||||
|
||||
|
||||
return [[[self class] alloc] _initWithRGBA:components];
|
||||
}
|
||||
|
||||
@@ -552,37 +547,40 @@ var cachedBlackColor,
|
||||
var red = ROUND(_components[_redComponent] * 255.0),
|
||||
green = ROUND(_components[_greenComponent] * 255.0),
|
||||
blue = ROUND(_components[_blueComponent] * 255.0);
|
||||
|
||||
|
||||
var max = MAX(red, green, blue),
|
||||
min = MIN(red, green, blue),
|
||||
delta = max - min;
|
||||
|
||||
|
||||
var brightness = max / 255.0,
|
||||
saturation = (max != 0) ? delta / max : 0;
|
||||
|
||||
|
||||
var hue;
|
||||
if(saturation == 0)
|
||||
|
||||
if (saturation == 0)
|
||||
{
|
||||
hue = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
var rr = (max - red) / delta;
|
||||
var gr = (max - green) / delta;
|
||||
var br = (max - blue) / delta;
|
||||
|
||||
if (red == max)
|
||||
var rr = (max - red) / delta,
|
||||
gr = (max - green) / delta,
|
||||
br = (max - blue) / delta;
|
||||
|
||||
if (red == max)
|
||||
hue = br - gr;
|
||||
else if (green == max)
|
||||
else if (green == max)
|
||||
hue = 2 + rr - br;
|
||||
else
|
||||
else
|
||||
hue = 4 + gr - rr;
|
||||
|
||||
|
||||
hue /= 6;
|
||||
if (hue < 0)
|
||||
if (hue < 0)
|
||||
hue++;
|
||||
}
|
||||
|
||||
|
||||
return [
|
||||
ROUND(hue * 360.0),
|
||||
ROUND(hue * 360.0),
|
||||
ROUND(saturation * 100.0),
|
||||
ROUND(brightness * 100.0)
|
||||
];
|
||||
@@ -630,7 +628,7 @@ url("data:image/png;base64,BASE64ENCODEDDATA") // if there is a pattern image
|
||||
|
||||
@implementation CPColor (CoreGraphicsExtensions)
|
||||
|
||||
/*!
|
||||
/*!
|
||||
Set's the receiver to be the fill and stroke color in the current graphics context
|
||||
*/
|
||||
- (void)set
|
||||
@@ -639,16 +637,16 @@ url("data:image/png;base64,BASE64ENCODEDDATA") // if there is a pattern image
|
||||
[self setStroke];
|
||||
}
|
||||
|
||||
/*!
|
||||
/*!
|
||||
Set's the receiver to be the fill color in the current graphics context
|
||||
*/
|
||||
- (void)setFill
|
||||
{
|
||||
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
|
||||
*/
|
||||
- (void)setStroke
|
||||
@@ -681,7 +679,7 @@ var CPColorComponentsKey = @"CPColorComponentsKey",
|
||||
{
|
||||
if ([aCoder containsValueForKey:CPColorPatternImageKey])
|
||||
return [self _initWithPatternImage:[aCoder decodeObjectForKey:CPColorPatternImageKey]];
|
||||
|
||||
|
||||
return [self _initWithRGBA:[aCoder decodeObjectForKey:CPColorComponentsKey]];
|
||||
}
|
||||
|
||||
@@ -699,10 +697,8 @@ var CPColorComponentsKey = @"CPColorComponentsKey",
|
||||
|
||||
@end
|
||||
|
||||
var hexCharacters = "0123456789ABCDEF";
|
||||
|
||||
// HACK: prevent these from becoming globals. workaround for obj-j "function foo(){}" behavior
|
||||
var hexToRGB, rgbToHex, byteToHex;
|
||||
var hexCharacters = "0123456789ABCDEF";
|
||||
|
||||
/*!
|
||||
Used for the CPColor \c +colorWithHexString: implementation
|
||||
@@ -710,39 +706,39 @@ var hexToRGB, rgbToHex, byteToHex;
|
||||
@class CPColor
|
||||
@return an array of rgb components
|
||||
*/
|
||||
function hexToRGB(hex)
|
||||
var hexToRGB = function(hex)
|
||||
{
|
||||
if ( hex.length == 3 )
|
||||
if (hex.length == 3)
|
||||
hex = hex.charAt(0) + hex.charAt(0) + hex.charAt(1) + hex.charAt(1) + hex.charAt(2) + hex.charAt(2);
|
||||
if(hex.length != 6)
|
||||
|
||||
if (hex.length != 6)
|
||||
return null;
|
||||
|
||||
hex = hex.toUpperCase();
|
||||
|
||||
for(var i=0; i<hex.length; i++)
|
||||
if(hexCharacters.indexOf(hex.charAt(i)) == -1)
|
||||
for (var i = 0; i < hex.length; i++)
|
||||
if (hexCharacters.indexOf(hex.charAt(i)) == -1)
|
||||
return null;
|
||||
|
||||
var red = (hexCharacters.indexOf(hex.charAt(0)) * 16 + hexCharacters.indexOf(hex.charAt(1))) / 255.0;
|
||||
var green = (hexCharacters.indexOf(hex.charAt(2)) * 16 + hexCharacters.indexOf(hex.charAt(3))) / 255.0;
|
||||
var blue = (hexCharacters.indexOf(hex.charAt(4)) * 16 + hexCharacters.indexOf(hex.charAt(5))) / 255.0;
|
||||
|
||||
|
||||
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,
|
||||
blue = (hexCharacters.indexOf(hex.charAt(4)) * 16 + hexCharacters.indexOf(hex.charAt(5))) / 255.0;
|
||||
|
||||
return [red, green, blue, 1.0];
|
||||
}
|
||||
};
|
||||
|
||||
function rgbToHex(r,g,b) {
|
||||
var rgbToHex = function(r,g,b)
|
||||
{
|
||||
return byteToHex(r) + byteToHex(g) + byteToHex(b);
|
||||
}
|
||||
};
|
||||
|
||||
function byteToHex(n) {
|
||||
if (!n || isNaN(n)) return "00";
|
||||
n = ROUND(MIN(255,MAX(0,256*n)));
|
||||
return hexCharacters.charAt((n - n % 16) / 16) +
|
||||
hexCharacters.charAt(n % 16);
|
||||
}
|
||||
var byteToHex = function(n)
|
||||
{
|
||||
if (!n || isNaN(n))
|
||||
return "00";
|
||||
|
||||
// Toll-Free bridge CPColor to CGColor.
|
||||
//CGColor.prototype.isa = CPColor;
|
||||
//[CPColor initialize];
|
||||
n = FLOOR(MIN(255, MAX(0, 256 * n)));
|
||||
|
||||
//http://dev.mootools.net/browser/trunk/Source/Utilities/Color.js?rev=1184
|
||||
return hexCharacters.charAt((n - n % 16) / 16) +
|
||||
hexCharacters.charAt(n % 16);
|
||||
};
|
||||
|
||||
+83
-80
@@ -20,11 +20,13 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CPApplication.j"
|
||||
@import "CPButton.j"
|
||||
@import "CPCookie.j"
|
||||
@import "CPPanel.j"
|
||||
@import "CPView.j"
|
||||
|
||||
|
||||
CPColorPanelColorDidChangeNotification = @"CPColorPanelColorDidChangeNotification";
|
||||
|
||||
var PREVIEW_HEIGHT = 20.0,
|
||||
@@ -35,7 +37,7 @@ var PREVIEW_HEIGHT = 20.0,
|
||||
|
||||
var SharedColorPanel = nil,
|
||||
ColorPickerClasses = [];
|
||||
|
||||
|
||||
/*
|
||||
A color wheel
|
||||
@global
|
||||
@@ -52,7 +54,7 @@ CPSliderColorPickerMode = 2;
|
||||
CPColorPickerViewWidth = 265,
|
||||
CPColorPickerViewHeight = 370;
|
||||
|
||||
/*!
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPColorPanel
|
||||
|
||||
@@ -61,7 +63,7 @@ CPColorPickerViewHeight = 370;
|
||||
obtain the panel, call the \c +sharedColorPanel method.
|
||||
*/
|
||||
@implementation CPColorPanel : CPPanel
|
||||
{
|
||||
{
|
||||
_CPColorPanelToolbar _toolbar;
|
||||
_CPColorPanelSwatches _swatchView;
|
||||
_CPColorPanelPreview _previewView;
|
||||
@@ -80,8 +82,8 @@ CPColorPickerViewHeight = 370;
|
||||
int _mode;
|
||||
}
|
||||
|
||||
/*!
|
||||
A list of color pickers is collected here, and any color panel created will contain
|
||||
/*!
|
||||
A list of color pickers is collected here, and any color panel created will contain
|
||||
any picker in this list up to this point. In other words, call before creating a color panel.
|
||||
*/
|
||||
+ (void)provideColorPickerClass:(Class)aColorPickerSubclass
|
||||
@@ -96,7 +98,7 @@ CPColorPickerViewHeight = 370;
|
||||
{
|
||||
if (!SharedColorPanel)
|
||||
SharedColorPanel = [[CPColorPanel alloc] init];
|
||||
|
||||
|
||||
return SharedColorPanel;
|
||||
}
|
||||
|
||||
@@ -107,7 +109,7 @@ CPColorPickerViewHeight = 370;
|
||||
+ (void)setPickerMode:(CPColorPanelMode)mode
|
||||
{
|
||||
var panel = [CPColorPanel sharedColorPanel];
|
||||
[panel setMode: mode];
|
||||
[panel setMode:mode];
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -116,7 +118,7 @@ CPColorPickerViewHeight = 370;
|
||||
*/
|
||||
- (id)init
|
||||
{
|
||||
self = [super initWithContentRect:CGRectMake(500.0, 50.0, 219.0, 370.0)
|
||||
self = [super initWithContentRect:CGRectMake(500.0, 50.0, 219.0, 370.0)
|
||||
styleMask:(CPTitledWindowMask | CPClosableWindowMask | CPResizableWindowMask)];
|
||||
|
||||
if (self)
|
||||
@@ -125,14 +127,14 @@ CPColorPickerViewHeight = 370;
|
||||
|
||||
[self setTitle:@"Color Panel"];
|
||||
[self setLevel:CPFloatingWindowLevel];
|
||||
|
||||
|
||||
[self setFloatingPanel:YES];
|
||||
[self setBecomesKeyOnlyIfNeeded:YES];
|
||||
|
||||
|
||||
[self setMinSize:CGSizeMake(219.0, 342.0)];
|
||||
[self setMaxSize:CGSizeMake(323.0, 537.0)];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -143,12 +145,12 @@ CPColorPickerViewHeight = 370;
|
||||
{
|
||||
_color = aColor;
|
||||
[_previewView setBackgroundColor: _color];
|
||||
|
||||
|
||||
[CPApp sendAction:@selector(changeColor:) to:nil from:self];
|
||||
|
||||
if (_target && _action)
|
||||
[CPApp sendAction:_action to:_target from:self];
|
||||
|
||||
|
||||
[[CPNotificationCenter defaultCenter]
|
||||
postNotificationName:CPColorPanelColorDidChangeNotification
|
||||
object:self];
|
||||
@@ -165,7 +167,7 @@ CPColorPickerViewHeight = 370;
|
||||
- (void)setColor:(CPColor)aColor updatePicker:(BOOL)bool
|
||||
{
|
||||
[self setColor:aColor];
|
||||
|
||||
|
||||
if (bool)
|
||||
[_activePicker setColor:_color];
|
||||
}
|
||||
@@ -232,30 +234,30 @@ CPColorPickerViewHeight = 370;
|
||||
{
|
||||
var picker = _colorPickers[[sender tag]],
|
||||
view = [picker provideNewView:NO];
|
||||
|
||||
|
||||
if (!view)
|
||||
view = [picker provideNewView:YES];
|
||||
|
||||
|
||||
if (view == _currentView)
|
||||
return;
|
||||
|
||||
|
||||
if (_currentView)
|
||||
[view setFrame:[_currentView frame]];
|
||||
else
|
||||
{
|
||||
var height = (TOOLBAR_HEIGHT+10+PREVIEW_HEIGHT+5+SWATCH_HEIGHT+32),
|
||||
var height = (TOOLBAR_HEIGHT + 10 + PREVIEW_HEIGHT + 5 + SWATCH_HEIGHT + 32),
|
||||
bounds = [[self contentView] bounds];
|
||||
|
||||
[view setFrameSize: CPSizeMake(bounds.size.width - 10, bounds.size.height - height)];
|
||||
[view setFrameOrigin: CPPointMake(5, height)];
|
||||
[view setFrameSize:CPSizeMake(bounds.size.width - 10, bounds.size.height - height)];
|
||||
[view setFrameOrigin:CPPointMake(5, height)];
|
||||
}
|
||||
|
||||
|
||||
[_currentView removeFromSuperview];
|
||||
[[self contentView] addSubview:view];
|
||||
|
||||
|
||||
_currentView = view;
|
||||
_activePicker = picker;
|
||||
|
||||
|
||||
[picker setColor:[self color]];
|
||||
}
|
||||
|
||||
@@ -285,7 +287,7 @@ CPColorPickerViewHeight = 370;
|
||||
_colorPickers = [];
|
||||
|
||||
var count = [ColorPickerClasses count];
|
||||
for (var i=0; i<count; i++)
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var currentPickerClass = ColorPickerClasses[i],
|
||||
currentPicker = [[currentPickerClass alloc] initWithPickerMask:0 colorPanel:self];
|
||||
@@ -297,29 +299,29 @@ CPColorPickerViewHeight = 370;
|
||||
bounds = [contentView bounds];
|
||||
|
||||
_toolbar = [[CPView alloc] initWithFrame:CGRectMake(0, 6, CGRectGetWidth(bounds), TOOLBAR_HEIGHT)];
|
||||
[_toolbar setAutoresizingMask: CPViewWidthSizable];
|
||||
[_toolbar setAutoresizingMask: CPViewWidthSizable];
|
||||
|
||||
var totalToolbarWidth = count * ICON_WIDTH + (count - 1) * ICON_PADDING,
|
||||
leftOffset = (CGRectGetWidth(bounds) - totalToolbarWidth) / 2.0,
|
||||
buttonForLater = nil;
|
||||
|
||||
for (var i=0; i<count; i++)
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var image = [_colorPickers[i] provideNewButtonImage],
|
||||
highlightImage = [_colorPickers[i] provideNewAlternateButtonImage],
|
||||
button = [[CPButton alloc] initWithFrame:CGRectMake(leftOffset + i*(ICON_WIDTH+ICON_PADDING), 0, ICON_WIDTH, ICON_WIDTH)];
|
||||
|
||||
button = [[CPButton alloc] initWithFrame:CGRectMake(leftOffset + i * (ICON_WIDTH + ICON_PADDING), 0, ICON_WIDTH, ICON_WIDTH)];
|
||||
|
||||
[button setTag:i];
|
||||
[button setTarget:self];
|
||||
[button setAction:@selector(_setPicker:)];
|
||||
[button setBordered:NO];
|
||||
[button setAutoresizingMask:CPViewMinXMargin|CPViewMaxXMargin];
|
||||
|
||||
[button setAutoresizingMask:CPViewMinXMargin | CPViewMaxXMargin];
|
||||
|
||||
[button setImage:image];
|
||||
[button setAlternateImage:highlightImage];
|
||||
|
||||
|
||||
[_toolbar addSubview:button];
|
||||
|
||||
|
||||
if (!buttonForLater)
|
||||
buttonForLater = button;
|
||||
}
|
||||
@@ -330,7 +332,7 @@ CPColorPickerViewHeight = 370;
|
||||
_previewView = [[_CPColorPanelPreview alloc] initWithFrame:CGRectInset([previewBox bounds], 2.0, 2.0)];
|
||||
|
||||
[_previewView setColorPanel:self];
|
||||
[_previewView setAutoresizingMask:CPViewWidthSizable];
|
||||
[_previewView setAutoresizingMask:CPViewWidthSizable];
|
||||
|
||||
[previewBox setBackgroundColor:[CPColor colorWithWhite:0.8 alpha:1.0]];
|
||||
[previewBox setAutoresizingMask:CPViewWidthSizable];
|
||||
@@ -338,7 +340,7 @@ CPColorPickerViewHeight = 370;
|
||||
[previewBox addSubview:_previewView];
|
||||
|
||||
var _previewLabel = [[CPTextField alloc] initWithFrame: CPRectMake(10, TOOLBAR_HEIGHT + 10, 60, 15)];
|
||||
[_previewLabel setStringValue: "Preview:"];
|
||||
[_previewLabel setStringValue:"Preview:"];
|
||||
[_previewLabel setTextColor:[CPColor blackColor]];
|
||||
[_previewLabel setAlignment:CPRightTextAlignment];
|
||||
|
||||
@@ -350,8 +352,8 @@ CPColorPickerViewHeight = 370;
|
||||
|
||||
_swatchView = [[_CPColorPanelSwatches alloc] initWithFrame:CGRectInset([swatchBox bounds], 1.0, 1.0)];
|
||||
|
||||
[_swatchView setColorPanel: self];
|
||||
[_swatchView setAutoresizingMask: CPViewWidthSizable];
|
||||
[_swatchView setColorPanel:self];
|
||||
[_swatchView setAutoresizingMask:CPViewWidthSizable];
|
||||
|
||||
[swatchBox addSubview:_swatchView];
|
||||
|
||||
@@ -367,7 +369,7 @@ CPColorPickerViewHeight = 370;
|
||||
[opacityLabel setAlignment:CPRightTextAlignment];
|
||||
|
||||
_opacitySlider = [[CPSlider alloc] initWithFrame:CGRectMake(76, TOOLBAR_HEIGHT + PREVIEW_HEIGHT + 34, CGRectGetWidth(bounds) - 86, 20.0)];
|
||||
|
||||
|
||||
[_opacitySlider setMinValue:0.0];
|
||||
[_opacitySlider setMaxValue:1.0];
|
||||
|
||||
@@ -415,37 +417,37 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
CPCookie _swatchCookie;
|
||||
}
|
||||
|
||||
-(id)initWithFrame:(CPRect)aFrame
|
||||
- (id)initWithFrame:(CPRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
|
||||
[self setBackgroundColor: [CPColor grayColor]];
|
||||
|
||||
|
||||
[self registerForDraggedTypes:[CPArray arrayWithObjects:CPColorDragType]];
|
||||
|
||||
var whiteColor = [CPColor whiteColor];
|
||||
|
||||
_swatchCookie = [[CPCookie alloc] initWithName: CPColorPanelSwatchesCookie];
|
||||
var colorList = [self startingColorList];
|
||||
|
||||
|
||||
_swatches = [];
|
||||
|
||||
for(var i=0; i < 50; i++)
|
||||
|
||||
for (var i = 0; i < 50; i++)
|
||||
{
|
||||
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
|
||||
var view = [[CPView alloc] initWithFrame: CPRectMake(13*i+1, 1, 12, 12)],
|
||||
var view = [[CPView alloc] initWithFrame: CPRectMake(13 * i + 1, 1, 12, 12)],
|
||||
fillView = [[CPView alloc] initWithFrame:CGRectInset([view bounds], 1.0, 1.0)];
|
||||
|
||||
|
||||
[view setBackgroundColor:whiteColor];
|
||||
[fillView setBackgroundColor: (i < colorList.length) ? colorList[i] : whiteColor];
|
||||
|
||||
[view addSubview:fillView];
|
||||
|
||||
[self addSubview: view];
|
||||
|
||||
|
||||
_swatches.push(view);
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -457,7 +459,8 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
- (CPArray)startingColorList
|
||||
{
|
||||
var cookieValue = [_swatchCookie value];
|
||||
if(cookieValue == "")
|
||||
|
||||
if (cookieValue == "")
|
||||
{
|
||||
return [
|
||||
[CPColor blackColor],
|
||||
@@ -471,11 +474,11 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
[CPColor yellowColor]
|
||||
];
|
||||
}
|
||||
|
||||
var cookieValue = eval(cookieValue);
|
||||
var result = [];
|
||||
|
||||
for(var i=0; i<cookieValue.length; i++)
|
||||
|
||||
var cookieValue = eval(cookieValue),
|
||||
result = [];
|
||||
|
||||
for (var i = 0; i < cookieValue.length; i++)
|
||||
result.push([CPColor colorWithHexString: cookieValue[i]]);
|
||||
|
||||
return result;
|
||||
@@ -485,12 +488,12 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
{
|
||||
var result = [];
|
||||
// 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]);
|
||||
|
||||
|
||||
var future = new Date();
|
||||
future.setYear(2019);
|
||||
|
||||
|
||||
[_swatchCookie setValue: JSON.stringify(result) expires:future domain: nil];
|
||||
}
|
||||
|
||||
@@ -520,8 +523,8 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
{
|
||||
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil],
|
||||
bounds = [self bounds];
|
||||
|
||||
if(!CGRectContainsPoint(bounds, point) || point.x > [self bounds].size.width - 1 || point.x < 1)
|
||||
|
||||
if (!CGRectContainsPoint(bounds, point) || point.x > [self bounds].size.width - 1 || point.x < 1)
|
||||
return NO;
|
||||
|
||||
[_colorPanel setColor: [self colorAtIndex:FLOOR(point.x / 13)] updatePicker: YES];
|
||||
@@ -535,21 +538,21 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
return NO;
|
||||
|
||||
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:[CPArray arrayWithObject:CPColorDragType] owner:self];
|
||||
|
||||
|
||||
var swatch = _swatches[FLOOR(point.x / 13)];
|
||||
|
||||
|
||||
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
|
||||
_dragColor = [[swatch subviews][0] backgroundColor];
|
||||
|
||||
|
||||
var bounds = CPRectCreateCopy([swatch bounds]);
|
||||
|
||||
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
|
||||
var dragView = [[CPView alloc] initWithFrame: bounds];
|
||||
var dragView = [[CPView alloc] initWithFrame: bounds],
|
||||
dragFillView = [[CPView alloc] initWithFrame:CGRectInset(bounds, 1.0, 1.0)];
|
||||
|
||||
|
||||
[dragView setBackgroundColor:[CPColor blackColor]];
|
||||
[dragFillView setBackgroundColor:_dragColor];
|
||||
|
||||
|
||||
[dragView addSubview:dragFillView];
|
||||
|
||||
[self dragView: dragView
|
||||
@@ -563,19 +566,19 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
|
||||
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
|
||||
{
|
||||
if(aType == CPColorDragType)
|
||||
if (aType == CPColorDragType)
|
||||
[aPasteboard setData:[CPKeyedArchiver archivedDataWithRootObject:_dragColor] forType:aType];
|
||||
}
|
||||
|
||||
- (void)performDragOperation:(id <CPDraggingInfo>)aSender
|
||||
{
|
||||
{
|
||||
var location = [self convertPoint:[aSender draggingLocation] fromView:nil],
|
||||
pasteboard = [aSender draggingPasteboard],
|
||||
swatch = nil;
|
||||
|
||||
if(![pasteboard availableTypeFromArray:[CPColorDragType]] || location.x > [self bounds].size.width - 1 || location.x < 1)
|
||||
if (![pasteboard availableTypeFromArray:[CPColorDragType]] || location.x > [self bounds].size.width - 1 || location.x < 1)
|
||||
return NO;
|
||||
|
||||
|
||||
[self setColor:[CPKeyedUnarchiver unarchiveObjectWithData:[pasteboard dataForType:CPColorDragType]] atIndex: FLOOR(location.x / 13)];
|
||||
}
|
||||
|
||||
@@ -590,9 +593,9 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
- (id)initWithFrame:(CPRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
|
||||
[self registerForDraggedTypes:[CPArray arrayWithObjects:CPColorDragType]];
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -610,9 +613,9 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
{
|
||||
var pasteboard = [aSender draggingPasteboard];
|
||||
|
||||
if(![pasteboard availableTypeFromArray:[CPColorDragType]])
|
||||
if (![pasteboard availableTypeFromArray:[CPColorDragType]])
|
||||
return NO;
|
||||
|
||||
|
||||
var color = [CPKeyedUnarchiver unarchiveObjectWithData:[pasteboard dataForType:CPColorDragType]];
|
||||
[_colorPanel setColor:color updatePicker:YES];
|
||||
}
|
||||
@@ -626,19 +629,19 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
{
|
||||
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||
|
||||
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:[CPColorDragType] owner:self];
|
||||
|
||||
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:[CPColorDragType] owner:self];
|
||||
|
||||
var bounds = CPRectMake(0, 0, 15, 15);
|
||||
|
||||
|
||||
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
|
||||
var dragView = [[CPView alloc] initWithFrame: bounds];
|
||||
var dragView = [[CPView alloc] initWithFrame: bounds],
|
||||
dragFillView = [[CPView alloc] initWithFrame:CGRectInset(bounds, 1.0, 1.0)];
|
||||
|
||||
|
||||
[dragView setBackgroundColor:[CPColor blackColor]];
|
||||
[dragFillView setBackgroundColor:[self backgroundColor]];
|
||||
|
||||
|
||||
[dragView addSubview:dragFillView];
|
||||
|
||||
|
||||
[self dragView: dragView
|
||||
at: CPPointMake(point.x - bounds.size.width / 2.0, point.y - bounds.size.height / 2.0)
|
||||
offset: CPPointMake(0.0, 0.0)
|
||||
@@ -650,7 +653,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
|
||||
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
|
||||
{
|
||||
if(aType == CPColorDragType)
|
||||
if (aType == CPColorDragType)
|
||||
[aPasteboard setData:[CPKeyedArchiver archivedDataWithRootObject:[self backgroundColor]] forType:aType];
|
||||
}
|
||||
|
||||
|
||||
+36
-39
@@ -21,11 +21,11 @@
|
||||
*/
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
@import "CPColorPanel.j"
|
||||
|
||||
#include "Platform/Platform.h"
|
||||
@import "CPView.j"
|
||||
|
||||
/*!
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPColorPicker
|
||||
|
||||
@@ -102,18 +102,18 @@
|
||||
|
||||
CPColor _cachedColor;
|
||||
}
|
||||
|
||||
- (id)initWithPickerMask:(int)mask colorPanel:(CPColorPanel)owningColorPanel
|
||||
|
||||
- (id)initWithPickerMask:(int)mask colorPanel:(CPColorPanel)owningColorPanel
|
||||
{
|
||||
return [super initWithPickerMask:mask colorPanel: owningColorPanel];
|
||||
}
|
||||
|
||||
-(id)initView
|
||||
- (id)initView
|
||||
{
|
||||
aFrame = CPRectMake(0, 0, CPColorPickerViewWidth, CPColorPickerViewHeight);
|
||||
|
||||
_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)];
|
||||
|
||||
@@ -136,17 +136,17 @@
|
||||
[_pickerView addSubview:_brightnessSlider];
|
||||
}
|
||||
|
||||
-(void)brightnessSliderDidChange:(id)sender
|
||||
- (void)brightnessSliderDidChange:(id)sender
|
||||
{
|
||||
[self updateColor];
|
||||
}
|
||||
|
||||
-(void)colorWheelDidChange:(id)sender
|
||||
- (void)colorWheelDidChange:(id)sender
|
||||
{
|
||||
[self updateColor];
|
||||
}
|
||||
|
||||
-(void)updateColor
|
||||
- (void)updateColor
|
||||
{
|
||||
var hue = [_hueSaturationView angle],
|
||||
saturation = [_hueSaturationView distance],
|
||||
@@ -223,7 +223,7 @@
|
||||
float _radius;
|
||||
}
|
||||
|
||||
-(id)initWithFrame:(CPRect)aFrame
|
||||
- (id)initWithFrame:(CPRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
@@ -261,19 +261,19 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void)setWheelBrightness:(float)brightness
|
||||
- (void)setWheelBrightness:(float)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];
|
||||
[self setWheelSize:aSize];
|
||||
}
|
||||
|
||||
-(void)setWheelSize:(CPSize)aSize
|
||||
- (void)setWheelSize:(CPSize)aSize
|
||||
{
|
||||
var min = MIN(aSize.width, aSize.height);
|
||||
|
||||
@@ -296,57 +296,55 @@
|
||||
[self setAngle:[self degreesToRadians:_angle] distance:(_distance / 100.0) * _radius];
|
||||
}
|
||||
|
||||
-(void)setDelegate:(id)aDelegate
|
||||
- (void)setDelegate:(id)aDelegate
|
||||
{
|
||||
_delegate = aDelegate;
|
||||
}
|
||||
|
||||
-(id)delegate
|
||||
- (id)delegate
|
||||
{
|
||||
return _delegate;
|
||||
}
|
||||
|
||||
-(float)angle
|
||||
- (float)angle
|
||||
{
|
||||
return _angle;
|
||||
}
|
||||
|
||||
-(float)distance
|
||||
- (float)distance
|
||||
{
|
||||
return _distance;
|
||||
}
|
||||
|
||||
-(void)mouseDown:(CPEvent)anEvent
|
||||
- (void)mouseDown:(CPEvent)anEvent
|
||||
{
|
||||
[self reposition:anEvent];
|
||||
}
|
||||
|
||||
-(void)mouseDragged:(CPEvent)anEvent
|
||||
- (void)mouseDragged:(CPEvent)anEvent
|
||||
{
|
||||
[self reposition:anEvent];
|
||||
}
|
||||
|
||||
-(void)reposition:(CPEvent)anEvent
|
||||
- (void)reposition:(CPEvent)anEvent
|
||||
{
|
||||
var bounds = [self bounds],
|
||||
location = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||
|
||||
var midX = CGRectGetMidX(bounds);
|
||||
var midY = CGRectGetMidY(bounds);
|
||||
|
||||
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);
|
||||
location = [self convertPoint:[anEvent locationInWindow] fromView:nil],
|
||||
midX = CGRectGetMidX(bounds),
|
||||
midY = CGRectGetMidY(bounds),
|
||||
distance = MIN(SQRT((location.x - midX) * (location.x - midX) + (location.y - midY) * (location.y - midY)), _radius),
|
||||
angle = ATAN2(location.y - midY, location.x - midX);
|
||||
|
||||
[self setAngle:angle distance:distance];
|
||||
|
||||
[_delegate colorWheelDidChange:self];
|
||||
}
|
||||
|
||||
-(void)setAngle:(int)angle distance:(float)distance
|
||||
- (void)setAngle:(int)angle distance:(float)distance
|
||||
{
|
||||
var bounds = [self bounds];
|
||||
var midX = CGRectGetMidX(bounds);
|
||||
var midY = CGRectGetMidY(bounds);
|
||||
var bounds = [self bounds],
|
||||
midX = CGRectGetMidX(bounds),
|
||||
midY = CGRectGetMidY(bounds);
|
||||
|
||||
_angle = [self radiansToDegrees:angle];
|
||||
_distance = (distance / _radius) * 100.0;
|
||||
@@ -354,23 +352,22 @@
|
||||
[_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],
|
||||
bounds = [self bounds];
|
||||
|
||||
var angle = [self degreesToRadians:hsb[0]],
|
||||
bounds = [self bounds],
|
||||
angle = [self degreesToRadians:hsb[0]],
|
||||
distance = (hsb[1] / 100.0) * _radius;
|
||||
|
||||
[self setAngle:angle distance:distance];
|
||||
}
|
||||
|
||||
-(int)radiansToDegrees:(float)radians
|
||||
- (int)radiansToDegrees:(float)radians
|
||||
{
|
||||
return ((-radians / PI) * 180 + 360) % 360;
|
||||
}
|
||||
|
||||
-(float)degreesToRadians:(float)degrees
|
||||
- (float)degreesToRadians:(float)degrees
|
||||
{
|
||||
return -(((degrees - 360) / 180) * PI);
|
||||
}
|
||||
|
||||
+36
-30
@@ -29,7 +29,7 @@
|
||||
|
||||
var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiveNotification";
|
||||
|
||||
/*!
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPColorWell
|
||||
|
||||
@@ -41,7 +41,7 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
||||
{
|
||||
BOOL _active;
|
||||
BOOL _bordered;
|
||||
|
||||
|
||||
CPColor _color;
|
||||
CPView _wellView;
|
||||
}
|
||||
@@ -49,19 +49,19 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_active = NO;
|
||||
_bordered = YES;
|
||||
_color = [CPColor whiteColor];
|
||||
|
||||
|
||||
[self drawBezelWithHighlight:NO];
|
||||
[self drawWellInside:CGRectInset([self bounds], 3.0, 3.0)];
|
||||
|
||||
|
||||
[self _registerForNotifications];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -97,9 +97,9 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
||||
{
|
||||
if (_bordered == bordered)
|
||||
return;
|
||||
|
||||
|
||||
_bordered = bordered;
|
||||
|
||||
|
||||
[self drawWellInside:CGRectInset([self bounds], 3.0, 3.0)];
|
||||
}
|
||||
|
||||
@@ -120,9 +120,9 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
||||
{
|
||||
if (_color == aColor)
|
||||
return;
|
||||
|
||||
|
||||
_color = aColor;
|
||||
|
||||
|
||||
[self drawWellInside:CGRectInset([self bounds], 3.0, 3.0)];
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
||||
|
||||
// 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.
|
||||
@param shouldBeExclusive whether other color wells should be deactivated.
|
||||
*/
|
||||
@@ -152,9 +152,9 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
||||
|
||||
if ([self isActive])
|
||||
return;
|
||||
|
||||
|
||||
_active = YES;
|
||||
|
||||
|
||||
[[CPNotificationCenter defaultCenter]
|
||||
addObserver:self
|
||||
selector:@selector(colorPanelDidChangeColor:)
|
||||
@@ -169,9 +169,9 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
||||
{
|
||||
if (![self isActive])
|
||||
return;
|
||||
|
||||
|
||||
_active = NO;
|
||||
|
||||
|
||||
[[CPNotificationCenter defaultCenter]
|
||||
removeObserver:self
|
||||
name:CPColorPanelColorDidChangeNotification
|
||||
@@ -202,19 +202,19 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
||||
{
|
||||
_wellView = [[CPView alloc] initWithFrame:aRect];
|
||||
[_wellView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
|
||||
|
||||
[self addSubview:_wellView];
|
||||
}
|
||||
else
|
||||
[_wellView setFrame:aRect];
|
||||
|
||||
|
||||
[_wellView setBackgroundColor:_color];
|
||||
}
|
||||
|
||||
- (void)colorPanelDidChangeColor:(CPNotification)aNotification
|
||||
{
|
||||
[self takeColorFrom:[aNotification object]];
|
||||
|
||||
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
}
|
||||
|
||||
@@ -231,25 +231,31 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
|
||||
|
||||
- (void)mouseDown:(CPEvent)anEvent
|
||||
{
|
||||
if (![self isEnabled])
|
||||
return;
|
||||
|
||||
[self drawBezelWithHighlight:YES];
|
||||
}
|
||||
|
||||
- (void)mouseDragged:(CPEvent)anEvent
|
||||
{
|
||||
if (![self isEnabled])
|
||||
return;
|
||||
|
||||
[self drawBezelWithHighlight:CGRectContainsPoint([self bounds], [self convertPoint:[anEvent locationInWindow] fromView:nil])];
|
||||
}
|
||||
|
||||
-(void)mouseUp:(CPEvent)anEvent
|
||||
- (void)mouseUp:(CPEvent)anEvent
|
||||
{
|
||||
[self drawBezelWithHighlight:NO];
|
||||
|
||||
if (!CGRectContainsPoint([self bounds], [self convertPoint:[anEvent locationInWindow] fromView:nil]))
|
||||
if (!CGRectContainsPoint([self bounds], [self convertPoint:[anEvent locationInWindow] fromView:nil]) || ![self isEnabled])
|
||||
return;
|
||||
|
||||
|
||||
[self activate:YES];
|
||||
|
||||
var colorPanel = [CPColorPanel sharedColorPanel];
|
||||
|
||||
|
||||
[colorPanel setColor:_color];
|
||||
[colorPanel orderFront:self];
|
||||
}
|
||||
@@ -268,11 +274,11 @@ var CPColorWellColorKey = "CPColorWellColorKey",
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_active = NO;
|
||||
_bordered = [aCoder decodeObjectForKey:CPColorWellBorderedKey];
|
||||
_bordered = [aCoder decodeBoolForKey:CPColorWellBorderedKey];
|
||||
_color = [aCoder decodeObjectForKey:CPColorWellColorKey];
|
||||
|
||||
[self drawBezelWithHighlight:NO];
|
||||
@@ -280,7 +286,7 @@ var CPColorWellColorKey = "CPColorWellColorKey",
|
||||
|
||||
[self _registerForNotifications];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -290,17 +296,17 @@ var CPColorWellColorKey = "CPColorWellColorKey",
|
||||
*/
|
||||
- (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.
|
||||
var actualSubviews = _subviews;
|
||||
|
||||
|
||||
_subviews = [_subviews copy];
|
||||
[_subviews removeObjectIdenticalTo:_wellView];
|
||||
|
||||
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
|
||||
_subviews = actualSubviews;
|
||||
|
||||
|
||||
[aCoder encodeObject:_color forKey:CPColorWellColorKey];
|
||||
[aCoder encodeObject:_bordered forKey:CPColorWellBorderedKey];
|
||||
}
|
||||
|
||||
+16
-15
@@ -23,6 +23,7 @@
|
||||
@import "CPEvent.j"
|
||||
@import "CPPlatform.j"
|
||||
|
||||
|
||||
// Browser Engines
|
||||
CPUnknownBrowserEngine = 0;
|
||||
CPGeckoBrowserEngine = 1;
|
||||
@@ -77,23 +78,23 @@ if (typeof window !== "undefined" && typeof window.navigator !== "undefined")
|
||||
USER_AGENT = window.navigator.userAgent;
|
||||
|
||||
// Opera
|
||||
if (window.opera)
|
||||
if (typeof window !== "undefined" && window.opera)
|
||||
{
|
||||
PLATFORM_ENGINE = CPOperaBrowserEngine;
|
||||
|
||||
|
||||
PLATFORM_FEATURES |= CPJavaScriptCanvasDrawFeature;
|
||||
}
|
||||
|
||||
// Internet Explorer
|
||||
else if (window.attachEvent) // Must follow Opera check.
|
||||
else if (typeof window !== "undefined" && window.attachEvent) // Must follow Opera check.
|
||||
{
|
||||
PLATFORM_ENGINE = CPInternetExplorerBrowserEngine;
|
||||
|
||||
|
||||
// Features we can only be sure of with IE (no known independent tests)
|
||||
PLATFORM_FEATURES |= CPVMLFeature;
|
||||
PLATFORM_FEATURES |= CPJavascriptRemedialKeySupport;
|
||||
PLATFORM_FEATURES |= CPJavaScriptShadowFeature;
|
||||
|
||||
|
||||
PLATFORM_FEATURES |= CPOpacityRequiresFilterFeature;
|
||||
|
||||
PLATFORM_FEATURES &= ~CPInputTypeCanBeChangedFeature;
|
||||
@@ -103,7 +104,7 @@ else if (window.attachEvent) // Must follow Opera check.
|
||||
else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
|
||||
{
|
||||
PLATFORM_ENGINE = CPWebKitBrowserEngine;
|
||||
|
||||
|
||||
// Features we can only be sure of with WebKit (no known independent tests)
|
||||
PLATFORM_FEATURES |= CPCSSRGBAFeature;
|
||||
PLATFORM_FEATURES |= CPHTMLContentEditableFeature;
|
||||
@@ -114,7 +115,7 @@ else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
|
||||
PLATFORM_FEATURES |= CPJavascriptClipboardEventsFeature;
|
||||
PLATFORM_FEATURES |= CPJavascriptClipboardAccessFeature;
|
||||
PLATFORM_FEATURES |= CPJavaScriptShadowFeature;
|
||||
|
||||
|
||||
var versionStart = USER_AGENT.indexOf("AppleWebKit/") + "AppleWebKit/".length,
|
||||
versionEnd = USER_AGENT.indexOf(" ", versionStart),
|
||||
versionString = USER_AGENT.substring(versionStart, versionEnd),
|
||||
@@ -122,7 +123,7 @@ else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
|
||||
majorVersion = parseInt(versionString.substring(0, versionDivision)),
|
||||
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;
|
||||
|
||||
// FIXME this is a terrible hack to get around this bug:
|
||||
@@ -144,12 +145,12 @@ else if (USER_AGENT.indexOf("KHTML") != -1) // Must follow WebKit check.
|
||||
else if (USER_AGENT.indexOf("Gecko") !== -1) // Must follow KHTML check.
|
||||
{
|
||||
PLATFORM_ENGINE = CPGeckoBrowserEngine;
|
||||
|
||||
|
||||
PLATFORM_FEATURES |= CPJavaScriptCanvasDrawFeature;
|
||||
|
||||
|
||||
var index = USER_AGENT.indexOf("Firefox"),
|
||||
version = (index === -1) ? 2.0 : parseFloat(USER_AGENT.substring(index + "Firefox".length + 1));
|
||||
|
||||
|
||||
if (version >= 3.0)
|
||||
PLATFORM_FEATURES |= CPCSSRGBAFeature;
|
||||
|
||||
@@ -165,16 +166,16 @@ if (typeof document != "undefined")
|
||||
if (canvasElement && canvasElement.getContext)
|
||||
{
|
||||
PLATFORM_FEATURES |= CPHTMLCanvasFeature;
|
||||
|
||||
|
||||
// Detect Canvas setTransform/transform support
|
||||
var context = document.createElement("canvas").getContext("2d");
|
||||
|
||||
|
||||
if (context && context.setTransform && context.transform)
|
||||
PLATFORM_FEATURES |= CPJavaScriptCanvasTransformFeature;
|
||||
}
|
||||
|
||||
|
||||
var DOMElement = document.createElement("div");
|
||||
|
||||
|
||||
// Detect whether we have innerText or textContent (or neither)
|
||||
if (DOMElement.innerText != undefined)
|
||||
PLATFORM_FEATURES |= CPJavascriptInnerTextFeature;
|
||||
|
||||
+176
-64
@@ -23,9 +23,8 @@
|
||||
@import "CPFont.j"
|
||||
@import "CPShadow.j"
|
||||
@import "CPView.j"
|
||||
@import "CPKeyValueBinding.j"
|
||||
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
#include "Platform/Platform.h"
|
||||
|
||||
CPLeftTextAlignment = 0;
|
||||
CPRightTextAlignment = 1;
|
||||
@@ -75,7 +74,7 @@ CPControlTextDidEndEditingNotification = "CPControlTextDidEndEditingNotific
|
||||
|
||||
var CPControlBlackColor = [CPColor blackColor];
|
||||
|
||||
/*!
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPControl
|
||||
|
||||
@@ -84,7 +83,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
@implementation CPControl : CPView
|
||||
{
|
||||
id _value;
|
||||
|
||||
|
||||
// Target-Action Support
|
||||
id _target;
|
||||
SEL _action;
|
||||
@@ -126,16 +125,46 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
@"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
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_sendActionOn = CPLeftMouseUpMask;
|
||||
_trackingMouseDownFlags = 0;
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -180,15 +209,16 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
*/
|
||||
- (void)sendAction:(SEL)anAction to:(id)anObject
|
||||
{
|
||||
[self _reverseSetBinding];
|
||||
[CPApp sendAction:anAction to:anObject from:self];
|
||||
}
|
||||
|
||||
- (int)sendActionOn:(int)mask
|
||||
{
|
||||
var previousMask = _sendActionOn;
|
||||
|
||||
|
||||
_sendActionOn = mask;
|
||||
|
||||
|
||||
return previousMask;
|
||||
}
|
||||
|
||||
@@ -201,7 +231,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
{
|
||||
if (_toolTip == aToolTip)
|
||||
return;
|
||||
|
||||
|
||||
_toolTip = aToolTip;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
@@ -236,7 +266,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
// Some subclasses should redefine this with CPLeftMouseDraggedMask
|
||||
if (flag)
|
||||
_sendActionOn |= CPPeriodicMask;
|
||||
else
|
||||
else
|
||||
_sendActionOn &= ~CPPeriodicMask;
|
||||
}
|
||||
|
||||
@@ -248,16 +278,15 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
- (void)trackMouse:(CPEvent)anEvent
|
||||
{
|
||||
var type = [anEvent type],
|
||||
currentLocation = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||
currentLocation = [self convertPoint:[anEvent locationInWindow] fromView:nil],
|
||||
isWithinFrame = [self tracksMouseOutsideOfFrame] || CGRectContainsPoint([self bounds], currentLocation);
|
||||
|
||||
if (type === CPLeftMouseUp)
|
||||
{
|
||||
[self stopTracking:_previousTrackingLocation at:currentLocation mouseIsUp:YES];
|
||||
|
||||
|
||||
_trackingMouseDownFlags = 0;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (type === CPLeftMouseDown)
|
||||
@@ -271,20 +300,20 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
{
|
||||
if (!_trackingWasWithinFrame)
|
||||
_continuousTracking = [self startTrackingAt:currentLocation];
|
||||
|
||||
|
||||
else if (_continuousTracking)
|
||||
_continuousTracking = [self continueTracking:_previousTrackingLocation at:currentLocation];
|
||||
}
|
||||
else
|
||||
[self stopTracking:_previousTrackingLocation at:currentLocation mouseIsUp:NO];
|
||||
}
|
||||
|
||||
|
||||
[CPApp setTarget:self selector:@selector(trackMouse:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
|
||||
}
|
||||
|
||||
|
||||
if ((_sendActionOn & (1 << type)) && isWithinFrame)
|
||||
[self sendAction:_action to:_target];
|
||||
|
||||
|
||||
_trackingWasWithinFrame = isWithinFrame;
|
||||
_previousTrackingLocation = currentLocation;
|
||||
}
|
||||
@@ -298,13 +327,26 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (void)performClick:(id)sender
|
||||
- (void)performClick:(id)sender
|
||||
{
|
||||
if (![self isEnabled])
|
||||
return;
|
||||
|
||||
[self highlight:YES];
|
||||
[self setState:[self nextState]];
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
|
||||
[CPTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(unhighlightButtonTimerDidFinish:) userInfo:nil repeats:NO];
|
||||
|
||||
try
|
||||
{
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
[CPTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(unhighlightButtonTimerDidFinish:) userInfo:nil repeats:NO];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)unhighlightButtonTimerDidFinish:(id)sender
|
||||
@@ -320,7 +362,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
- (BOOL)startTrackingAt:(CGPoint)aPoint
|
||||
{
|
||||
[self highlight:YES];
|
||||
|
||||
|
||||
return (_sendActionOn & CPPeriodicMask) || (_sendActionOn & CPLeftMouseDraggedMask);
|
||||
}
|
||||
|
||||
@@ -338,7 +380,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
{
|
||||
if (![self isEnabled])
|
||||
return;
|
||||
|
||||
|
||||
[self trackMouse:anEvent];
|
||||
}
|
||||
|
||||
@@ -356,7 +398,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
- (void)setObjectValue:(id)anObject
|
||||
{
|
||||
_value = anObject;
|
||||
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
@@ -430,7 +472,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the receiver's int value
|
||||
Returns the receiver's string value
|
||||
*/
|
||||
- (CPString)stringValue
|
||||
{
|
||||
@@ -438,7 +480,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
}
|
||||
|
||||
/*!
|
||||
Set's the receiver's int value
|
||||
Set's the receiver's string value
|
||||
*/
|
||||
- (void)setStringValue:(CPString)anObject
|
||||
{
|
||||
@@ -485,54 +527,124 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
[self setStringValue:[sender stringValue]];
|
||||
}
|
||||
|
||||
- (void)textDidBeginEditing:(CPNotification)note
|
||||
- (void)textDidBeginEditing:(CPNotification)note
|
||||
{
|
||||
//this looks to prevent false propagation of notifications for other objects
|
||||
if([note object] != self)
|
||||
if ([note object] != self)
|
||||
return;
|
||||
|
||||
[[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
|
||||
if([note object] != self)
|
||||
if ([note object] != self)
|
||||
return;
|
||||
|
||||
[[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
|
||||
if([note object] != self)
|
||||
if ([note object] != self)
|
||||
return;
|
||||
|
||||
[self _reverseSetBinding];
|
||||
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidEndEditingNotification object:self userInfo:[CPDictionary dictionaryWithObject:[note object] forKey:"CPFieldEditor"]];
|
||||
}
|
||||
|
||||
#define BRIDGE(UPPERCASE, LOWERCASE, ATTRIBUTENAME) \
|
||||
/*! Sets the value for ATTRIBUTENAME */\
|
||||
- (void)set##UPPERCASE:(id)aValue\
|
||||
{\
|
||||
[self setValue:aValue forThemeAttribute:ATTRIBUTENAME];\
|
||||
}\
|
||||
/*! Returns the current value for ATTRIBUTENAME */\
|
||||
- (id)LOWERCASE\
|
||||
{\
|
||||
return [self valueForThemeAttribute:ATTRIBUTENAME];\
|
||||
- (void)setAlignment:(CPTextAlignment)alignment
|
||||
{
|
||||
[self setValue:alignment forThemeAttribute:@"alignment"];
|
||||
}
|
||||
|
||||
BRIDGE(Alignment, alignment, "alignment")
|
||||
BRIDGE(VerticalAlignment, verticalAlignment, "vertical-alignment")
|
||||
BRIDGE(LineBreakMode, lineBreakMode, "line-break-mode")
|
||||
BRIDGE(TextColor, textColor, "text-color")
|
||||
BRIDGE(Font, font, "font")
|
||||
BRIDGE(TextShadowColor, textShadowColor, "text-shadow-color")
|
||||
BRIDGE(TextShadowOffset, textShadowOffset, "text-shadow-offset")
|
||||
BRIDGE(ImagePosition, imagePosition, "image-position")
|
||||
BRIDGE(ImageScaling, imageScaling, "image-scaling")
|
||||
- (CPTextAlignment)alignment
|
||||
{
|
||||
return [self valueForThemeAttribute:@"alignment"];
|
||||
}
|
||||
|
||||
- (void)setVerticalAlignment:(CPTextVerticalAlignment)alignment
|
||||
{
|
||||
[self setValue:alignment forThemeAttribute:@"vertical-alignment"];
|
||||
}
|
||||
|
||||
- (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
|
||||
{
|
||||
@@ -570,7 +682,7 @@ BRIDGE(ImageScaling, imageScaling, "image-scaling")
|
||||
var CPControlValueKey = "CPControlValueKey",
|
||||
CPControlControlStateKey = @"CPControlControlStateKey",
|
||||
CPControlIsEnabledKey = "CPControlIsEnabledKey",
|
||||
|
||||
|
||||
CPControlTargetKey = "CPControlTargetKey",
|
||||
CPControlActionKey = "CPControlActionKey",
|
||||
CPControlSendActionOnKey = "CPControlSendActionOnKey",
|
||||
@@ -600,7 +712,7 @@ var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
|
||||
[self sendActionOn:[aCoder decodeIntForKey:CPControlSendActionOnKey]];
|
||||
[self setSendsActionOnEndEditing:[aCoder decodeBoolForKey:CPControlSendsActionOnEndEditingKey]];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -636,7 +748,7 @@ var _CPControlSizeIdentifiers = [],
|
||||
_CPControlSizeIdentifiers[CPRegularControlSize] = "Regular";
|
||||
_CPControlSizeIdentifiers[CPSmallControlSize] = "Small";
|
||||
_CPControlSizeIdentifiers[CPMiniControlSize] = "Mini";
|
||||
|
||||
|
||||
function _CPControlIdentifierForControlSize(aControlSize)
|
||||
{
|
||||
return _CPControlSizeIdentifiers[aControlSize];
|
||||
@@ -647,21 +759,21 @@ function _CPControlColorWithPatternImage(sizes, aClassName)
|
||||
var index = 1,
|
||||
count = arguments.length,
|
||||
identifier = "";
|
||||
|
||||
|
||||
for (; index < count; ++index)
|
||||
identifier += arguments[index];
|
||||
|
||||
|
||||
var color = _CPControlCachedColorWithPatternImages[identifier];
|
||||
|
||||
|
||||
if (!color)
|
||||
{
|
||||
var bundle = [CPBundle bundleForClass:[CPControl class]];
|
||||
|
||||
|
||||
color = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:aClassName + "/" + identifier + ".png"] size:sizes[identifier]]];
|
||||
|
||||
_CPControlCachedColorWithPatternImages[identifier] = color;
|
||||
}
|
||||
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
@@ -670,17 +782,17 @@ function _CPControlThreePartImagePattern(isVertical, sizes, aClassName)
|
||||
var index = 2,
|
||||
count = arguments.length,
|
||||
identifier = "";
|
||||
|
||||
|
||||
for (; index < count; ++index)
|
||||
identifier += arguments[index];
|
||||
|
||||
var color = _CPControlCachedThreePartImagePattern[identifier];
|
||||
|
||||
|
||||
if (!color)
|
||||
{
|
||||
var bundle = [CPBundle bundleForClass:[CPControl class]],
|
||||
path = aClassName + "/" + identifier;
|
||||
|
||||
|
||||
sizes = sizes[identifier];
|
||||
|
||||
color = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:[
|
||||
@@ -688,9 +800,9 @@ function _CPControlThreePartImagePattern(isVertical, sizes, aClassName)
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:path + "1.png"] size:sizes[1]],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:path + "2.png"] size:sizes[2]]
|
||||
] isVertical:isVertical]];
|
||||
|
||||
|
||||
_CPControlCachedThreePartImagePattern[identifier] = color;
|
||||
}
|
||||
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
//
|
||||
// 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
|
||||
+29
-20
@@ -24,7 +24,7 @@
|
||||
@import <Foundation/CPString.j>
|
||||
|
||||
|
||||
/*!
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPCookie
|
||||
CPCookie is the Cappuccino interface to a web browser cookie. You can set the name
|
||||
@@ -33,7 +33,7 @@
|
||||
{
|
||||
CPString _cookieName;
|
||||
CPString _cookieValue;
|
||||
|
||||
|
||||
CPString _expires;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
- (id)initWithName:(CPString)aName
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
_cookieName = aName;
|
||||
_cookieValue = [self _readCookieValue];
|
||||
|
||||
@@ -83,30 +83,39 @@
|
||||
*/
|
||||
- (void)setValue:(CPString)value expires:(CPDate)date domain:(CPString)domain
|
||||
{
|
||||
if(date)
|
||||
var expires = "; expires="+date.toGMTString();
|
||||
else
|
||||
if (date)
|
||||
var expires = "; expires=" + date.toGMTString();
|
||||
else
|
||||
var expires = "";
|
||||
|
||||
if(domain)
|
||||
domain = "; domain="+domain;
|
||||
else
|
||||
|
||||
if (domain)
|
||||
domain = "; domain=" + domain;
|
||||
else
|
||||
domain = "";
|
||||
|
||||
document.cookie = _cookieName+"="+value+expires+"; path=/"+domain;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
document.cookie = _cookieName+"="+value+expires+"; path=/"+domain;
|
||||
#else
|
||||
_cookieValue = value;
|
||||
_expires = expires;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (CPString)_readCookieValue
|
||||
{
|
||||
var nameEQ = _cookieName + "=";
|
||||
var ca = document.cookie.split(';');
|
||||
for(var i=0;i < ca.length;i++) {
|
||||
var c = ca[i];
|
||||
while (c.charAt(0)==' ') c = c.substring(1,c.length);
|
||||
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
|
||||
}
|
||||
return "";
|
||||
#if PLATFORM(DOM)
|
||||
var nameEQ = _cookieName + "=",
|
||||
ca = document.cookie.split(';');
|
||||
|
||||
for (var i = 0; i < ca.length; i++)
|
||||
{
|
||||
var c = ca[i];
|
||||
while (c.charAt(0) == ' ') c = c.substring(1, c.length);
|
||||
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
|
||||
}
|
||||
#endif
|
||||
return "";
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+15
-10
@@ -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
|
||||
*/
|
||||
|
||||
#include "Platform/Platform.h"
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
var currentCursor = nil,
|
||||
cursorStack = [],
|
||||
@@ -61,9 +61,9 @@ var currentCursor = nil,
|
||||
if (CPBrowserIsEngine(CPGeckoBrowserEngine))
|
||||
cursorURLFormat += ", default";
|
||||
}
|
||||
|
||||
|
||||
var url = [CPString stringWithFormat:cursorURLFormat, imageName];
|
||||
|
||||
|
||||
return [[CPCursor alloc] initWithCSSString:url];
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ var currentCursor = nil,
|
||||
{
|
||||
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)];
|
||||
|
||||
|
||||
return [CPCursor cursorWithCSSString:"s-resize"]; // WebKit | FF | opera
|
||||
}
|
||||
|
||||
@@ -167,18 +167,22 @@ var currentCursor = nil,
|
||||
{
|
||||
if (CPBrowserIsEngine(CPWebKitBrowserEngine))
|
||||
return [CPCursor cursorWithCSSString:@"-webkit-grab"];
|
||||
else if (CPBrowserIsEngine(CPGeckoBrowserEngine) || CPBrowserIsEngine(CPOperaBrowserEngine))
|
||||
else if (CPBrowserIsEngine(CPGeckoBrowserEngine))
|
||||
return [CPCursor cursorWithCSSString:@"-moz-grab"];
|
||||
else if (CPBrowserIsEngine(CPOperaBrowserEngine))
|
||||
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
|
||||
{
|
||||
if (CPBrowserIsEngine(CPWebKitBrowserEngine))
|
||||
return [CPCursor cursorWithCSSString:@"-webkit-grabbing"];
|
||||
else if (CPBrowserIsEngine(CPGeckoBrowserEngine))
|
||||
return [CPCursor cursorWithCSSString:@"-moz-grabbing"];
|
||||
|
||||
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)]; // WebKit only
|
||||
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)]; // WebKit || FF
|
||||
}
|
||||
|
||||
+ (CPCursor)disappearingItemCursor
|
||||
@@ -193,7 +197,7 @@ var currentCursor = nil,
|
||||
|
||||
+ (void)unhide
|
||||
{
|
||||
[self _setCursorCSS:[currentCursor _cssString]]
|
||||
[self _setCursorCSS:[currentCursor _cssString]];
|
||||
}
|
||||
|
||||
+ (void)setHiddenUntilMouseMoves:(BOOL)flag
|
||||
@@ -206,9 +210,10 @@ var currentCursor = nil,
|
||||
|
||||
- (id)initWithImage:(CPImage)image hotSpot:(CPPoint)hotSpot
|
||||
{
|
||||
return [self initWithCSSString:"url(" + [image filename] + ")"];
|
||||
return [self initWithCSSString:"url(" + [image filename] + "), auto"];
|
||||
}
|
||||
|
||||
|
||||
- (void)mouseEntered:(CPEvent)event
|
||||
{
|
||||
}
|
||||
@@ -219,7 +224,7 @@ var currentCursor = nil,
|
||||
|
||||
- (void)set
|
||||
{
|
||||
currentCursor = self;
|
||||
currentCursor = self;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
[[self class] _setCursorCSS:_cssString];
|
||||
|
||||
+55
-67
@@ -23,6 +23,7 @@
|
||||
@import <Foundation/CPString.j>
|
||||
@import <Foundation/CPArray.j>
|
||||
|
||||
@import "CPApplication.j"
|
||||
@import "CPResponder.j"
|
||||
@import "CPSavePanel.j"
|
||||
@import "CPViewController.j"
|
||||
@@ -82,7 +83,7 @@ CPDocumentDidFailToSaveNotification = @"CPDocumentDidFailToSaveNotification";
|
||||
|
||||
var CPDocumentUntitledCount = 0;
|
||||
|
||||
/*!
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPDocument
|
||||
|
||||
@@ -120,7 +121,7 @@ var CPDocumentUntitledCount = 0;
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_windowControllers = [];
|
||||
@@ -131,7 +132,7 @@ var CPDocumentUntitledCount = 0;
|
||||
|
||||
[self setNextResponder:CPApp];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -144,10 +145,10 @@ var CPDocumentUntitledCount = 0;
|
||||
- (id)initWithType:(CPString)aType error:({CPError})anError
|
||||
{
|
||||
self = [self init];
|
||||
|
||||
|
||||
if (self)
|
||||
[self setFileType:aType];
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -165,7 +166,7 @@ var CPDocumentUntitledCount = 0;
|
||||
- (id)initWithContentsOfURL:(CPURL)anAbsoluteURL ofType:(CPString)aType delegate:(id)aDelegate didReadSelector:(SEL)aDidReadSelector contextInfo:(id)aContextInfo
|
||||
{
|
||||
self = [self init];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
[self setFileURL:anAbsoluteURL];
|
||||
@@ -173,7 +174,7 @@ var CPDocumentUntitledCount = 0;
|
||||
|
||||
[self readFromURL:anAbsoluteURL ofType:aType delegate:aDelegate didReadSelector:aDidReadSelector contextInfo:aContextInfo];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -190,7 +191,7 @@ var CPDocumentUntitledCount = 0;
|
||||
- (id)initForURL:(CPURL)anAbsoluteURL withContentsOfURL:(CPURL)absoluteContentsURL ofType:(CPString)aType delegate:(id)aDelegate didReadSelector:(SEL)aDidReadSelector contextInfo:(id)aContextInfo
|
||||
{
|
||||
self = [self init];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
[self setFileURL:anAbsoluteURL];
|
||||
@@ -198,7 +199,7 @@ var CPDocumentUntitledCount = 0;
|
||||
|
||||
[self readFromURL:absoluteContentsURL ofType:aType delegate:aDelegate didReadSelector:aDidReadSelector contextInfo:aContextInfo];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -210,10 +211,10 @@ var CPDocumentUntitledCount = 0;
|
||||
@throws CPUnsupportedMethodException if this method hasn't been overriden by the subclass
|
||||
@return the document data
|
||||
*/
|
||||
- (CPData)dataOfType:(CPString)aType
|
||||
- (CPData)dataOfType:(CPString)aType error:({CPError})anError
|
||||
{
|
||||
[CPException raise:CPUnsupportedMethodException
|
||||
reason:"dataOfType: must be overridden by the document subclass."];
|
||||
reason:"dataOfType:error: must be overridden by the document subclass."];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -281,7 +282,7 @@ var CPDocumentUntitledCount = 0;
|
||||
{
|
||||
var view = [viewController view],
|
||||
viewFrame = [view frame];
|
||||
|
||||
|
||||
viewFrame.origin = CGPointMake(50, 50);
|
||||
|
||||
var theWindow = [[CPWindow alloc] initWithContentRect:viewFrame styleMask:CPTitledWindowMask | CPClosableWindowMask | CPMiniaturizableWindowMask | CPResizableWindowMask];
|
||||
@@ -381,14 +382,14 @@ var CPDocumentUntitledCount = 0;
|
||||
{
|
||||
if (_fileURL)
|
||||
return [_fileURL lastPathComponent];
|
||||
|
||||
|
||||
if (!_untitledDocumentIndex)
|
||||
_untitledDocumentIndex = ++CPDocumentUntitledCount;
|
||||
|
||||
if (_untitledDocumentIndex == 1)
|
||||
return @"Untitled";
|
||||
|
||||
return @"Untitled " + _untitledDocumentIndex;
|
||||
if (_untitledDocumentIndex == 1)
|
||||
return @"Untitled";
|
||||
|
||||
return @"Untitled " + _untitledDocumentIndex;
|
||||
}
|
||||
|
||||
- (CPString)viewCibName
|
||||
@@ -457,7 +458,7 @@ var CPDocumentUntitledCount = 0;
|
||||
return;
|
||||
|
||||
_fileURL = aFileURL;
|
||||
|
||||
|
||||
[_windowControllers makeObjectsPerformSelector:@selector(synchronizeWindowTitleWithDocumentName)];
|
||||
}
|
||||
|
||||
@@ -473,21 +474,8 @@ var CPDocumentUntitledCount = 0;
|
||||
*/
|
||||
- (void)saveToURL:(CPURL)anAbsoluteURL ofType:(CPString)aTypeName forSaveOperation:(CPSaveOperationType)aSaveOperation delegate:(id)aDelegate didSaveSelector:(SEL)aDidSaveSelector contextInfo:(id)aContextInfo
|
||||
{
|
||||
if (anAbsoluteURL.isLocalStorageURL())
|
||||
[[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;
|
||||
var data = [self dataOfType:[self fileType] error:nil],
|
||||
oldChangeCount = _changeCount;
|
||||
|
||||
_writeRequest = [CPURLRequest requestWithURL:anAbsoluteURL];
|
||||
|
||||
@@ -522,21 +510,21 @@ var CPDocumentUntitledCount = 0;
|
||||
// If we got this far and it wasn't an HTTP request, then everything is fine.
|
||||
if (![aResponse isKindOfClass:[CPHTTPURLResponse class]])
|
||||
return;
|
||||
|
||||
|
||||
var statusCode = [aResponse statusCode];
|
||||
|
||||
|
||||
// Nothing to do if everything is hunky dory.
|
||||
if (statusCode === 200)
|
||||
return;
|
||||
|
||||
|
||||
var session = aConnection.session;
|
||||
|
||||
|
||||
if (aConnection == _readConnection)
|
||||
{
|
||||
[aConnection cancel];
|
||||
|
||||
|
||||
alert("There was an error retrieving the document.");
|
||||
|
||||
|
||||
objj_msgSend(session.delegate, session.didReadSelector, self, NO, session.contextInfo);
|
||||
}
|
||||
else
|
||||
@@ -545,23 +533,23 @@ var CPDocumentUntitledCount = 0;
|
||||
if (statusCode == 409)
|
||||
{
|
||||
[aConnection cancel];
|
||||
|
||||
|
||||
if (confirm("There already exists a file with that name, would you like to overwrite it?"))
|
||||
{
|
||||
[_writeRequest setValue:@"true" forHTTPHeaderField:@"x-cappuccino-overwrite"];
|
||||
|
||||
|
||||
[aConnection start];
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
if (session.saveOperation != CPSaveToOperation)
|
||||
{
|
||||
_changeCount += session.changeCount;
|
||||
[_windowControllers makeObjectsPerformSelector:@selector(setDocumentEdited:) withObject:[self isDocumentEdited]];
|
||||
}
|
||||
|
||||
|
||||
_writeRequest = nil;
|
||||
|
||||
|
||||
objj_msgSend(session.delegate, session.didSaveSelector, self, NO, session.contextInfo);
|
||||
[self _sendDocumentSavedNotification:NO];
|
||||
}
|
||||
@@ -576,7 +564,7 @@ var CPDocumentUntitledCount = 0;
|
||||
- (void)connection:(CPURLConnection)aConnection didReceiveData:(CPString)aData
|
||||
{
|
||||
var session = aConnection.session;
|
||||
|
||||
|
||||
// READ
|
||||
if (aConnection == _readConnection)
|
||||
{
|
||||
@@ -588,9 +576,9 @@ var CPDocumentUntitledCount = 0;
|
||||
{
|
||||
if (session.saveOperation != CPSaveToOperation)
|
||||
[self setFileURL:session.absoluteURL];
|
||||
|
||||
|
||||
_writeRequest = nil;
|
||||
|
||||
|
||||
objj_msgSend(session.delegate, session.didSaveSelector, self, YES, session.contextInfo);
|
||||
[self _sendDocumentSavedNotification:YES];
|
||||
}
|
||||
@@ -603,17 +591,17 @@ var CPDocumentUntitledCount = 0;
|
||||
- (void)connection:(CPURLConnection)aConnection didFailWithError:(CPError)anError
|
||||
{
|
||||
var session = aConnection.session;
|
||||
|
||||
|
||||
if (_readConnection == aConnection)
|
||||
objj_msgSend(session.delegate, session.didReadSelector, self, NO, session.contextInfo);
|
||||
|
||||
|
||||
else
|
||||
{
|
||||
{
|
||||
if (session.saveOperation != CPSaveToOperation)
|
||||
{
|
||||
_changeCount += session.changeCount;
|
||||
[_windowControllers makeObjectsPerformSelector:@selector(setDocumentEdited:) withObject:[self isDocumentEdited]];
|
||||
}
|
||||
}
|
||||
|
||||
_writeRequest = nil;
|
||||
|
||||
@@ -656,9 +644,9 @@ var CPDocumentUntitledCount = 0;
|
||||
else if (aChangeType == CPChangeCleared)
|
||||
_changeCount = 0;
|
||||
/*else if (aChangeType == CPCHangeReadOtherContents)
|
||||
|
||||
else if (aChangeType == CPChangeAutosaved)*/
|
||||
|
||||
|
||||
else if (aChangeType == CPChangeAutosaved)*/
|
||||
|
||||
[_windowControllers makeObjectsPerformSelector:@selector(setDocumentEdited:) withObject:[self isDocumentEdited]];
|
||||
}
|
||||
|
||||
@@ -698,9 +686,9 @@ var CPDocumentUntitledCount = 0;
|
||||
{
|
||||
if (_hasUndoManager == aFlag)
|
||||
return;
|
||||
|
||||
|
||||
_hasUndoManager = aFlag;
|
||||
|
||||
|
||||
if (!_hasUndoManager)
|
||||
[self setUndoManager:nil];
|
||||
}
|
||||
@@ -709,7 +697,7 @@ var CPDocumentUntitledCount = 0;
|
||||
- (void)_undoManagerWillCloseGroup:(CPNotification)aNotification
|
||||
{
|
||||
var undoManager = [aNotification object];
|
||||
|
||||
|
||||
if ([undoManager isUndoing] || [undoManager isRedoing])
|
||||
return;
|
||||
|
||||
@@ -736,13 +724,13 @@ var CPDocumentUntitledCount = 0;
|
||||
- (void)setUndoManager:(CPUndoManager)anUndoManager
|
||||
{
|
||||
var defaultCenter = [CPNotificationCenter defaultCenter];
|
||||
|
||||
|
||||
if (_undoManager)
|
||||
{
|
||||
[defaultCenter removeObserver:self
|
||||
name:CPUndoManagerDidUndoChangeNotification
|
||||
object:_undoManager];
|
||||
|
||||
|
||||
[defaultCenter removeObserver:self
|
||||
name:CPUndoManagerDidRedoChangeNotification
|
||||
object:_undoManager];
|
||||
@@ -751,17 +739,17 @@ var CPDocumentUntitledCount = 0;
|
||||
name:CPUndoManagerWillCloseUndoGroupNotification
|
||||
object:_undoManager];
|
||||
}
|
||||
|
||||
|
||||
_undoManager = anUndoManager;
|
||||
|
||||
|
||||
if (_undoManager)
|
||||
{
|
||||
|
||||
|
||||
[defaultCenter addObserver:self
|
||||
selector:@selector(_undoManagerDidUndoChange:)
|
||||
name:CPUndoManagerDidUndoChangeNotification
|
||||
object:_undoManager];
|
||||
|
||||
|
||||
[defaultCenter addObserver:self
|
||||
selector:@selector(_undoManagerDidRedoChange:)
|
||||
name:CPUndoManagerDidRedoChangeNotification
|
||||
@@ -787,7 +775,7 @@ var CPDocumentUntitledCount = 0;
|
||||
|
||||
return _undoManager;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Implemented as a delegate of a CPWindow
|
||||
@ignore
|
||||
@@ -816,7 +804,7 @@ var CPDocumentUntitledCount = 0;
|
||||
[[CPNotificationCenter defaultCenter]
|
||||
postNotificationName:CPDocumentWillSaveNotification
|
||||
object:self];
|
||||
|
||||
|
||||
[self saveToURL:_fileURL ofType:[self fileType] forSaveOperation:CPSaveOperation delegate:delegate didSaveSelector:didSaveSelector contextInfo:contextInfo];
|
||||
}
|
||||
else
|
||||
@@ -874,7 +862,7 @@ var CPDocumentUntitledCount = 0;
|
||||
[[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))
|
||||
[self canCloseDocumentWithDelegate:self shouldCloseSelector:@selector(_document:shouldClose:context:) contextInfo:{delegate:delegate, selector:selector, context:info}];
|
||||
@@ -891,7 +879,7 @@ var CPDocumentUntitledCount = 0;
|
||||
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])
|
||||
return [aDelegate respondsToSelector:aSelector] && objj_msgSend(aDelegate, aSelector, self, YES, context);
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
var CPSharedDocumentController = nil;
|
||||
|
||||
/*!
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPDocumentController
|
||||
This class is responsible for managing an application's open documents.
|
||||
@@ -38,11 +38,10 @@ var CPSharedDocumentController = nil;
|
||||
{
|
||||
CPArray _documents;
|
||||
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.
|
||||
@return a CPDocumentController
|
||||
*/
|
||||
@@ -50,7 +49,7 @@ var CPSharedDocumentController = nil;
|
||||
{
|
||||
if (!CPSharedDocumentController)
|
||||
[[self alloc] init];
|
||||
|
||||
|
||||
return CPSharedDocumentController;
|
||||
}
|
||||
|
||||
@@ -63,27 +62,11 @@ var CPSharedDocumentController = nil;
|
||||
|
||||
if (self)
|
||||
{
|
||||
_documents = [[CPArray alloc] init];
|
||||
|
||||
if (!CPSharedDocumentController)
|
||||
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"];
|
||||
}
|
||||
return self;
|
||||
@@ -102,16 +85,16 @@ var CPSharedDocumentController = nil;
|
||||
{
|
||||
var index = 0,
|
||||
count = [_documents count];
|
||||
|
||||
for (; index < count; ++index)
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var theDocument = _documents[index];
|
||||
|
||||
if ([[theDocument fileURL] isEqual:aURL])
|
||||
return theDocument;
|
||||
|
||||
if ([[theDocument fileURL] isEqual:aURL])
|
||||
return theDocument;
|
||||
}
|
||||
|
||||
return nil;
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -122,10 +105,10 @@ var CPSharedDocumentController = nil;
|
||||
- (void)openUntitledDocumentOfType:(CPString)aType display:(BOOL)shouldDisplay
|
||||
{
|
||||
var theDocument = [self makeUntitledDocumentOfType:aType error:nil];
|
||||
|
||||
|
||||
if (theDocument)
|
||||
[self addDocument:theDocument];
|
||||
|
||||
|
||||
if (shouldDisplay)
|
||||
{
|
||||
[theDocument makeWindowControllers];
|
||||
@@ -227,7 +210,7 @@ var CPSharedDocumentController = nil;
|
||||
return;
|
||||
|
||||
[aDocument makeWindowControllers];
|
||||
|
||||
|
||||
if ([aContextInfo objectForKey:@"shouldDisplay"])
|
||||
[aDocument showWindows];
|
||||
}
|
||||
@@ -236,12 +219,12 @@ var CPSharedDocumentController = nil;
|
||||
Opens a new document in the application.
|
||||
@param aSender the requesting object
|
||||
*/
|
||||
- (@action)newDocument:(id)aSender
|
||||
- (CFAction)newDocument:(id)aSender
|
||||
{
|
||||
[self openUntitledDocumentOfType:[[_documentTypes objectAtIndex:0] objectForKey:@"CPBundleTypeName"] display:YES];
|
||||
}
|
||||
|
||||
-(void)openDocument:(id)aSender
|
||||
- (void)openDocument:(id)aSender
|
||||
{
|
||||
var openPanel = [CPOpenPanel openPanel];
|
||||
|
||||
@@ -293,17 +276,17 @@ var CPSharedDocumentController = nil;
|
||||
{
|
||||
var index = 0,
|
||||
count = _documentTypes.length,
|
||||
|
||||
|
||||
extension = [[anAbsoluteURL pathExtension] lowercaseString],
|
||||
starType = nil;
|
||||
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var documentType = _documentTypes[index],
|
||||
extensions = [documentType objectForKey:@"CFBundleTypeExtensions"],
|
||||
extensionIndex = 0,
|
||||
extensionCount = extensions.length;
|
||||
|
||||
|
||||
for (; extensionIndex < extensionCount; ++extensionIndex)
|
||||
{
|
||||
var thisExtension = [extensions[extensionIndex] lowercaseString];
|
||||
@@ -329,11 +312,11 @@ var CPSharedDocumentController = nil;
|
||||
for (;i < count; ++i)
|
||||
{
|
||||
var documentType = _documentTypes[i];
|
||||
|
||||
|
||||
if ([documentType objectForKey:@"CPBundleTypeName"] == aType)
|
||||
return documentType;
|
||||
}
|
||||
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
@@ -353,7 +336,7 @@ var CPSharedDocumentController = nil;
|
||||
|
||||
@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 = {
|
||||
delegate: aDelegate,
|
||||
@@ -472,41 +455,3 @@ var CPSharedDocumentController = nil;
|
||||
}
|
||||
|
||||
@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
|
||||
|
||||
+100
-38
@@ -20,13 +20,12 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <AppKit/CPView.j>
|
||||
@import <AppKit/CPEvent.j>
|
||||
@import <AppKit/CPPasteboard.j>
|
||||
@import <AppKit/CPImageView.j>
|
||||
|
||||
#import "CoreGraphics/CGGeometry.h"
|
||||
#import "Platform/Platform.h"
|
||||
@import "CPApplication.j"
|
||||
@import "CPEvent.j"
|
||||
@import "CPImageView.j"
|
||||
@import "CPPasteboard.j"
|
||||
@import "CPView.j"
|
||||
@import "CPWindow.j"
|
||||
|
||||
|
||||
CPDragOperationNone = 0,
|
||||
@@ -40,29 +39,10 @@ CPDragOperationEvery = -1;
|
||||
|
||||
#define DRAGGING_WINDOW(anObject) ([anObject isKindOfClass:[CPWindow class]] ? anObject : [anObject window])
|
||||
|
||||
var CPDragServerPreviousEvent = nil,
|
||||
CPDragServerAutoscrollInterval = nil;
|
||||
/*
|
||||
var CPDragServerAutoscroll = function()
|
||||
{
|
||||
[CPDragServerSource autoscroll:CPDragServerPreviousEvent];
|
||||
}
|
||||
var CPDragServerPreviousEvent = nil,
|
||||
CPDragServerPeriodicUpdateInterval = 0.05;
|
||||
|
||||
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 CPSharedDragServer = nil;
|
||||
|
||||
var CPDragServerSource = nil;
|
||||
var CPDragServerDraggingInfo = nil;
|
||||
@@ -150,10 +130,13 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
||||
|
||||
CGPoint _draggingLocation;
|
||||
id _draggingDestination;
|
||||
BOOL _draggingDestinationWantsPeriodicUpdates;
|
||||
|
||||
CGPoint _startDragLocation;
|
||||
BOOL _shouldSlideBack;
|
||||
unsigned _dragOperation;
|
||||
|
||||
CPTimer _draggingUpdateTimer;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -234,6 +217,9 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
||||
|
||||
- (CPDragOperation)draggingUpdatedInPlatformWindow:(CPPlatformWindow)aPlatformWindow location:(CGPoint)aLocation
|
||||
{
|
||||
[_draggingUpdateTimer invalidate];
|
||||
_draggingUpdateTimer = nil;
|
||||
|
||||
var dragOperation = CPDragOperationCopy;
|
||||
// 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]];
|
||||
@@ -243,25 +229,89 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
||||
|
||||
if(draggingDestination !== _draggingDestination)
|
||||
{
|
||||
if (_draggingDestination && [_draggingDestination respondsToSelector:@selector(draggingExited:)])
|
||||
if ([_draggingDestination respondsToSelector:@selector(draggingExited:)])
|
||||
[_draggingDestination draggingExited:CPDragServerDraggingInfo];
|
||||
|
||||
_draggingDestination = draggingDestination;
|
||||
|
||||
if (_draggingDestination && [_draggingDestination respondsToSelector:@selector(draggingEntered:)])
|
||||
if ([_draggingDestination respondsToSelector:@selector(wantsPeriodicDraggingUpdates)])
|
||||
_draggingDestinationWantsPeriodicUpdates = [_draggingDestination wantsPeriodicDraggingUpdates];
|
||||
else
|
||||
_draggingDestinationWantsPeriodicUpdates = YES;
|
||||
|
||||
if ([_draggingDestination respondsToSelector:@selector(draggingEntered:)])
|
||||
dragOperation = [_draggingDestination draggingEntered:CPDragServerDraggingInfo];
|
||||
}
|
||||
else if (_draggingDestination && [_draggingDestination respondsToSelector:@selector(draggingUpdated:)])
|
||||
else if ([_draggingDestination respondsToSelector:@selector(draggingUpdated:)])
|
||||
dragOperation = [_draggingDestination draggingUpdated:CPDragServerDraggingInfo];
|
||||
|
||||
if (!_draggingDestination)
|
||||
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;
|
||||
}
|
||||
|
||||
- (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
|
||||
{
|
||||
[_draggingUpdateTimer invalidate];
|
||||
_draggingUpdateTimer = nil;
|
||||
|
||||
[_draggedView removeFromSuperview];
|
||||
|
||||
if (![CPPlatform supportsDragAndDrop])
|
||||
@@ -277,8 +327,8 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
||||
|
||||
- (void)performDragOperationInPlatformWindow:(CPPlatformWindow)aPlatformWindow
|
||||
{
|
||||
if (_draggingDestination &&
|
||||
(![_draggingDestination respondsToSelector:@selector(prepareForDragOperation:)] || [_draggingDestination prepareForDragOperation:CPDragServerDraggingInfo]) &&
|
||||
if (_draggingDestination &&
|
||||
(![_draggingDestination respondsToSelector:@selector(prepareForDragOperation:)] || [_draggingDestination prepareForDragOperation:CPDragServerDraggingInfo]) &&
|
||||
(![_draggingDestination respondsToSelector:@selector(performDragOperation:)] || [_draggingDestination performDragOperation:CPDragServerDraggingInfo]) &&
|
||||
[_draggingDestination respondsToSelector:@selector(concludeDragOperation:)])
|
||||
[_draggingDestination concludeDragOperation:CPDragServerDraggingInfo];
|
||||
@@ -404,13 +454,25 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
||||
// Stop tracking events.
|
||||
return;
|
||||
}
|
||||
|
||||
[self draggingSourceUpdatedWithGlobalLocation:platformWindowLocation];
|
||||
_dragOperation = [self draggingUpdatedInPlatformWindow:platformWindow location:platformWindowLocation];
|
||||
else if (type === CPKeyDown)
|
||||
{
|
||||
var keyCode = [anEvent keyCode];
|
||||
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.
|
||||
[CPApp setTarget:self selector:@selector(trackDragging:)
|
||||
forNextEventMatchingMask:CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask
|
||||
forNextEventMatchingMask:CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPKeyDownMask
|
||||
untilDate:nil inMode:0 dequeue:NO];
|
||||
}
|
||||
|
||||
|
||||
+165
-38
@@ -21,8 +21,7 @@
|
||||
*/
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
@import "CPText.j"
|
||||
|
||||
|
||||
CPLeftMouseDown = 1;
|
||||
@@ -41,7 +40,7 @@ CPAppKitDefined = 13;
|
||||
CPSystemDefined = 14;
|
||||
CPApplicationDefined = 15;
|
||||
CPPeriodic = 16;
|
||||
CPCursorUpdate = 17;
|
||||
CPCursorUpdate = 17;
|
||||
CPScrollWheel = 22;
|
||||
CPOtherMouseDown = 25;
|
||||
CPOtherMouseUp = 26;
|
||||
@@ -52,8 +51,7 @@ CPTouchStart = 28;
|
||||
CPTouchMove = 29;
|
||||
CPTouchEnd = 30;
|
||||
CPTouchCancel = 31;
|
||||
|
||||
|
||||
|
||||
CPAlphaShiftKeyMask = 1 << 16;
|
||||
CPShiftKeyMask = 1 << 17;
|
||||
CPControlKeyMask = 1 << 18;
|
||||
@@ -87,26 +85,102 @@ CPPeriodicMask = 1 << CPPeriodic;
|
||||
CPScrollWheelMask = 1 << CPScrollWheel;
|
||||
CPAnyEventMask = 0xffffffff;
|
||||
|
||||
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";
|
||||
CPUpArrowFunctionKey = "\uF700";
|
||||
CPDownArrowFunctionKey = "\uF701";
|
||||
CPLeftArrowFunctionKey = "\uF702";
|
||||
CPRightArrowFunctionKey = "\uF703";
|
||||
CPF1FunctionKey = "\uF704";
|
||||
CPF2FunctionKey = "\uF705";
|
||||
CPF3FunctionKey = "\uF706";
|
||||
CPF4FunctionKey = "\uF707";
|
||||
CPF5FunctionKey = "\uF708";
|
||||
CPF6FunctionKey = "\uF709";
|
||||
CPF7FunctionKey = "\uF70A";
|
||||
CPF8FunctionKey = "\uF70B";
|
||||
CPF9FunctionKey = "\uF70C";
|
||||
CPF10FunctionKey = "\uF70D";
|
||||
CPF11FunctionKey = "\uF70E";
|
||||
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,
|
||||
_CPEventPeriodicEventTimer = nil;
|
||||
_CPEventPeriodicEventTimer = nil,
|
||||
_CPEventUpperCaseRegex = new RegExp("[A-Z]");
|
||||
|
||||
/*!
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPEvent
|
||||
CPEvent encapsulates the details of a Cappuccino keyboard or mouse event.
|
||||
@@ -155,7 +229,7 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
characters:(CPString)characters charactersIgnoringModifiers:(CPString)unmodCharacters isARepeat:(BOOL)repeatKey keyCode:(unsigned short)code
|
||||
{
|
||||
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];
|
||||
}
|
||||
|
||||
@@ -173,7 +247,7 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
@throws CPInternalInconsistencyException if an invalid event type is provided
|
||||
@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
|
||||
eventNumber:(int)anEventNumber clickCount:(int)aClickCount pressure:(float)aPressure
|
||||
{
|
||||
@@ -204,12 +278,12 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
}
|
||||
|
||||
/* @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
|
||||
eventNumber:(int)anEventNumber clickCount:(int)aClickCount pressure:(float)aPressure
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_type = anEventType;
|
||||
@@ -222,7 +296,7 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
_pressure = aPressure;
|
||||
_window = [CPApp windowWithWindowNumber:aWindowNumber];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -232,7 +306,7 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
characters:(CPString)characters charactersIgnoringModifiers:(CPString)unmodCharacters isARepeat:(BOOL)isARepeat keyCode:(unsigned short)code
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_type = anEventType;
|
||||
@@ -246,7 +320,7 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
_keyCode = code;
|
||||
_windowNumber = aWindowNumber;
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -256,7 +330,7 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
subtype:(short)aSubtype data1:(int)aData1 data2:(int)aData2
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_type = anEventType;
|
||||
@@ -267,7 +341,7 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
_subtype = aSubtype;
|
||||
_data1 = aData1;
|
||||
_data2 = aData2;
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
@@ -445,23 +519,76 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
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
|
||||
{
|
||||
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?
|
||||
return _type === CPKeyDown &&
|
||||
_modifierFlags & (CPCommandKeyMask | CPControlKeyMask) &&
|
||||
[_characters length] > 0;
|
||||
return NO;
|
||||
}
|
||||
|
||||
/*!
|
||||
Generates periodic events every \c aPeriod seconds.
|
||||
Gene rates periodic events every \c aPeriod seconds.
|
||||
@param aDelay the number of seconds before the first event
|
||||
@param aPeriod the length of time in seconds between successive events
|
||||
*/
|
||||
+ (void)startPeriodicEventsAfterDelay:(CPTimeInterval)aDelay withPeriod:(CPTimeInterval)aPeriod
|
||||
{
|
||||
_CPEventPeriodicEventPeriod = aPeriod;
|
||||
|
||||
|
||||
// FIXME: OH TIMERS!!!
|
||||
_CPEventPeriodicEventTimer = window.setTimeout(function() { _CPEventPeriodicEventTimer = window.setInterval(_CPEventFirePeriodEvent, aPeriod * 1000.0); }, aDelay * 1000.0);
|
||||
}
|
||||
@@ -473,9 +600,9 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
{
|
||||
if (_CPEventPeriodicEventTimer === nil)
|
||||
return;
|
||||
|
||||
|
||||
window.clearTimeout(_CPEventPeriodicEventTimer);
|
||||
|
||||
|
||||
_CPEventPeriodicEventTimer = nil;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPFlashMovie
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
@import "CPFlashMovie.j"
|
||||
@import "CPView.j"
|
||||
|
||||
#include "Platform/Platform.h"
|
||||
|
||||
var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
|
||||
|
||||
|
||||
+73
-8
@@ -20,6 +20,12 @@
|
||||
* 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 = {},
|
||||
_CPFontSystemFontFace = @"Arial, sans-serif",
|
||||
_CPWrapRegExp = new RegExp("\\s*,\\s*", "g");
|
||||
@@ -28,7 +34,7 @@ var _CPFonts = {},
|
||||
#define _CPCreateCSSString(aName, aSize, isBold) (isBold ? @"bold " : @"") + ROUND(aSize) + @"px " + ((aName === _CPFontSystemFontFace) ? aName : (@"\"" + aName.replace(_CPWrapRegExp, '", "') + @"\", " + _CPFontSystemFontFace))
|
||||
#define _CPCachedFont(aName, aSize, isBold) _CPFonts[_CPCreateCSSString(aName, aSize, isBold)]
|
||||
|
||||
/*!
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPFont
|
||||
|
||||
@@ -38,11 +44,22 @@ var _CPFonts = {},
|
||||
{
|
||||
CPString _name;
|
||||
float _size;
|
||||
float _ascender;
|
||||
float _descender;
|
||||
float _lineHeight;
|
||||
BOOL _isBold;
|
||||
|
||||
|
||||
CPString _cssString;
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
var systemFont = [[CPBundle bundleForClass:[CPView class]] objectForInfoDictionaryKey:"CPSystemFontFace"];
|
||||
|
||||
if (systemFont)
|
||||
_CPFontSystemFontFace = systemFont;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a font with the specified name and size.
|
||||
@param aName the name of the font
|
||||
@@ -89,25 +106,64 @@ var _CPFonts = {},
|
||||
@ignore
|
||||
*/
|
||||
- (id)_initWithName:(CPString)aName size:(float)aSize bold:(BOOL)isBold
|
||||
{
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_name = aName;
|
||||
_size = aSize;
|
||||
_ascender = 0;
|
||||
_descender = 0;
|
||||
_lineHeight = 0;
|
||||
_isBold = isBold;
|
||||
|
||||
|
||||
_cssString = _CPCreateCSSString(_name, _size, _isBold);
|
||||
|
||||
|
||||
_CPFonts[_cssString] = self;
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the font size (in points)
|
||||
Returns the distance of the longest ascender's top y-coordinate from the baseline (in CSS px)
|
||||
*/
|
||||
- (float)ascender
|
||||
{
|
||||
if (!_ascender)
|
||||
[self _getMetrics];
|
||||
|
||||
return _ascender;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the bottom y coordinate (in CSS px), offset from the baseline, of the receiver's longest descender.
|
||||
Thus, if the longest descender extends 2 points below the baseline, descender will return –2.
|
||||
*/
|
||||
- (float)descender
|
||||
{
|
||||
if (!_descender)
|
||||
[self _getMetrics];
|
||||
|
||||
return _descender;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the default line height.
|
||||
|
||||
NOTE: This was moved from NSFont to NSLayoutManager in Cocoa, but since there is no CPLayoutManager, it has been kept here.
|
||||
*/
|
||||
- (float)defaultLineHeightForFont
|
||||
{
|
||||
if (!_lineHeight)
|
||||
[self _getMetrics];
|
||||
|
||||
return _lineHeight;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the font size (in CSS px)
|
||||
*/
|
||||
- (float)size
|
||||
{
|
||||
@@ -140,6 +196,15 @@ var _CPFonts = {},
|
||||
return [CPString stringWithFormat:@"%@ %@ %f pt.", [super description], [self familyName], [self size]];
|
||||
}
|
||||
|
||||
- (void)_getMetrics
|
||||
{
|
||||
var metrics = [CPString metricsOfFont:self];
|
||||
|
||||
_ascender = [metrics objectForKey:@"ascender"];
|
||||
_descender = [metrics objectForKey:@"descender"];
|
||||
_lineHeight = [metrics objectForKey:@"lineHeight"];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPFontNameKey = @"CPFontNameKey",
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
@import <AppKit/CPFont.j>
|
||||
@import "CPFont.j"
|
||||
|
||||
|
||||
var CPSharedFontManager = nil,
|
||||
|
||||
+29
-15
@@ -70,7 +70,7 @@ function CPPointMake(x, y)
|
||||
*/
|
||||
function CPRectInset(aRect, dX, dY)
|
||||
{
|
||||
return CPRectMake( aRect.origin.x + dX, aRect.origin.y + dY,
|
||||
return CPRectMake( aRect.origin.x + dX, aRect.origin.y + dY,
|
||||
aRect.size.width - 2 * dX, aRect.size.height - 2*dY);
|
||||
}
|
||||
|
||||
@@ -96,13 +96,13 @@ function CPRectIntegral(aRect)
|
||||
function CPRectIntersection(lhsRect, rhsRect)
|
||||
{
|
||||
var intersection = CPRectMake(
|
||||
Math.max(CPRectGetMinX(lhsRect), CPRectGetMinX(rhsRect)),
|
||||
Math.max(CPRectGetMinY(lhsRect), CPRectGetMinY(rhsRect)),
|
||||
Math.max(CPRectGetMinX(lhsRect), CPRectGetMinX(rhsRect)),
|
||||
Math.max(CPRectGetMinY(lhsRect), CPRectGetMinY(rhsRect)),
|
||||
0, 0);
|
||||
|
||||
|
||||
intersection.size.width = Math.min(CPRectGetMaxX(lhsRect), CPRectGetMaxX(rhsRect)) - CPRectGetMinX(intersection);
|
||||
intersection.size.height = Math.min(CPRectGetMaxY(lhsRect), CPRectGetMaxY(rhsRect)) - CPRectGetMinY(intersection);
|
||||
|
||||
|
||||
return CPRectIsEmpty(intersection) ? CPRectMakeZero() : intersection;
|
||||
}
|
||||
|
||||
@@ -160,13 +160,13 @@ function CPRectStandardize(aRect)
|
||||
standardized.origin.x += width;
|
||||
standardized.size.width = -width;
|
||||
}
|
||||
|
||||
|
||||
if (height < 0.0)
|
||||
{
|
||||
standardized.origin.y += height;
|
||||
standardized.size.height = -height;
|
||||
}
|
||||
|
||||
|
||||
return standardized;
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ function CPRectUnion(lhsRect, rhsRect)
|
||||
minY = Math.min(CPRectGetMinY(lhsRect), CPRectGetMinY(rhsRect)),
|
||||
maxX = Math.max(CPRectGetMaxX(lhsRect), CPRectGetMaxX(rhsRect)),
|
||||
maxY = Math.max(CPRectGetMaxY(lhsRect), CPRectGetMaxY(rhsRect));
|
||||
|
||||
|
||||
return CPRectMake(minX, minY, maxX - minX, maxY - minY);
|
||||
}
|
||||
|
||||
@@ -222,8 +222,8 @@ function CPRectContainsPoint(aRect, aPoint)
|
||||
{
|
||||
return aPoint.x >= CPRectGetMinX(aRect) &&
|
||||
aPoint.y >= CPRectGetMinY(aRect) &&
|
||||
aPoint.x < CPRectGetMaxX(aRect) &&
|
||||
aPoint.y < CPRectGetMaxY(aRect);
|
||||
aPoint.x < CPRectGetMaxX(aRect) &&
|
||||
aPoint.y < CPRectGetMaxY(aRect);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -261,7 +261,7 @@ function CPPointEqualToPoint(lhsPoint, rhsPoint)
|
||||
*/
|
||||
function CPRectEqualToRect(lhsRect, rhsRect)
|
||||
{
|
||||
return CPPointEqualToPoint(lhsRect.origin, rhsRect.origin) &&
|
||||
return CPPointEqualToPoint(lhsRect.origin, rhsRect.origin) &&
|
||||
CPSizeEqualToSize(lhsRect.size, rhsRect.size);
|
||||
}
|
||||
|
||||
@@ -380,6 +380,20 @@ function CPRectIsNull(aRect)
|
||||
return aRect.size.width <= 0.0 || aRect.size.height <= 0.0;
|
||||
}
|
||||
|
||||
/*!
|
||||
Creates two rectangles -- slice and rem -- from inRect, by dividing inRect
|
||||
with a line that's parallel to the side of inRect specified by edge.
|
||||
The size of slice is determined by amount, which specifies the distance from edge.
|
||||
|
||||
slice and rem must not be NULL.
|
||||
|
||||
@group CGRect
|
||||
*/
|
||||
function CPDivideRect(inRect, slice, rem, amount, edge)
|
||||
{
|
||||
CGRectDivide(inRect, slice, rem, amount, edge);
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns \c YES if the two CGSizes are identical.
|
||||
@group CGSize
|
||||
@@ -434,7 +448,7 @@ function CPStringFromRect(aRect)
|
||||
function CPPointFromString(aString)
|
||||
{
|
||||
var comma = aString.indexOf(',');
|
||||
|
||||
|
||||
return { x:parseFloat(aString.substr(1, comma - 1), 10), y:parseFloat(aString.substring(comma + 1, aString.length), 10) };
|
||||
}
|
||||
|
||||
@@ -447,7 +461,7 @@ function CPPointFromString(aString)
|
||||
function CPSizeFromString(aString)
|
||||
{
|
||||
var comma = aString.indexOf(',');
|
||||
|
||||
|
||||
return { width:parseFloat(aString.substr(1, comma - 1), 10), height:parseFloat(aString.substring(comma + 1, aString.length), 10) };
|
||||
}
|
||||
|
||||
@@ -460,7 +474,7 @@ function CPSizeFromString(aString)
|
||||
function CPRectFromString(aString)
|
||||
{
|
||||
var comma = aString.indexOf(',', aString.indexOf(',') + 1);
|
||||
|
||||
|
||||
return { origin:CPPointFromString(aString.substr(1, comma - 1)), size:CPSizeFromString(aString.substring(comma + 2, aString.length)) };
|
||||
}
|
||||
|
||||
@@ -504,6 +518,6 @@ function CPPointMakeZero()
|
||||
return CPPointMake(0, 0, 0);
|
||||
}
|
||||
|
||||
/*!
|
||||
/*!
|
||||
@}
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
@@ -20,6 +20,11 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
@import "CGContext.j"
|
||||
|
||||
|
||||
var CPGraphicsContextCurrent = nil;
|
||||
|
||||
/*!
|
||||
|
||||
+9
-6
@@ -28,8 +28,6 @@
|
||||
|
||||
@import "CPGeometry.j"
|
||||
|
||||
#include "Platform/Platform.h"
|
||||
|
||||
|
||||
CPImageLoadStatusInitialized = 0;
|
||||
CPImageLoadStatusLoading = 1;
|
||||
@@ -193,6 +191,9 @@ function CPAppKitImage(aFilename, aSize)
|
||||
|
||||
var imageOrSize = AppKitImageForNames[aName];
|
||||
|
||||
if (!imageOrSize)
|
||||
return nil;
|
||||
|
||||
if (!imageOrSize.isa)
|
||||
{
|
||||
imageOrSize = CPAppKitImage("CPImage/" + aName + ".png", imageOrSize);
|
||||
@@ -205,17 +206,19 @@ function CPAppKitImage(aFilename, aSize)
|
||||
return imageOrSize;
|
||||
}
|
||||
|
||||
- (void)setName:(CPString)aName
|
||||
- (BOOL)setName:(CPString)aName
|
||||
{
|
||||
if (_name === aName)
|
||||
return;
|
||||
return YES;
|
||||
|
||||
if (imagesForNames[aName] === self)
|
||||
imagesForNames[aName] = nil;
|
||||
if (imagesForNames[aName])
|
||||
return NO;
|
||||
|
||||
_name = aName;
|
||||
|
||||
imagesForNames[aName] = self;
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (CPString)name
|
||||
|
||||
+99
-18
@@ -26,16 +26,23 @@
|
||||
@import "CPImage.j"
|
||||
@import "CPShadowView.j"
|
||||
|
||||
#include "Platform/Platform.h"
|
||||
#include "Platform/DOM/CPDOMDisplayServer.h"
|
||||
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
|
||||
CPScaleProportionally = 0;
|
||||
CPScaleToFit = 1;
|
||||
CPScaleNone = 2;
|
||||
|
||||
var CPImageViewShadowBackgroundColor = nil;
|
||||
CPImageAlignCenter = 0;
|
||||
CPImageAlignTop = 1;
|
||||
CPImageAlignTopLeft = 2;
|
||||
CPImageAlignTopRight = 3;
|
||||
CPImageAlignLeft = 4;
|
||||
CPImageAlignBottom = 5;
|
||||
CPImageAlignBottomLeft = 6;
|
||||
CPImageAlignBottomRight = 7;
|
||||
CPImageAlignRight = 8;
|
||||
|
||||
var CPImageViewShadowBackgroundColor = nil,
|
||||
CPImageViewEmptyPlaceholderImage = nil;
|
||||
|
||||
var LEFT_SHADOW_INSET = 3.0,
|
||||
RIGHT_SHADOW_INSET = 3.0,
|
||||
@@ -52,14 +59,22 @@ var LEFT_SHADOW_INSET = 3.0,
|
||||
*/
|
||||
@implementation CPImageView : CPControl
|
||||
{
|
||||
DOMElement _DOMImageElement;
|
||||
DOMElement _DOMImageElement;
|
||||
|
||||
BOOL _hasShadow;
|
||||
CPView _shadowView;
|
||||
BOOL _hasShadow;
|
||||
CPView _shadowView;
|
||||
|
||||
BOOL _isEditable;
|
||||
BOOL _isEditable;
|
||||
|
||||
CGRect _imageRect;
|
||||
CGRect _imageRect;
|
||||
CPImageAlignment _imageAlignment;
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
var bundle = [CPBundle bundleForClass:[CPView class]];
|
||||
|
||||
CPImageViewEmptyPlaceholderImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"empty.png"]];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
@@ -120,7 +135,7 @@ var LEFT_SHADOW_INSET = 3.0,
|
||||
var newImage = [self objectValue];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
_DOMImageElement.src = newImage ? [newImage filename] : "";
|
||||
_DOMImageElement.src = newImage ? [newImage filename] : [CPImageViewEmptyPlaceholderImage filename];
|
||||
#endif
|
||||
|
||||
var size = [newImage size];
|
||||
@@ -191,6 +206,30 @@ var LEFT_SHADOW_INSET = 3.0,
|
||||
[self hideOrDisplayContents];
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the type of image alignment that should be used to
|
||||
render the image.
|
||||
@param anImageAlignment the type of scaling to use
|
||||
*/
|
||||
- (void)setImageAlignment:(CPImageAlignment)anImageAlignment
|
||||
{
|
||||
if (_imageAlignment == anImageAlignment)
|
||||
return;
|
||||
|
||||
_imageAlignment = anImageAlignment;
|
||||
|
||||
if (![self image])
|
||||
return;
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (unsigned)imageAlignment
|
||||
{
|
||||
return _imageAlignment;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the type of image scaling that should be used to
|
||||
render the image.
|
||||
@@ -318,8 +357,45 @@ var LEFT_SHADOW_INSET = 3.0,
|
||||
#endif
|
||||
}
|
||||
|
||||
var x = (boundsWidth - width) / 2.0,
|
||||
y = (boundsHeight - height) / 2.0;
|
||||
var x, y;
|
||||
|
||||
switch (_imageAlignment)
|
||||
{
|
||||
case CPImageAlignLeft:
|
||||
case CPImageAlignTopLeft:
|
||||
case CPImageAlignBottomLeft:
|
||||
x = 0.0;
|
||||
break;
|
||||
|
||||
case CPImageAlignRight:
|
||||
case CPImageAlignTopRight:
|
||||
case CPImageAlignBottomRight:
|
||||
x = boundsWidth - width;
|
||||
break;
|
||||
|
||||
default:
|
||||
x = (boundsWidth - width) / 2.0;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (_imageAlignment)
|
||||
{
|
||||
case CPImageAlignTop:
|
||||
case CPImageAlignTopLeft:
|
||||
case CPImageAlignTopRight:
|
||||
y = 0.0;
|
||||
break;
|
||||
|
||||
case CPImageAlignBottom:
|
||||
case CPImageAlignBottomLeft:
|
||||
case CPImageAlignBottomRight:
|
||||
y = boundsHeight - height;
|
||||
break;
|
||||
|
||||
default:
|
||||
y = (boundsHeight - height) / 2.0;
|
||||
break;
|
||||
}
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
CPDOMDisplayServerSetStyleLeftTop(_DOMImageElement, NULL, x, y);
|
||||
@@ -365,7 +441,7 @@ var LEFT_SHADOW_INSET = 3.0,
|
||||
return _isEditable;
|
||||
}
|
||||
|
||||
- (void)performDragOperation:(CPDraggingInfo)aSender
|
||||
- (BOOL)performDragOperation:(CPDraggingInfo)aSender
|
||||
{
|
||||
var images = [CPKeyedUnarchiver unarchiveObjectWithData:[[aSender draggingPasteboard] dataForType:CPImagesPboardType]];
|
||||
|
||||
@@ -374,14 +450,17 @@ var LEFT_SHADOW_INSET = 3.0,
|
||||
[self setImage:images[0]];
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPImageViewImageKey = @"CPImageViewImageKey",
|
||||
CPImageViewImageScalingKey = @"CPImageViewImageScalingKey",
|
||||
CPImageViewHasShadowKey = @"CPImageViewHasShadowKey",
|
||||
CPImageViewIsEditableKey = @"CPImageViewIsEditableKey";
|
||||
var CPImageViewImageKey = @"CPImageViewImageKey",
|
||||
CPImageViewImageScalingKey = @"CPImageViewImageScalingKey",
|
||||
CPImageViewImageAlignmentKey = @"CPImageViewImageAlignmentKey",
|
||||
CPImageViewHasShadowKey = @"CPImageViewHasShadowKey",
|
||||
CPImageViewIsEditableKey = @"CPImageViewIsEditableKey";
|
||||
|
||||
@implementation CPImageView (CPCoding)
|
||||
|
||||
@@ -414,6 +493,7 @@ var CPImageViewImageKey = @"CPImageViewImageKey",
|
||||
#endif
|
||||
|
||||
[self setHasShadow:[aCoder decodeBoolForKey:CPImageViewHasShadowKey]];
|
||||
[self setImageAlignment:[aCoder decodeIntForKey:CPImageViewImageAlignmentKey]];
|
||||
|
||||
if ([aCoder decodeBoolForKey:CPImageViewIsEditableKey] || NO)
|
||||
[self setEditable:YES];
|
||||
@@ -448,6 +528,7 @@ var CPImageViewImageKey = @"CPImageViewImageKey",
|
||||
_subviews = actualSubviews;
|
||||
|
||||
[aCoder encodeBool:_hasShadow forKey:CPImageViewHasShadowKey];
|
||||
[aCoder encodeInt:_imageAlignment forKey:CPImageViewImageAlignmentKey];
|
||||
|
||||
if (_isEditable)
|
||||
[aCoder encodeBool:_isEditable forKey:CPImageViewIsEditableKey];
|
||||
|
||||
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* 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
|
||||
@@ -0,0 +1,472 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
+58
-65
@@ -31,9 +31,6 @@
|
||||
@import "CPMenuItem.j"
|
||||
@import "CPPanel.j"
|
||||
|
||||
#include "../CoreGraphics/CGGeometry.h"
|
||||
#include "../Platform/Platform.h"
|
||||
|
||||
|
||||
CPMenuDidAddItemNotification = @"CPMenuDidAddItemNotification";
|
||||
CPMenuDidChangeItemNotification = @"CPMenuDidChangeItemNotification";
|
||||
@@ -50,11 +47,11 @@ var _CPMenuBarVisible = NO,
|
||||
_CPMenuBarAttributes = nil,
|
||||
_CPMenuBarSharedWindow = nil;
|
||||
|
||||
/*!
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@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.
|
||||
*/
|
||||
@implementation CPMenu : CPObject
|
||||
@@ -69,13 +66,13 @@ var _CPMenuBarVisible = NO,
|
||||
float _minimumWidth;
|
||||
|
||||
CPMutableArray _items;
|
||||
|
||||
|
||||
BOOL _autoenablesItems;
|
||||
BOOL _showsStateColumn;
|
||||
|
||||
id _delegate;
|
||||
|
||||
CPMenuItem _highlightedIndex;
|
||||
|
||||
int _highlightedIndex;
|
||||
_CPMenuWindow _menuWindow;
|
||||
}
|
||||
|
||||
@@ -95,7 +92,7 @@ var _CPMenuBarVisible = NO,
|
||||
{
|
||||
if (_CPMenuBarVisible === menuBarShouldBeVisible)
|
||||
return;
|
||||
|
||||
|
||||
_CPMenuBarVisible = menuBarShouldBeVisible;
|
||||
|
||||
if ([CPPlatform supportsNativeMainMenu])
|
||||
@@ -105,13 +102,13 @@ var _CPMenuBarVisible = NO,
|
||||
{
|
||||
if (!_CPMenuBarSharedWindow)
|
||||
_CPMenuBarSharedWindow = [[_CPMenuBarWindow alloc] init];
|
||||
|
||||
|
||||
[_CPMenuBarSharedWindow setMenu:[CPApp mainMenu]];
|
||||
|
||||
|
||||
[_CPMenuBarSharedWindow setTitle:_CPMenuBarTitle];
|
||||
[_CPMenuBarSharedWindow setIconImage:_CPMenuBarIconImage];
|
||||
[_CPMenuBarSharedWindow setIconImageAlphaValue:_CPMenuBarIconImageAlphaValue];
|
||||
|
||||
|
||||
[_CPMenuBarSharedWindow setColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarBackgroundColor"]];
|
||||
[_CPMenuBarSharedWindow setTextColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTextColor"]];
|
||||
[_CPMenuBarSharedWindow setTitleColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTitleColor"]];
|
||||
@@ -120,12 +117,12 @@ var _CPMenuBarVisible = NO,
|
||||
[_CPMenuBarSharedWindow setHighlightColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightColor"]];
|
||||
[_CPMenuBarSharedWindow setHighlightTextColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightTextColor"]];
|
||||
[_CPMenuBarSharedWindow setHighlightTextShadowColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightTextShadowColor"]];
|
||||
|
||||
|
||||
[_CPMenuBarSharedWindow orderFront:self];
|
||||
}
|
||||
else
|
||||
[_CPMenuBarSharedWindow orderOut:self];
|
||||
|
||||
|
||||
// FIXME: There must be a better way to do this.
|
||||
#if PLATFORM(DOM)
|
||||
[[CPPlatformWindow primaryPlatformWindow] resizeEvent:nil];
|
||||
@@ -159,9 +156,9 @@ var _CPMenuBarVisible = NO,
|
||||
{
|
||||
if (_CPMenuBarAttributes == attributes)
|
||||
return;
|
||||
|
||||
|
||||
_CPMenuBarAttributes = [attributes copy];
|
||||
|
||||
|
||||
var textColor = [attributes objectForKey:@"CPMenuBarTextColor"],
|
||||
titleColor = [attributes objectForKey:@"CPMenuBarTitleColor"],
|
||||
textShadowColor = [attributes objectForKey:@"CPMenuBarTextShadowColor"],
|
||||
@@ -169,40 +166,40 @@ var _CPMenuBarVisible = NO,
|
||||
highlightColor = [attributes objectForKey:@"CPMenuBarHighlightColor"],
|
||||
highlightTextColor = [attributes objectForKey:@"CPMenuBarHighlightTextColor"],
|
||||
highlightTextShadowColor = [attributes objectForKey:@"CPMenuBarHighlightTextShadowColor"];
|
||||
|
||||
|
||||
if (!textColor && titleColor)
|
||||
[_CPMenuBarAttributes setObject:titleColor forKey:@"CPMenuBarTextColor"];
|
||||
|
||||
|
||||
else if (textColor && !titleColor)
|
||||
[_CPMenuBarAttributes setObject:textColor forKey:@"CPMenuBarTitleColor"];
|
||||
|
||||
|
||||
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:@"CPMenuBarTitleColor"];
|
||||
}
|
||||
|
||||
|
||||
if (!textShadowColor && titleShadowColor)
|
||||
[_CPMenuBarAttributes setObject:titleShadowColor forKey:@"CPMenuBarTextShadowColor"];
|
||||
|
||||
|
||||
else if (textShadowColor && !titleShadowColor)
|
||||
[_CPMenuBarAttributes setObject:textShadowColor forKey:@"CPMenuBarTitleShadowColor"];
|
||||
|
||||
|
||||
else if (!textShadowColor && !titleShadowColor)
|
||||
{
|
||||
[_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarTextShadowColor"];
|
||||
[_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarTitleShadowColor"];
|
||||
}
|
||||
|
||||
|
||||
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"];
|
||||
|
||||
|
||||
if (!highlightTextColor)
|
||||
[_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarHighlightTextColor"];
|
||||
|
||||
|
||||
if (!highlightTextShadowColor)
|
||||
[_CPMenuBarAttributes setObject:[CPColor blackColor] forKey:@"CPMenuBarHighlightTextShadowColor"];
|
||||
|
||||
|
||||
if (_CPMenuBarSharedWindow)
|
||||
{
|
||||
[_CPMenuBarSharedWindow setColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarBackgroundColor"]];
|
||||
@@ -231,7 +228,7 @@ var _CPMenuBarVisible = NO,
|
||||
{
|
||||
if (self === [CPApp mainMenu])
|
||||
return MENUBAR_HEIGHT;
|
||||
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
@@ -249,18 +246,18 @@ var _CPMenuBarVisible = NO,
|
||||
- (id)initWithTitle:(CPString)aTitle
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_title = aTitle;
|
||||
_items = [];
|
||||
|
||||
|
||||
_autoenablesItems = YES;
|
||||
_showsStateColumn = YES;
|
||||
|
||||
[self setMinimumWidth:0];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -287,7 +284,7 @@ var _CPMenuBarVisible = NO,
|
||||
|
||||
[aMenuItem setMenu:self];
|
||||
[_items insertObject:aMenuItem atIndex:anIndex];
|
||||
|
||||
|
||||
[[CPNotificationCenter defaultCenter]
|
||||
postNotificationName:CPMenuDidAddItemNotification
|
||||
object:self
|
||||
@@ -306,7 +303,7 @@ var _CPMenuBarVisible = NO,
|
||||
- (CPMenuItem)insertItemWithTitle:(CPString)aTitle action:(SEL)anAction keyEquivalent:(CPString)aKeyEquivalent atIndex:(unsigned)anIndex
|
||||
{
|
||||
var item = [[CPMenuItem alloc] initWithTitle:aTitle action:anAction keyEquivalent:aKeyEquivalent];
|
||||
|
||||
|
||||
[self insertItem:item atIndex:anIndex];
|
||||
|
||||
return item;
|
||||
@@ -351,10 +348,10 @@ var _CPMenuBarVisible = NO,
|
||||
{
|
||||
if (anIndex < 0 || anIndex >= _items.length)
|
||||
return;
|
||||
|
||||
|
||||
[_items[anIndex] setMenu:nil];
|
||||
[_items removeObjectAtIndex:anIndex];
|
||||
|
||||
|
||||
[[CPNotificationCenter defaultCenter]
|
||||
postNotificationName:CPMenuDidRemoveItemNotification
|
||||
object:self
|
||||
@@ -369,7 +366,7 @@ var _CPMenuBarVisible = NO,
|
||||
{
|
||||
if ([aMenuItem menu] != self)
|
||||
return;
|
||||
|
||||
|
||||
[[CPNotificationCenter defaultCenter]
|
||||
postNotificationName:CPMenuDidChangeItemNotification
|
||||
object:self
|
||||
@@ -385,10 +382,10 @@ var _CPMenuBarVisible = NO,
|
||||
- (CPMenuItem)itemWithTag:(int)aTag
|
||||
{
|
||||
var index = [self indexOfItemWithTag:aTag];
|
||||
|
||||
|
||||
if (index == CPNotFound)
|
||||
return nil;
|
||||
|
||||
|
||||
return _items[index];
|
||||
}
|
||||
|
||||
@@ -400,10 +397,10 @@ var _CPMenuBarVisible = NO,
|
||||
- (CPMenuItem)itemWithTitle:(CPString)aTitle
|
||||
{
|
||||
var index = [self indexOfItemWithTitle:aTitle];
|
||||
|
||||
|
||||
if (index == CPNotFound)
|
||||
return nil;
|
||||
|
||||
|
||||
return _items[index];
|
||||
}
|
||||
|
||||
@@ -442,7 +439,7 @@ var _CPMenuBarVisible = NO,
|
||||
{
|
||||
if ([aMenuItem menu] !== self)
|
||||
return CPNotFound;
|
||||
|
||||
|
||||
return [_items indexOfObjectIdenticalTo:aMenuItem];
|
||||
}
|
||||
|
||||
@@ -455,7 +452,7 @@ var _CPMenuBarVisible = NO,
|
||||
{
|
||||
var index = 0,
|
||||
count = _items.length;
|
||||
|
||||
|
||||
for (; index < count; ++index)
|
||||
if ([_items[index] title] === aTitle)
|
||||
return index;
|
||||
@@ -472,7 +469,7 @@ var _CPMenuBarVisible = NO,
|
||||
{
|
||||
var index = 0,
|
||||
count = _items.length;
|
||||
|
||||
|
||||
for (; index < count; ++index)
|
||||
if ([_items[index] tag] == aTag)
|
||||
return index;
|
||||
@@ -490,11 +487,11 @@ var _CPMenuBarVisible = NO,
|
||||
{
|
||||
var index = 0,
|
||||
count = _items.length;
|
||||
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var item = _items[index];
|
||||
|
||||
|
||||
if ([item target] == aTarget && (!anAction || [item action] == anAction))
|
||||
return index;
|
||||
}
|
||||
@@ -511,7 +508,7 @@ var _CPMenuBarVisible = NO,
|
||||
{
|
||||
var index = 0,
|
||||
count = _items.length;
|
||||
|
||||
|
||||
for (; index < count; ++index)
|
||||
if ([[_items[index] representedObject] isEqual:anObject])
|
||||
return index;
|
||||
@@ -528,7 +525,7 @@ var _CPMenuBarVisible = NO,
|
||||
{
|
||||
var index = 0,
|
||||
count = _items.length;
|
||||
|
||||
|
||||
for (; index < count; ++index)
|
||||
if ([_items[index] submenu] == aMenu)
|
||||
return index;
|
||||
@@ -546,7 +543,7 @@ var _CPMenuBarVisible = NO,
|
||||
{
|
||||
[aMenuItem setTarget:aMenuItem];
|
||||
[aMenuItem setAction:@selector(submenuAction:)];
|
||||
|
||||
|
||||
[aMenuItem setSubmenu:aMenu];
|
||||
}
|
||||
|
||||
@@ -683,7 +680,7 @@ var _CPMenuBarVisible = NO,
|
||||
itemIndex = [self indexOfItem:anItem];
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -747,6 +744,9 @@ var _CPMenuBarVisible = NO,
|
||||
}
|
||||
|
||||
// Show it.
|
||||
if ([CPPlatform isBrowser])
|
||||
[menuWindow setPlatformWindow:[[aView window] platformWindow]];
|
||||
|
||||
[menuWindow orderFront:self];
|
||||
|
||||
// Track it.
|
||||
@@ -781,10 +781,10 @@ var _CPMenuBarVisible = NO,
|
||||
+ (void)popUpContextMenu:(CPMenu)aMenu withEvent:(CPEvent)anEvent forView:(CPView)aView withFont:(CPFont)aFont
|
||||
{
|
||||
var delegate = [aMenu delegate];
|
||||
|
||||
|
||||
if ([delegate respondsToSelector:@selector(menuWillOpen:)])
|
||||
[delegate menuWillOpen:aMenu];
|
||||
|
||||
|
||||
if (!aFont)
|
||||
aFont = [CPFont systemFontOfSize:12.0];
|
||||
|
||||
@@ -816,6 +816,9 @@ var _CPMenuBarVisible = NO,
|
||||
[menuWindow setFrameOrigin:CGRectIntersection(unconstrainedFrame, constraintRect).origin];
|
||||
}
|
||||
|
||||
if ([CPPlatform isBrowser])
|
||||
[menuWindow setPlatformWindow:[[aView window] platformWindow]];
|
||||
|
||||
[menuWindow orderFront:self];
|
||||
|
||||
[[_CPMenuManager sharedMenuManager]
|
||||
@@ -932,17 +935,7 @@ var _CPMenuBarVisible = NO,
|
||||
var item = _items[index],
|
||||
modifierMask = [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 ([anEvent _triggersKeyEquivalent:[item keyEquivalent] withModifierMask:[item keyEquivalentModifierMask]])
|
||||
{
|
||||
if ([item isEnabled])
|
||||
[self performActionForItemAtIndex:index];
|
||||
@@ -950,7 +943,7 @@ var _CPMenuBarVisible = NO,
|
||||
{
|
||||
//beep?
|
||||
}
|
||||
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
@@ -969,7 +962,7 @@ var _CPMenuBarVisible = NO,
|
||||
- (void)performActionForItemAtIndex:(unsigned)anIndex
|
||||
{
|
||||
var item = _items[anIndex];
|
||||
|
||||
|
||||
[CPApp sendAction:[item action] to:[item target] from:item];
|
||||
}
|
||||
|
||||
@@ -1058,7 +1051,7 @@ var CPMenuTitleKey = @"CPMenuTitleKey",
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_title = [aCoder decodeObjectForKey:CPMenuTitleKey];
|
||||
@@ -1070,7 +1063,7 @@ var CPMenuTitleKey = @"CPMenuTitleKey",
|
||||
|
||||
[self setMinimumWidth:0];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
|
||||
#include "../CoreGraphics/CGGeometry.h"
|
||||
#include "../Platform/Platform.h"
|
||||
|
||||
@import "CPPanel.j"
|
||||
@import "_CPMenuWindow.j"
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
|
||||
#include "../CoreGraphics/CGGeometry.h"
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
|
||||
@@ -96,7 +93,7 @@ var SharedMenuManager = nil;
|
||||
|
||||
// Close Menu Event.
|
||||
if (type === CPAppKitDefined)
|
||||
return [self completeTracking]
|
||||
return [self completeTracking];
|
||||
|
||||
[CPApp setTarget:self selector:@selector(trackEvent:) forNextEventMatchingMask:CPPeriodicMask | CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPAppKitDefinedMask untilDate:nil inMode:nil dequeue:YES];
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
|
||||
#include "../CoreGraphics/CGGeometry.h"
|
||||
@import "CPWindow.j"
|
||||
|
||||
|
||||
var _CPMenuWindowPool = [],
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
@import "CPView.j"
|
||||
@import "_CPMenuItemView.j"
|
||||
|
||||
/*!
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPMenuItem
|
||||
|
||||
@@ -43,39 +44,39 @@
|
||||
|
||||
CPString _title;
|
||||
//CPAttributedString _attributedTitle;
|
||||
|
||||
|
||||
CPFont _font;
|
||||
|
||||
|
||||
id _target;
|
||||
SEL _action;
|
||||
|
||||
|
||||
BOOL _isEnabled;
|
||||
BOOL _isHidden;
|
||||
|
||||
|
||||
int _tag;
|
||||
int _state;
|
||||
|
||||
|
||||
CPImage _image;
|
||||
CPImage _alternateImage;
|
||||
CPImage _onStateImage;
|
||||
CPImage _offStateImage;
|
||||
CPImage _mixedStateImage;
|
||||
|
||||
|
||||
CPMenu _submenu;
|
||||
CPMenu _menu;
|
||||
|
||||
|
||||
CPString _keyEquivalent;
|
||||
unsigned _keyEquivalentModifierMask;
|
||||
|
||||
|
||||
int _mnemonicLocation;
|
||||
|
||||
|
||||
BOOL _isAlternate;
|
||||
int _indentationLevel;
|
||||
|
||||
|
||||
CPString _toolTip;
|
||||
id _representedObject;
|
||||
CPView _view;
|
||||
|
||||
|
||||
_CPMenuItemView _menuItemView;
|
||||
}
|
||||
|
||||
@@ -94,19 +95,19 @@
|
||||
- (id)initWithTitle:(CPString)aTitle action:(SEL)anAction keyEquivalent:(CPString)aKeyEquivalent
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_isSeparator = NO;
|
||||
|
||||
_title = aTitle;
|
||||
_action = anAction;
|
||||
|
||||
|
||||
_isEnabled = YES;
|
||||
|
||||
|
||||
_tag = 0;
|
||||
_state = CPOffState;
|
||||
|
||||
|
||||
_keyEquivalent = aKeyEquivalent || @"";
|
||||
_keyEquivalentModifierMask = CPPlatformActionKeyMask;
|
||||
|
||||
@@ -114,7 +115,7 @@
|
||||
|
||||
_mnemonicLocation = CPNotFound;
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -152,7 +153,7 @@
|
||||
{
|
||||
if (_isHidden == isHidden)
|
||||
return;
|
||||
|
||||
|
||||
_isHidden = isHidden;
|
||||
|
||||
[_menu itemChanged:self];
|
||||
@@ -173,9 +174,9 @@
|
||||
{
|
||||
if (_isHidden)
|
||||
return YES;
|
||||
|
||||
|
||||
var supermenu = [_menu supermenu];
|
||||
|
||||
|
||||
if ([[supermenu itemAtIndex:[supermenu indexOfItemWithSubmenu:_menu]] isHiddenOrHasHiddenAncestor])
|
||||
return YES;
|
||||
|
||||
@@ -228,11 +229,11 @@
|
||||
|
||||
if (_title == aTitle)
|
||||
return;
|
||||
|
||||
|
||||
_title = aTitle;
|
||||
|
||||
|
||||
[_menuItemView setDirty];
|
||||
|
||||
|
||||
[_menu itemChanged:self];
|
||||
}
|
||||
|
||||
@@ -260,11 +261,11 @@
|
||||
{
|
||||
if (_font == aFont)
|
||||
return;
|
||||
|
||||
|
||||
_font = aFont;
|
||||
|
||||
[_menu itemChanged:self];
|
||||
|
||||
|
||||
[_menuItemView setDirty];
|
||||
}
|
||||
|
||||
@@ -316,9 +317,9 @@ CPOffState
|
||||
{
|
||||
if (_state == aState)
|
||||
return;
|
||||
|
||||
|
||||
_state = aState;
|
||||
|
||||
|
||||
[_menu itemChanged:self];
|
||||
|
||||
[_menuItemView setDirty];
|
||||
@@ -346,11 +347,11 @@ CPOffState
|
||||
{
|
||||
if (_image == anImage)
|
||||
return;
|
||||
|
||||
|
||||
_image = anImage;
|
||||
|
||||
[_menuItemView setDirty];
|
||||
|
||||
|
||||
[_menu itemChanged:self];
|
||||
}
|
||||
|
||||
@@ -388,7 +389,7 @@ CPOffState
|
||||
{
|
||||
if (_onStateImage == anImage)
|
||||
return;
|
||||
|
||||
|
||||
_onStateImage = anImage;
|
||||
[_menu itemChanged:self];
|
||||
}
|
||||
@@ -409,7 +410,7 @@ CPOffState
|
||||
{
|
||||
if (_offStateImage == anImage)
|
||||
return;
|
||||
|
||||
|
||||
_offStateImage = anImage;
|
||||
[_menu itemChanged:self];
|
||||
}
|
||||
@@ -430,7 +431,7 @@ CPOffState
|
||||
{
|
||||
if (_mixedStateImage == anImage)
|
||||
return;
|
||||
|
||||
|
||||
_mixedStateImage = anImage;
|
||||
[_menu itemChanged:self];
|
||||
}
|
||||
@@ -591,7 +592,8 @@ CPControlKeyMask
|
||||
return @"";
|
||||
|
||||
var string = _keyEquivalent.toUpperCase(),
|
||||
needsShift = _keyEquivalentModifierMask & CPShiftKeyMask || string === _keyEquivalent;
|
||||
needsShift = _keyEquivalentModifierMask & CPShiftKeyMask ||
|
||||
(string === _keyEquivalent && _keyEquivalent.toLowerCase() !== _keyEquivalent.toUpperCase());
|
||||
|
||||
if (CPBrowserIsOperatingSystem(CPMacOperatingSystem))
|
||||
{
|
||||
@@ -648,14 +650,14 @@ CPControlKeyMask
|
||||
- (void)setTitleWithMnemonicLocation:(CPString)aTitle
|
||||
{
|
||||
var location = [aTitle rangeOfString:@"&"].location;
|
||||
|
||||
|
||||
if (location == CPNotFound)
|
||||
[self setTitle:aTitle];
|
||||
else
|
||||
{
|
||||
[self setTitle:[aTitle substringToIndex:location] + [aTitle substringFromIndex:location + 1]];
|
||||
[self setMnemonicLocation:location];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -696,7 +698,7 @@ CPControlKeyMask
|
||||
{
|
||||
if (aLevel < 0)
|
||||
[CPException raise:CPInvalidArgumentException reason:"setIndentationLevel: argument must be greater than or equal to 0."];
|
||||
|
||||
|
||||
_indentationLevel = MIN(15, aLevel);
|
||||
}
|
||||
|
||||
@@ -755,11 +757,11 @@ CPControlKeyMask
|
||||
{
|
||||
if (_view === aView)
|
||||
return;
|
||||
|
||||
|
||||
_view = aView;
|
||||
|
||||
|
||||
[_menuItemView setDirty];
|
||||
|
||||
|
||||
[_menu itemChanged:self];
|
||||
}
|
||||
|
||||
@@ -781,7 +783,48 @@ CPControlKeyMask
|
||||
return [[self menu] highlightedItem] == self;
|
||||
}
|
||||
|
||||
//
|
||||
#pragma mark CPObject Overrides
|
||||
|
||||
/*!
|
||||
Returns a copy of the item. The copy does not belong If the item has a submenu, it is NOT copied.
|
||||
*/
|
||||
- (id)copy
|
||||
{
|
||||
var item = [[CPMenuItem alloc] init];
|
||||
|
||||
// No point in going through accessors and doing lots of unnecessary state checking/updating
|
||||
item._isSeparator = _isSeparator;
|
||||
|
||||
[item setTitle:_title];
|
||||
[item setFont:_font];
|
||||
[item setTarget:_target];
|
||||
[item setAction:_action];
|
||||
[item setEnabled:_isEnabled];
|
||||
[item setHidden:_isHidden]
|
||||
[item setTag:_tag];
|
||||
[item setState:_state];
|
||||
[item setImage:_image];
|
||||
[item setAlternateImage:_alternateImage];
|
||||
[item setOnStateImage:_onStateImage];
|
||||
[item setOffStateImage:_offStateImage];
|
||||
[item setMixedStateImage:_mixedStateImage];
|
||||
[item setKeyEquivalent:_keyEquivalent];
|
||||
[item setKeyEquivalentModifierMask:_keyEquivalentModifierMask];
|
||||
[item setMnemonicLocation:_mnemonicLocation];
|
||||
[item setAlternate:_isAlternate];
|
||||
[item setIndentationLevel:_indentationLevel];
|
||||
[item setToolTip:_toolTip];
|
||||
[item setRepresentedObject:_representedObject];
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
- (id)mutableCopy
|
||||
{
|
||||
return [self copy];
|
||||
}
|
||||
|
||||
#pragma mark Internal
|
||||
|
||||
/*
|
||||
@ignore
|
||||
@@ -790,7 +833,7 @@ CPControlKeyMask
|
||||
{
|
||||
if (!_menuItemView)
|
||||
_menuItemView = [[_CPMenuItemView alloc] initWithFrame:CGRectMakeZero() forMenuItem:self];
|
||||
|
||||
|
||||
return _menuItemView;
|
||||
}
|
||||
|
||||
@@ -844,15 +887,15 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_isSeparator = [aCoder containsValueForKey:CPMenuItemIsSeparatorKey] && [aCoder decodeBoolForKey:CPMenuItemIsSeparatorKey];
|
||||
|
||||
_title = [aCoder decodeObjectForKey:CPMenuItemTitleKey];
|
||||
|
||||
|
||||
// _font;
|
||||
|
||||
|
||||
_target = [aCoder decodeObjectForKey:CPMenuItemTargetKey];
|
||||
_action = [aCoder decodeObjectForKey:CPMenuItemActionKey];
|
||||
|
||||
@@ -860,7 +903,6 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
|
||||
_isHidden = DEFAULT_VALUE(CPMenuItemIsHiddenKey, NO);
|
||||
_tag = DEFAULT_VALUE(CPMenuItemTagKey, 0);
|
||||
_state = DEFAULT_VALUE(CPMenuItemStateKey, CPOffState);
|
||||
// int _state;
|
||||
|
||||
_image = DEFAULT_VALUE(CPMenuItemImageKey, nil);
|
||||
_alternateImage = DEFAULT_VALUE(CPMenuItemAlternateImageKey, nil);
|
||||
@@ -887,7 +929,7 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
|
||||
_representedObject = DEFAULT_VALUE(CPMenuItemRepresentedObjectKey, nil);
|
||||
_view = DEFAULT_VALUE(CPMenuItemViewKey, nil);
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -901,11 +943,11 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
|
||||
[aCoder encodeBool:_isSeparator forKey:CPMenuItemIsSeparatorKey];
|
||||
|
||||
[aCoder encodeObject:_title forKey:CPMenuItemTitleKey];
|
||||
|
||||
|
||||
[aCoder encodeObject:_target forKey:CPMenuItemTargetKey];
|
||||
[aCoder encodeObject:_action forKey:CPMenuItemActionKey];
|
||||
|
||||
ENCODE_IFNOT(CPMenuItemIsEnabledKey, _isEnabled, YES);
|
||||
ENCODE_IFNOT(CPMenuItemIsEnabledKey, _isEnabled, YES);
|
||||
ENCODE_IFNOT(CPMenuItemIsHiddenKey, _isHidden, NO);
|
||||
|
||||
ENCODE_IFNOT(CPMenuItemTagKey, _tag, 0);
|
||||
@@ -913,7 +955,7 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
|
||||
|
||||
ENCODE_IFNOT(CPMenuItemImageKey, _image, nil);
|
||||
ENCODE_IFNOT(CPMenuItemAlternateImageKey, _alternateImage, nil);
|
||||
|
||||
|
||||
ENCODE_IFNOT(CPMenuItemSubmenuKey, _submenu, nil);
|
||||
ENCODE_IFNOT(CPMenuItemMenuKey, _menu, nil);
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
@import "CPView.j"
|
||||
|
||||
|
||||
var HORIZONTAL_MARGIN = 8.0,
|
||||
SUBMENU_INDICATOR_MARGIN = 3.0,
|
||||
VERTICAL_MARGIN = 4.0;
|
||||
@@ -62,6 +65,7 @@ var SelectionColor = nil,
|
||||
_imageAndTextView = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(HORIZONTAL_MARGIN, 0.0, 0.0, 0.0)];
|
||||
|
||||
[_imageAndTextView setImagePosition:CPImageLeft];
|
||||
[_imageAndTextView setImageOffset:3.0];
|
||||
[_imageAndTextView setTextShadowOffset:CGSizeMake(0.0, 1.0)];
|
||||
[_imageAndTextView setAutoresizingMask:CPViewMinYMargin | CPViewMaxYMargin];
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
@import <AppKit/CPView.j>
|
||||
@import "CPView.j"
|
||||
|
||||
|
||||
@implementation _CPMenuItemSeparatorView : CPView
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
@import "CPControl.j"
|
||||
|
||||
|
||||
var LEFT_MARGIN = 3.0,
|
||||
RIGHT_MARGIN = 14.0 + 3.0,
|
||||
STATE_COLUMN_WIDTH = 14.0,
|
||||
@@ -39,7 +42,7 @@ var SUBMENU_INDICATOR_COLOR = nil,
|
||||
SUBMENU_INDICATOR_COLOR = [CPColor grayColor];
|
||||
|
||||
_CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0];
|
||||
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0]
|
||||
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0];
|
||||
|
||||
var bundle = [CPBundle bundleForClass:self];
|
||||
|
||||
@@ -257,10 +260,13 @@ var SUBMENU_INDICATOR_COLOR = nil,
|
||||
[_keyEquivalentView setTextShadowColor:[self textShadowColor]];
|
||||
}
|
||||
|
||||
if (shouldHighlight)
|
||||
[_stateView setImage:_CPMenuItemDefaultStateHighlightedImages[[_menuItem state]] || nil];
|
||||
else
|
||||
[_stateView setImage:_CPMenuItemDefaultStateImages[[_menuItem state]] || nil];
|
||||
if ([[_menuItem menu] showsStateColumn])
|
||||
{
|
||||
if (shouldHighlight)
|
||||
[_stateView setImage:_CPMenuItemDefaultStateHighlightedImages[[_menuItem state]] || nil];
|
||||
else
|
||||
[_stateView setImage:_CPMenuItemDefaultStateImages[[_menuItem state]] || nil];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
|
||||
@import <AppKit/CPControl.j>
|
||||
|
||||
@import "_CPMenuItemSeparatorView.j"
|
||||
@import "_CPMenuItemStandardView.j"
|
||||
@import "_CPMenuItemMenuBarView.j"
|
||||
@@ -43,7 +45,7 @@ var _CPMenuItemSelectionColor = nil,
|
||||
return;
|
||||
|
||||
_CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0];
|
||||
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0]
|
||||
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0];
|
||||
|
||||
var bundle = [CPBundle bundleForClass:self];
|
||||
|
||||
@@ -252,4 +254,4 @@ var _CPMenuItemSelectionColor = nil,
|
||||
CGContextFillPath(context);
|
||||
}
|
||||
|
||||
@end
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,625 @@
|
||||
|
||||
@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,5 +1,5 @@
|
||||
|
||||
@import <AppKit/CPPanel.j>
|
||||
@import "CPPanel.j"
|
||||
|
||||
|
||||
@implementation CPOpenPanel : CPPanel
|
||||
|
||||
+371
-125
@@ -23,8 +23,6 @@
|
||||
@import "CPTableColumn.j"
|
||||
@import "CPTableView.j"
|
||||
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
|
||||
|
||||
CPOutlineViewColumnDidMoveNotification = @"CPOutlineViewColumnDidMoveNotification";
|
||||
CPOutlineViewColumnDidResizeNotification = @"CPOutlineViewColumnDidResizeNotification";
|
||||
@@ -50,12 +48,30 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_
|
||||
|
||||
CPOutlineViewDataSource_outlineView_sortDescriptorsDidChange_ = 1 << 10;
|
||||
|
||||
|
||||
var CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_ = 1 << 1,
|
||||
CPOutlineViewDelegate_outlineView_shouldSelectItem_ = 1 << 2,
|
||||
CPOutlineViewDelegate_outlineView_heightOfRowByItem_ = 1 << 3,
|
||||
CPOutlineViewDelegate_outlineView_willDisplayView_forTableColumn_item_ = 1 << 4,
|
||||
CPOutlineViewDelegate_outlineView_isGroupItem_ = 1 << 5;
|
||||
CPOutlineViewDelegate_outlineView_didClickTableColumn_ = 1 << 2,
|
||||
CPOutlineViewDelegate_outlineView_didDragTableColumn_ = 1 << 3,
|
||||
CPOutlineViewDelegate_outlineView_heightOfRowByItem_ = 1 << 4,
|
||||
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;
|
||||
|
||||
@@ -79,12 +95,14 @@ CPOutlineViewDropOnItemIndex = -1;
|
||||
CPArray _disclosureControlsForRows;
|
||||
CPData _disclosureControlData;
|
||||
CPArray _disclosureControlQueue;
|
||||
|
||||
|
||||
BOOL _shouldRetargetItem;
|
||||
id _retargetedItem;
|
||||
|
||||
|
||||
BOOL _shouldRetargetChildIndex;
|
||||
CPInteger _retargedChildIndex;
|
||||
CPTimer _dragHoverTimer;
|
||||
id _dropItem;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
@@ -105,9 +123,10 @@ CPOutlineViewDropOnItemIndex = -1;
|
||||
|
||||
_retargetedItem = nil;
|
||||
_shouldRetargetItem = NO;
|
||||
|
||||
|
||||
_retargedChildIndex = nil;
|
||||
_shouldRetargetChildIndex = NO;
|
||||
_startHoverTime = nil;
|
||||
|
||||
[self setIndentationPerLevel:16.0];
|
||||
[self setIndentationMarkerFollowsDataView:YES];
|
||||
@@ -213,7 +232,7 @@ CPOutlineViewDropOnItemIndex = -1;
|
||||
- (void)expandItem:(id)anItem expandChildren:(BOOL)shouldExpandChildren
|
||||
{
|
||||
var itemInfo = null;
|
||||
|
||||
|
||||
if (!anItem)
|
||||
itemInfo = _rootItemInfo;
|
||||
else
|
||||
@@ -221,15 +240,21 @@ CPOutlineViewDropOnItemIndex = -1;
|
||||
|
||||
if (!itemInfo)
|
||||
return;
|
||||
|
||||
itemInfo.isExpanded = YES;
|
||||
[self reloadItem:anItem reloadChildren:YES];
|
||||
|
||||
|
||||
// to prevent items which are already expanded from firing notifications
|
||||
if (!itemInfo.isExpanded)
|
||||
{
|
||||
[self _noteItemWillExpand:anItem];
|
||||
itemInfo.isExpanded = YES;
|
||||
[self _noteItemDidExpand:anItem];
|
||||
[self reloadItem:anItem reloadChildren:YES];
|
||||
}
|
||||
|
||||
if (shouldExpandChildren)
|
||||
{
|
||||
var children = itemInfo.children,
|
||||
childIndex = children.length;
|
||||
|
||||
|
||||
while (childIndex--)
|
||||
[self expandItem:children[childIndex] expandChildren:YES];
|
||||
}
|
||||
@@ -248,7 +273,9 @@ CPOutlineViewDropOnItemIndex = -1;
|
||||
if (!itemInfo.isExpanded)
|
||||
return;
|
||||
|
||||
[self _noteItemWillCollapse:anItem];
|
||||
itemInfo.isExpanded = NO;
|
||||
[self _noteItemDidCollapse:anItem];
|
||||
|
||||
[self reloadItem:anItem reloadChildren:YES];
|
||||
}
|
||||
@@ -363,7 +390,7 @@ CPOutlineViewDropOnItemIndex = -1;
|
||||
return nil;
|
||||
|
||||
var parent = itemInfo.parent;
|
||||
|
||||
|
||||
// Check if the parent is the root item because we never return the actual root item
|
||||
if (itemInfo[[parent UID]] === _rootItemInfo)
|
||||
parent = nil;
|
||||
@@ -382,43 +409,14 @@ CPOutlineViewDropOnItemIndex = -1;
|
||||
return frame;
|
||||
}
|
||||
|
||||
- (void)selectRowIndexes:(CPIndexSet)rows byExtendingSelection:(BOOL)shouldExtendSelection
|
||||
- (void)_performSelection:(BOOL)select forRow:(CPInteger)rowIndex context:(id)context
|
||||
{
|
||||
// First un highlight the old disclosure controls
|
||||
var previousSelectedRows = [];
|
||||
[[self selectedRowIndexes] getIndexes:previousSelectedRows maxCount:-1 inIndexRange:nil];
|
||||
|
||||
var index = [previousSelectedRows count];
|
||||
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];
|
||||
}
|
||||
[super _performSelection:select forRow:rowIndex context:context];
|
||||
|
||||
var control = _disclosureControlsForRows[rowIndex],
|
||||
selector = select ? @"setThemeState:" : @"unsetThemeState:";
|
||||
|
||||
[control performSelector:CPSelectorFromString(selector) withObject:CPThemeStateSelected];
|
||||
}
|
||||
|
||||
- (void)setDelegate:(id)aDelegate
|
||||
@@ -453,25 +451,76 @@ CPOutlineViewDropOnItemIndex = -1;
|
||||
removeObserver:_outlineViewDelegate
|
||||
name:CPOutlineViewSelectionIsChangingNotification
|
||||
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;
|
||||
_implementedOutlineViewDelegateMethods = 0;
|
||||
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(outlineView:dataViewForTableColumn:item:)])
|
||||
_implementedOutlineViewDelegateMethods |= CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_;
|
||||
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(outlineView:shouldSelectItem:)])
|
||||
_implementedOutlineViewDelegateMethods |= CPOutlineViewDelegate_outlineView_shouldSelectItem_;
|
||||
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(outlineView:heightOfRowByItem:)])
|
||||
_implementedOutlineViewDelegateMethods |= CPOutlineViewDelegate_outlineView_heightOfRowByItem_;
|
||||
var delegateMethods = [
|
||||
CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_ , @selector(outlineView:dataViewForTableColumn:item:),
|
||||
CPOutlineViewDelegate_outlineView_didClickTableColumn_ , @selector(outlineView:didClickTableColumn:),
|
||||
CPOutlineViewDelegate_outlineView_didDragTableColumn_ , @selector(outlineView:didDragTableColumn:),
|
||||
CPOutlineViewDelegate_outlineView_heightOfRowByItem_ , @selector(outlineView:heightOfRowByItem:),
|
||||
CPOutlineViewDelegate_outlineView_isGroupItem_ , @selector(outlineView:isGroupItem:),
|
||||
CPOutlineViewDelegate_outlineView_mouseDownInHeaderOfTableColumn_ , @selector(outlineView:mouseDownInHeaderOfTableColumn:),
|
||||
CPOutlineViewDelegate_outlineView_nextTypeSelectMatchFromItem_toItem_forString_ , @selector(outlineView:nextTypeSelectMatchFromItem:toItem:forString:),
|
||||
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];
|
||||
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(outlineView:willDisplayView:forTableColumn:item:)])
|
||||
_implementedOutlineViewDelegateMethods |= CPOutlineViewDelegate_outlineView_willDisplayView_forTableColumn_item_;
|
||||
for (var i=0; i < delegateCount; i += 2)
|
||||
{
|
||||
var bitMask = delegateMethods[i],
|
||||
selector = delegateMethods[i+1];
|
||||
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(outlineView:isGroupItem:)])
|
||||
_implementedOutlineViewDelegateMethods |= CPOutlineViewDelegate_outlineView_isGroupItem_;
|
||||
if ([_outlineViewDelegate respondsToSelector:selector])
|
||||
_implementedOutlineViewDelegateMethods |= bitMask;
|
||||
}
|
||||
|
||||
if ([_outlineViewDelegate respondsToSelector:@selector(outlineViewColumnDidMove:)])
|
||||
[defaultCenter
|
||||
@@ -500,6 +549,36 @@ CPOutlineViewDropOnItemIndex = -1;
|
||||
selector:@selector(outlineViewSelectionIsChanging:)
|
||||
name:CPOutlineViewSelectionIsChangingNotification
|
||||
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
|
||||
@@ -534,18 +613,63 @@ CPOutlineViewDropOnItemIndex = -1;
|
||||
|
||||
- (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;
|
||||
_shouldRetargetItem = YES;
|
||||
|
||||
|
||||
_retargedChildIndex = theIndex;
|
||||
_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
|
||||
{
|
||||
if (_shouldRetargetItem)
|
||||
return _retargetedItem;
|
||||
|
||||
|
||||
var lowerLevel = [self levelForRow:theLowerRowIndex]
|
||||
upperItem = [self itemAtRow:theUpperRowIndex];
|
||||
upperLevel = [self levelForItem:upperItem];
|
||||
@@ -564,7 +688,7 @@ CPOutlineViewDropOnItemIndex = -1;
|
||||
// Check the next parent
|
||||
upperItem = [self parentForItem:upperItem];
|
||||
}
|
||||
|
||||
|
||||
return [self parentForItem:[self itemAtRow:theLowerRowIndex]];
|
||||
}
|
||||
|
||||
@@ -574,10 +698,10 @@ CPOutlineViewDropOnItemIndex = -1;
|
||||
var rect = [super _rectForDropHighlightViewBetweenUpperRow:theUpperRowIndex andLowerRow:theLowerRowIndex offset:theOffset],
|
||||
parentItem = [self _parentItemForUpperRow:theUpperRowIndex andLowerRow:theLowerRowIndex atMouseOffset:theOffset],
|
||||
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
|
||||
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
@@ -619,6 +743,8 @@ CPOutlineViewDropOnItemIndex = -1;
|
||||
_disclosureControlsForRows[row] = control;
|
||||
|
||||
[control setState:[self isItemExpanded:item] ? CPOnState : CPOffState];
|
||||
var selector = [self isRowSelected:row] ? @"setThemeState:" : @"unsetThemeState:";
|
||||
[control performSelector:CPSelectorFromString(selector) withObject:CPThemeStateSelected];
|
||||
[control setFrame:frame];
|
||||
|
||||
[self addSubview:control];
|
||||
@@ -709,9 +835,41 @@ CPOutlineViewDropOnItemIndex = -1;
|
||||
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
|
||||
|
||||
// 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)
|
||||
{
|
||||
if (!anItem)
|
||||
@@ -724,55 +882,55 @@ var _reloadItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anItem)
|
||||
dataSource = _outlineViewDataSource,
|
||||
itemUID = [anItem UID],
|
||||
itemInfo = itemInfosForItems[itemUID];
|
||||
|
||||
|
||||
// If we're not in the tree, then just bail.
|
||||
if (!itemInfo)
|
||||
return [];
|
||||
|
||||
|
||||
// See if the item itself can be swapped out.
|
||||
var parent = itemInfo.parent,
|
||||
parentItemInfo = parent ? itemInfosForItems[[parent UID]] : _rootItemInfo,
|
||||
parentChildren = parentItemInfo.children,
|
||||
index = [parentChildren indexOfObjectIdenticalTo:anItem],
|
||||
newItem = [dataSource outlineView:anOutlineView child:index ofItem:parent];
|
||||
|
||||
|
||||
if (anItem !== newItem)
|
||||
{
|
||||
itemInfosForItems[[anItem UID]] = nil;
|
||||
itemInfosForItems[[newItem UID]] = itemInfo;
|
||||
|
||||
|
||||
parentChildren[index] = newItem;
|
||||
_itemsForRows[itemInfo.row] = newItem;
|
||||
}
|
||||
|
||||
|
||||
itemInfo.isExpandable = [dataSource outlineView:anOutlineView isItemExpandable:newItem];
|
||||
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)
|
||||
{
|
||||
with(anOutlineView)
|
||||
{
|
||||
var itemInfosForItems = _itemInfosForItems,
|
||||
dataSource = _outlineViewDataSource;
|
||||
|
||||
|
||||
if (!anItem)
|
||||
var itemInfo = _rootItemInfo;
|
||||
|
||||
|
||||
else
|
||||
{
|
||||
// Get the existing info if it exists.
|
||||
var itemUID = [anItem UID],
|
||||
itemInfo = itemInfosForItems[itemUID];
|
||||
|
||||
|
||||
// If we're not in the tree, then just bail.
|
||||
if (!itemInfo)
|
||||
return [];
|
||||
|
||||
|
||||
itemInfo.isExpandable = [dataSource outlineView:anOutlineView isItemExpandable:anItem];
|
||||
|
||||
|
||||
// If we were previously expanded, but now no longer expandable, "de-expand".
|
||||
// NOTE: we are *not* collapsing, thus no notification is posted.
|
||||
if (!itemInfo.isExpandable && itemInfo.isExpanded)
|
||||
@@ -781,72 +939,72 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
itemInfo.children = [];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// The root item does not count as a descendant.
|
||||
var weight = itemInfo.weight,
|
||||
descendants = anItem ? [anItem] : [];
|
||||
|
||||
|
||||
if (itemInfo.isExpanded && (!(_implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_shouldDeferDisplayingChildrenOfItem_) ||
|
||||
![dataSource outlineView:anOutlineView shouldDeferDisplayingChildrenOfItem:anItem]))
|
||||
{
|
||||
var index = 0,
|
||||
count = [dataSource outlineView:anOutlineView numberOfChildrenOfItem:anItem],
|
||||
level = itemInfo.level + 1;
|
||||
|
||||
|
||||
itemInfo.children = [];
|
||||
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var childItem = [dataSource outlineView:anOutlineView child:index ofItem:anItem],
|
||||
childItemInfo = itemInfosForItems[[childItem UID]];
|
||||
|
||||
|
||||
if (!childItemInfo)
|
||||
{
|
||||
childItemInfo = { isExpanded:NO, isExpandable:NO, children:[], weight:1 };
|
||||
itemInfosForItems[[childItem UID]] = childItemInfo;
|
||||
}
|
||||
|
||||
|
||||
itemInfo.children[index] = childItem;
|
||||
|
||||
|
||||
var childDescendants = _loadItemInfoForItem(anOutlineView, childItem, YES);
|
||||
|
||||
|
||||
childItemInfo.parent = anItem;
|
||||
childItemInfo.level = level;
|
||||
descendants = descendants.concat(childDescendants);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
itemInfo.weight = descendants.length;
|
||||
|
||||
|
||||
if (!isIntermediate)
|
||||
{
|
||||
// row = -1 is the root item, so just go to row 0 since it is ignored.
|
||||
var index = MAX(itemInfo.row, 0),
|
||||
itemsForRows = _itemsForRows;
|
||||
|
||||
|
||||
descendants.unshift(index, weight);
|
||||
|
||||
|
||||
itemsForRows.splice.apply(itemsForRows, descendants);
|
||||
|
||||
|
||||
var count = itemsForRows.length;
|
||||
|
||||
|
||||
for (; index < count; ++index)
|
||||
itemInfosForItems[[itemsForRows[index] UID]].row = index;
|
||||
|
||||
|
||||
var deltaWeight = itemInfo.weight - weight;
|
||||
|
||||
|
||||
if (deltaWeight !== 0)
|
||||
{
|
||||
var parent = itemInfo.parent;
|
||||
|
||||
|
||||
while (parent)
|
||||
{
|
||||
var parentItemInfo = itemInfosForItems[[parent UID]];
|
||||
|
||||
|
||||
parentItemInfo.weight += deltaWeight;
|
||||
parent = parentItemInfo.parent;
|
||||
}
|
||||
|
||||
|
||||
if (anItem)
|
||||
_rootItemInfo.weight += deltaWeight;
|
||||
}
|
||||
@@ -880,20 +1038,27 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
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
|
||||
{
|
||||
if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_writeItems_toPasteboard_))
|
||||
return NO;
|
||||
|
||||
|
||||
var rowIndexes = [];
|
||||
[theIndexes getIndexes:rowIndexes maxCount:[theIndexes count] inIndexRange:nil];
|
||||
|
||||
|
||||
var rowIndex = [rowIndexes count],
|
||||
items = [];
|
||||
|
||||
|
||||
while (rowIndex--)
|
||||
[items addObject:[_outlineView itemAtRow:[rowIndexes objectAtIndex:rowIndex]]];
|
||||
|
||||
|
||||
return [_outlineView._outlineViewDataSource outlineView:_outlineView writeItems:items toPasteboard:thePasteboard];
|
||||
}
|
||||
|
||||
@@ -901,15 +1066,15 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
{
|
||||
if (_outlineView._shouldRetargetChildIndex)
|
||||
return _outlineView._retargedChildIndex;
|
||||
|
||||
|
||||
var childIndex = CPNotFound;
|
||||
|
||||
|
||||
if (theDropOperation === CPTableViewDropAbove)
|
||||
{
|
||||
var parentItem = [_outlineView _parentItemForUpperRow:theRow - 1 andLowerRow:theRow atMouseOffset:theOffset],
|
||||
itemInfo = (parentItem !== nil) ? _outlineView._itemInfosForItems[[parentItem UID]] : _outlineView._rootItemInfo,
|
||||
children = itemInfo.children;
|
||||
|
||||
|
||||
childIndex = [children indexOfObject:[_outlineView itemAtRow:theRow]];
|
||||
|
||||
if (childIndex === CPNotFound)
|
||||
@@ -924,12 +1089,12 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
- (void)_parentItemForDropOperation:(CPTableViewDropOperation)theDropOperation row:(int)theRow offset:(CPPoint)theOffset
|
||||
{
|
||||
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];
|
||||
}
|
||||
|
||||
- (CPDragOperation)tableView:(CPTableView)aTableView validateDrop:(id < CPDraggingInfo >)theInfo
|
||||
- (CPDragOperation)tableView:(CPTableView)aTableView validateDrop:(id < CPDraggingInfo >)theInfo
|
||||
proposedRow:(int)theRow proposedDropOperation:(CPTableViewDropOperation)theOperation
|
||||
{
|
||||
if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_validateDrop_proposedItem_proposedChildIndex_))
|
||||
@@ -943,21 +1108,21 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
_outlineView._shouldRetargetChildIndex = NO;
|
||||
|
||||
var location = [_outlineView convertPoint:[theInfo draggingLocation] fromView:nil],
|
||||
parentItem = [self _parentItemForDropOperation:theOperation row:theRow offset:location];
|
||||
parentItem = [self _parentItemForDropOperation:theOperation row:theRow offset:location],
|
||||
childIndex = [self _childIndexForDropOperation:theOperation row:theRow offset:location];
|
||||
|
||||
return [_outlineView._outlineViewDataSource outlineView:_outlineView validateDrop:theInfo proposedItem:parentItem proposedChildIndex:childIndex];
|
||||
}
|
||||
|
||||
- (BOOL)tableView:(CPTableView)aTableView acceptDrop:(id <CPDraggingInfo>)theInfo row:(int)theRow dropOperation:(CPTableViewDropOperation)theOperation
|
||||
{
|
||||
{
|
||||
if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_acceptDrop_item_childIndex_))
|
||||
return NO;
|
||||
|
||||
var location = [_outlineView convertPoint:[theInfo draggingLocation] fromView:nil],
|
||||
parentItem = [self _parentItemForDropOperation:theOperation row:theRow offset:location];
|
||||
childIndex = [self _childIndexForDropOperation:theOperation row:theRow offset:location];
|
||||
|
||||
|
||||
_outlineView._retargetedItem = nil;
|
||||
_outlineView._shouldRetargetItem = NO;
|
||||
|
||||
@@ -987,15 +1152,15 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
- (CPView)tableView:(CPTableView)theTableView dataViewForTableColumn:(CPTableColumn)theTableColumn row:(int)theRow
|
||||
{
|
||||
var dataView = nil;
|
||||
|
||||
|
||||
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_))
|
||||
dataView = [_outlineView._outlineViewDelegate outlineView:_outlineView
|
||||
dataViewForTableColumn:theTableColumn
|
||||
dataView = [_outlineView._outlineViewDelegate outlineView:_outlineView
|
||||
dataViewForTableColumn:theTableColumn
|
||||
item:[_outlineView itemAtRow:theRow]];
|
||||
|
||||
if (!dataView)
|
||||
dataView = [theTableColumn dataViewForRow:theRow];
|
||||
|
||||
dataView = [theTableColumn dataViewForRow:theRow];
|
||||
|
||||
return dataView;
|
||||
}
|
||||
|
||||
@@ -1003,10 +1168,18 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
{
|
||||
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_shouldSelectItem_))
|
||||
return [_outlineView._outlineViewDelegate outlineView:_outlineView shouldSelectItem:[_outlineView itemAtRow:theRow]];
|
||||
|
||||
|
||||
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
|
||||
{
|
||||
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_heightOfRowByItem_))
|
||||
@@ -1024,10 +1197,10 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)tableView:(CPTableView)aTableView isGroupRow:(int)row
|
||||
- (BOOL)tableView:(CPTableView)aTableView isGroupRow:(int)aRow
|
||||
{
|
||||
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_isGroupItem_))
|
||||
return [_outlineView._outlineViewDelegate outlineView:_outlineView isGroupItem:[_outlineView itemAtRow:theRow]];
|
||||
return [_outlineView._outlineViewDelegate outlineView:_outlineView isGroupItem:[_outlineView itemAtRow:aRow]];
|
||||
|
||||
return NO;
|
||||
}
|
||||
@@ -1080,9 +1253,82 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
CGContextAddLineToPoint(context, 0.0, 0.0);
|
||||
|
||||
CGContextClosePath(context);
|
||||
|
||||
CGContextSetFillColor(context, [self isHighlighted] ? [CPColor whiteColor] : [CPColor grayColor]);
|
||||
CGContextSetFillColor(context,
|
||||
colorForDisclosureTriangle([self hasThemeState:CPThemeStateSelected],
|
||||
[self hasThemeState:CPThemeStateHighlighted]));
|
||||
CGContextFillPath(context);
|
||||
|
||||
|
||||
CGContextBeginPath(context);
|
||||
CGContextMoveToPoint(context, 0.0, 0.0);
|
||||
if(_angle === 0.0) {
|
||||
CGContextAddLineToPoint(context, 4.5, 8.0);
|
||||
CGContextAddLineToPoint(context, 9.0, 0.0);
|
||||
} else {
|
||||
CGContextAddLineToPoint(context, 4.5, 8.0);
|
||||
}
|
||||
CGContextSetStrokeColor(context, [CPColor colorWithCalibratedWhite:1.0 alpha: 0.8]);
|
||||
CGContextStrokePath(context);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
var CPOutlineViewIndentationPerLevelKey = @"CPOutlineViewIndentationPerLevelKey",
|
||||
CPOutlineViewOutlineTableColumnKey = @"CPOutlineViewOutlineTableColumnKey",
|
||||
CPOutlineViewDataSourceKey = @"CPOutlineViewDataSourceKey",
|
||||
CPOutlineViewDelegateKey = @"CPOutlineViewDelegateKey";
|
||||
|
||||
@implementation CPOutlineView (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
|
||||
if (self)
|
||||
{
|
||||
// The root item has weight "0", thus represents the weight solely of its descendants.
|
||||
_rootItemInfo = { isExpanded:YES, isExpandable:NO, level:-1, row:-1, children:[], weight:0 };
|
||||
|
||||
_itemsForRows = [];
|
||||
_itemInfosForItems = { };
|
||||
_disclosureControlsForRows = [];
|
||||
|
||||
[self setIndentationMarkerFollowsDataView:YES];
|
||||
[self setDisclosureControlPrototype:[[CPDisclosureButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 10.0, 10.0)]];
|
||||
|
||||
_outlineTableColumn = [aCoder decodeObjectForKey:CPOutlineViewOutlineTableColumnKey];
|
||||
_indentationPerLevel = [aCoder decodeFloatForKey:CPOutlineViewIndentationPerLevelKey];
|
||||
|
||||
_outlineViewDataSource = [aCoder decodeObjectForKey:CPOutlineViewDataSourceKey];
|
||||
_outlineViewDelegate = [aCoder decodeObjectForKey:CPOutlineViewDelegateKey];
|
||||
|
||||
[super setDataSource:[[_CPOutlineViewTableViewDataSource alloc] initWithOutlineView:self]];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[aCoder encodeObject:_outlineTableColumn forKey:CPOutlineViewOutlineTableColumnKey];
|
||||
[aCoder encodeFloat:_indentationPerLevel forKey:CPOutlineViewIndentationPerLevelKey];
|
||||
|
||||
[aCoder encodeObject:_outlineViewDataSource forKey:CPOutlineViewDataSourceKey];
|
||||
[aCoder encodeObject:_outlineViewDelegate forKey:CPOutlineViewDelegateKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
var colorForDisclosureTriangle = function(isSelected, isHighlighted) {
|
||||
return isSelected
|
||||
? (isHighlighted
|
||||
? [CPColor colorWithCalibratedWhite:0.9 alpha: 1.0]
|
||||
: [CPColor colorWithCalibratedWhite:1.0 alpha: 1.0])
|
||||
: (isHighlighted
|
||||
? [CPColor colorWithCalibratedWhite:0.4 alpha: 1.0]
|
||||
: [CPColor colorWithCalibratedWhite:0.5 alpha: 1.0]);
|
||||
}
|
||||
|
||||
@@ -25,8 +25,6 @@
|
||||
@import <Foundation/CPDictionary.j>
|
||||
@import <Foundation/CPPropertyListSerialization.j>
|
||||
|
||||
#include "Platform/Platform.h"
|
||||
|
||||
|
||||
CPGeneralPboard = @"CPGeneralPboard";
|
||||
CPFontPboard = @"CPFontPboard";
|
||||
|
||||
+65
-41
@@ -25,14 +25,12 @@
|
||||
@import "CPMenu.j"
|
||||
@import "CPMenuItem.j"
|
||||
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
|
||||
|
||||
var VISIBLE_MARGIN = 7.0;
|
||||
|
||||
CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
|
||||
/*!
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPPopUpButton
|
||||
|
||||
@@ -42,11 +40,11 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
{
|
||||
int _selectedIndex;
|
||||
CPRectEdge _preferredEdge;
|
||||
|
||||
|
||||
CPMenu _menu;
|
||||
}
|
||||
|
||||
+ (CPString)themeClass
|
||||
+ (CPString)defaultThemeClass
|
||||
{
|
||||
return "popup-button";
|
||||
}
|
||||
@@ -60,21 +58,21 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
- (id)initWithFrame:(CGRect)aFrame pullsDown:(BOOL)shouldPullDown
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_selectedIndex = CPNotFound;
|
||||
_preferredEdge = CPMaxYEdge;
|
||||
|
||||
|
||||
[self setValue:CPImageLeft forThemeAttribute:@"image-position"];
|
||||
[self setValue:CPLeftTextAlignment forThemeAttribute:@"alignment"];
|
||||
[self setValue:CPLineBreakByTruncatingTail forThemeAttribute:@"line-break-mode"];
|
||||
|
||||
|
||||
[self setMenu:[[CPMenu alloc] initWithTitle:@""]];
|
||||
|
||||
[self setPullsDown:shouldPullDown];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -145,7 +143,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
{
|
||||
var index = 0,
|
||||
count = [titles count];
|
||||
|
||||
|
||||
for (; index < count; ++index)
|
||||
[self addItemWithTitle:titles[index]];
|
||||
}
|
||||
@@ -159,11 +157,11 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
{
|
||||
var items = [self itemArray],
|
||||
count = [items count];
|
||||
|
||||
|
||||
while (count--)
|
||||
if ([items[count] title] == aTitle)
|
||||
[self removeItemAtIndex:count];
|
||||
|
||||
|
||||
[_menu insertItemWithTitle:aTitle action:NULL keyEquivalent:nil atIndex:anIndex];
|
||||
}
|
||||
|
||||
@@ -173,7 +171,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
- (void)removeAllItems
|
||||
{
|
||||
var count = [_menu numberOfItems];
|
||||
|
||||
|
||||
while (count--)
|
||||
[_menu removeItemAtIndex:0];
|
||||
}
|
||||
@@ -206,7 +204,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
{
|
||||
if (_selectedIndex < 0 || _selectedIndex > [self numberOfItems] - 1)
|
||||
return nil;
|
||||
|
||||
|
||||
return [_menu itemAtIndex:_selectedIndex];
|
||||
}
|
||||
|
||||
@@ -253,15 +251,15 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
{
|
||||
if (_selectedIndex == anIndex)
|
||||
return;
|
||||
|
||||
|
||||
if (_selectedIndex >= 0 && ![self pullsDown])
|
||||
[[self selectedItem] setState:CPOffState];
|
||||
|
||||
|
||||
_selectedIndex = anIndex;
|
||||
|
||||
if (_selectedIndex >= 0 && ![self pullsDown])
|
||||
[[self selectedItem] setState:CPOnState];
|
||||
|
||||
|
||||
[self synchronizeTitleAndSelectedItem];
|
||||
}
|
||||
|
||||
@@ -310,7 +308,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
return;
|
||||
|
||||
var defaultCenter = [CPNotificationCenter defaultCenter];
|
||||
|
||||
|
||||
if (_menu)
|
||||
{
|
||||
[defaultCenter
|
||||
@@ -330,7 +328,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
}
|
||||
|
||||
_menu = aMenu;
|
||||
|
||||
|
||||
if (_menu)
|
||||
{
|
||||
[defaultCenter
|
||||
@@ -338,20 +336,20 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
selector:@selector(menuDidAddItem:)
|
||||
name:CPMenuDidAddItemNotification
|
||||
object:_menu];
|
||||
|
||||
|
||||
[defaultCenter
|
||||
addObserver:self
|
||||
selector:@selector(menuDidChangeItem:)
|
||||
name:CPMenuDidChangeItemNotification
|
||||
object:_menu];
|
||||
|
||||
|
||||
[defaultCenter
|
||||
addObserver:self
|
||||
selector:@selector(menuDidRemoveItem:)
|
||||
name:CPMenuDidRemoveItemNotification
|
||||
object:_menu];
|
||||
}
|
||||
|
||||
|
||||
[self synchronizeTitleAndSelectedItem];
|
||||
}
|
||||
|
||||
@@ -396,12 +394,13 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
{
|
||||
var titles = [],
|
||||
items = [self itemArray],
|
||||
|
||||
index = 0,
|
||||
count = [items count];
|
||||
|
||||
|
||||
for (; index < count; ++index)
|
||||
items.push([items[index] title]);
|
||||
titles.push([items[index] title]);
|
||||
|
||||
return titles;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -519,14 +518,14 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
else
|
||||
{
|
||||
var index = [self indexOfItemWithTitle:aTitle];
|
||||
|
||||
|
||||
if (index < 0)
|
||||
{
|
||||
[self addItemWithTitle:aTitle];
|
||||
|
||||
|
||||
index = [self numberOfItems] - 1;
|
||||
}
|
||||
|
||||
|
||||
[self selectItemAtIndex:index];
|
||||
}
|
||||
}
|
||||
@@ -554,7 +553,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
if ([self pullsDown])
|
||||
{
|
||||
var items = [_menu itemArray];
|
||||
|
||||
|
||||
if ([items count] > 0)
|
||||
item = items[0];
|
||||
}
|
||||
@@ -573,22 +572,22 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
- (void)menuDidAddItem:(CPNotification)aNotification
|
||||
{
|
||||
var index = [[aNotification userInfo] objectForKey:@"CPMenuItemIndex"];
|
||||
|
||||
|
||||
if (_selectedIndex < 0)
|
||||
[self selectItemAtIndex:0];
|
||||
|
||||
|
||||
else if (index == _selectedIndex)
|
||||
[self synchronizeTitleAndSelectedItem];
|
||||
|
||||
|
||||
else if (index < _selectedIndex)
|
||||
++_selectedIndex;
|
||||
|
||||
|
||||
if (index == 0 && [self pullsDown])
|
||||
{
|
||||
var items = [_menu itemArray];
|
||||
|
||||
|
||||
[items[0] setHidden:YES];
|
||||
|
||||
|
||||
if (items.length > 0)
|
||||
[items[1] setHidden:NO];
|
||||
}
|
||||
@@ -613,10 +612,10 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
|
||||
if ([self pullsDown] && index != 0)
|
||||
return;
|
||||
|
||||
|
||||
if (![self pullsDown] && index != _selectedIndex)
|
||||
return;
|
||||
|
||||
|
||||
[self synchronizeTitleAndSelectedItem];
|
||||
}
|
||||
|
||||
@@ -627,7 +626,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
- (void)menuDidRemoveItem:(CPNotification)aNotification
|
||||
{
|
||||
var numberOfItems = [self numberOfItems];
|
||||
|
||||
|
||||
if (numberOfItems <= _selectedIndex && numberOfItems > 0)
|
||||
[self selectItemAtIndex:numberOfItems - 1];
|
||||
else
|
||||
@@ -661,6 +660,9 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
location = CGPointMake(CGRectGetMinX(contentRect) - standardLeftMargin, 0.0);
|
||||
|
||||
minimumWidth += standardLeftMargin;
|
||||
|
||||
// To ensure the selected item is highlighted correctly, unset the highlighted item
|
||||
[menu _highlightItemAtIndex:CPNotFound];
|
||||
}
|
||||
|
||||
[menu setMinimumWidth:minimumWidth];
|
||||
@@ -698,11 +700,33 @@ 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
|
||||
{
|
||||
[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
|
||||
|
||||
var CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey",
|
||||
@@ -720,7 +744,7 @@ var CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey",
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
// Nothing is currently selected
|
||||
@@ -729,7 +753,7 @@ var CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey",
|
||||
[self setMenu:[aCoder decodeObjectForKey:CPPopUpButtonMenuKey]];
|
||||
[self selectItemAtIndex:[aCoder decodeObjectForKey:CPPopUpButtonSelectedIndexKey]];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -741,7 +765,7 @@ var CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey",
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
|
||||
[aCoder encodeObject:_menu forKey:CPPopUpButtonMenuKey];
|
||||
[aCoder encodeInt:_selectedIndex forKey:CPPopUpButtonSelectedIndexKey];
|
||||
}
|
||||
|
||||
@@ -20,11 +20,9 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <AppKit/CGGeometry.j>
|
||||
@import <AppKit/CPImageView.j>
|
||||
@import <AppKit/CPView.j>
|
||||
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
@import "CGGeometry.j"
|
||||
@import "CPImageView.j"
|
||||
@import "CPView.j"
|
||||
|
||||
|
||||
/*
|
||||
|
||||
+19
-15
@@ -25,28 +25,29 @@
|
||||
|
||||
@import "CPButton.j"
|
||||
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
|
||||
|
||||
from this mailing list thread:
|
||||
http://groups.google.com/group/objectivej/browse_thread/thread/7c41cbd9cbee9ea3
|
||||
|
||||
http://groups.google.com/group/objectivej/browse_thread/thread/7c41cbd9cbee9ea3
|
||||
|
||||
-----------------------------------
|
||||
|
||||
|
||||
Creating a checkbox is easy enough:
|
||||
|
||||
|
||||
checkbox = [[CPCheckBox alloc] initWithFrame:aFrame];
|
||||
|
||||
|
||||
That's basically all there is to it. Radio buttons are very similar,
|
||||
the key difference is the introduction of a new class CPRadioGroup,
|
||||
which defines which radio buttons are part of the same group:
|
||||
|
||||
|
||||
[myRadioButton setRadioGroup:aRadioGroup];
|
||||
|
||||
|
||||
Every radio button receives a unique radio group by default (so if you
|
||||
do nothing further, they will all behave independently), but you can
|
||||
use an existing radio button's group with other buttons as so:
|
||||
|
||||
|
||||
button1 = [[CPRadio alloc] initWithFrame:aFrame];
|
||||
...
|
||||
button2 = [[CPRadio alloc] initWithFrame:aFrame radioGroup:[button1
|
||||
@@ -55,13 +56,16 @@
|
||||
button3 = [[CPRadio alloc] initWithFrame:aFrame radioGroup:[button1
|
||||
radioGroup]];
|
||||
...etc...
|
||||
|
||||
|
||||
Here, all the radio buttons will act "together". [[button1 radioGroup]
|
||||
allRadios] returns every button that's part of this group, and
|
||||
[[button1 radioGroup] selectedRadio] returns the currently selected
|
||||
option.
|
||||
|
||||
*/
|
||||
|
||||
CPRadioImageOffset = 4.0;
|
||||
|
||||
@implementation CPRadio : CPButton
|
||||
{
|
||||
CPRadioGroup _radioGroup;
|
||||
@@ -86,7 +90,7 @@
|
||||
return button;
|
||||
}
|
||||
|
||||
+ (CPString)themeClass
|
||||
+ (CPString)defaultThemeClass
|
||||
{
|
||||
return @"radio";
|
||||
}
|
||||
@@ -95,7 +99,7 @@
|
||||
- (id)initWithFrame:(CGRect)aFrame radioGroup:(CPRadioGroup)aRadioGroup
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
[self setRadioGroup:aRadioGroup];
|
||||
@@ -109,8 +113,8 @@
|
||||
|
||||
[self setBordered:YES];
|
||||
}
|
||||
|
||||
return self;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
@@ -141,7 +145,7 @@
|
||||
- (void)setObjectValue:(id)aValue
|
||||
{
|
||||
[super setObjectValue:aValue];
|
||||
|
||||
|
||||
if ([self state] === CPOnState)
|
||||
[_radioGroup _setSelectedRadio:self];
|
||||
}
|
||||
|
||||
+47
-53
@@ -23,22 +23,23 @@
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
|
||||
CPDeleteKeyCode = 8;
|
||||
CPTabKeyCode = 9;
|
||||
CPReturnKeyCode = 13;
|
||||
CPEscapeKeyCode = 27;
|
||||
CPSpaceKeyCode = 32;
|
||||
CPPageUpKeyCode = 33;
|
||||
CPPageDownKeyCode = 34;
|
||||
CPLeftArrowKeyCode = 37;
|
||||
CPUpArrowKeyCode = 38;
|
||||
CPRightArrowKeyCode = 39;
|
||||
CPDownArrowKeyCode = 40;
|
||||
CPDeleteKeyCode = 8;
|
||||
CPTabKeyCode = 9;
|
||||
CPReturnKeyCode = 13;
|
||||
CPEscapeKeyCode = 27;
|
||||
CPSpaceKeyCode = 32;
|
||||
CPPageUpKeyCode = 33;
|
||||
CPPageDownKeyCode = 34;
|
||||
CPLeftArrowKeyCode = 37;
|
||||
CPUpArrowKeyCode = 38;
|
||||
CPRightArrowKeyCode = 39;
|
||||
CPDownArrowKeyCode = 40;
|
||||
CPDeleteForwardKeyCode = 46;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPResponder
|
||||
|
||||
|
||||
Subclasses of CPResonder can be part of the responder chain.
|
||||
*/
|
||||
@implementation CPResponder : CPObject
|
||||
@@ -104,42 +105,24 @@ CPDownArrowKeyCode = 40;
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var event = events[index];
|
||||
var event = events[index],
|
||||
modifierFlags = [event modifierFlags],
|
||||
character = [event charactersIgnoringModifiers],
|
||||
selectorNames = [CPKeyBinding selectorsForKey:character modifierFlags:modifierFlags];
|
||||
|
||||
switch([event keyCode])
|
||||
if (selectorNames)
|
||||
{
|
||||
case CPPageUpKeyCode: [self doCommandBySelector:@selector(pageUp:)];
|
||||
break;
|
||||
case CPPageDownKeyCode: [self doCommandBySelector:@selector(pageDown:)];
|
||||
break;
|
||||
case CPLeftArrowKeyCode: [self doCommandBySelector:@selector(moveLeft:)];
|
||||
break;
|
||||
case CPRightArrowKeyCode: [self doCommandBySelector:@selector(moveRight:)];
|
||||
break;
|
||||
case CPUpArrowKeyCode: [self doCommandBySelector:@selector(moveUp:)];
|
||||
break;
|
||||
case CPDownArrowKeyCode: [self doCommandBySelector:@selector(moveDown:)];
|
||||
break;
|
||||
case CPDeleteKeyCode: [self doCommandBySelector:@selector(deleteBackward:)];
|
||||
break;
|
||||
case CPReturnKeyCode:
|
||||
case 3: [self doCommandBySelector:@selector(insertLineBreak:)];
|
||||
break;
|
||||
|
||||
case CPEscapeKeyCode: [self doCommandBySelector:@selector(cancel:)];
|
||||
break;
|
||||
for (var s = 0, scount = selectorNames.length; s < scount; s++)
|
||||
{
|
||||
var selector = selectorNames[s];
|
||||
if (!selector)
|
||||
continue;
|
||||
|
||||
case CPTabKeyCode: var shift = [event modifierFlags] & CPShiftKeyMask;
|
||||
|
||||
if (!shift)
|
||||
[self doCommandBySelector:@selector(insertTab:)];
|
||||
else
|
||||
[self doCommandBySelector:@selector(insertBackTab:)];
|
||||
|
||||
break;
|
||||
|
||||
default: [self insertText:[event characters]];
|
||||
[self doCommandBySelector:CPSelectorFromString(selector)];
|
||||
}
|
||||
}
|
||||
else if (!(modifierFlags & (CPCommandKeyMask | CPControlKeyMask)) && [self respondsToSelector:@selector(insertText:)])
|
||||
[self insertText:[event characters]];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,6 +222,15 @@ CPDownArrowKeyCode = 40;
|
||||
[_nextResponder performSelector:_cmd withObject:anEvent];
|
||||
}
|
||||
|
||||
/*!
|
||||
Notifies the receiver that the user has pressed or released a modifier key (Shift, Control, and so on).
|
||||
@param anEvent information about the key press
|
||||
*/
|
||||
- (void)flagsChanged:(CPEvent)anEvent
|
||||
{
|
||||
[_nextResponder performSelector:_cmd withObject:anEvent];
|
||||
}
|
||||
|
||||
/*
|
||||
FIXME This description is bad.
|
||||
Based on \c anEvent, the receiver should simulate the event.
|
||||
@@ -269,10 +261,6 @@ CPDownArrowKeyCode = 40;
|
||||
[[self nextResponder] insertNewline:aSender];
|
||||
}
|
||||
|
||||
- (void)cancel:(id)sender
|
||||
{
|
||||
}
|
||||
|
||||
- (void)insertTab:(id)sender
|
||||
{
|
||||
}
|
||||
@@ -312,10 +300,10 @@ CPDownArrowKeyCode = 40;
|
||||
*/
|
||||
- (BOOL)tryToPerform:(SEL)aSelector with:(id)anObject
|
||||
{
|
||||
if([self respondsToSelector:aSelector])
|
||||
if ([self respondsToSelector:aSelector])
|
||||
{
|
||||
[self performSelector:aSelector withObject:anObject];
|
||||
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
@@ -354,7 +342,8 @@ CPDownArrowKeyCode = 40;
|
||||
|
||||
@end
|
||||
|
||||
var CPResponderNextResponderKey = @"CPResponderNextResponderKey";
|
||||
var CPResponderNextResponderKey = @"CPResponderNextResponderKey",
|
||||
CPResponderMenuKey = @"CPResponderMenuKey";
|
||||
|
||||
@implementation CPResponder (CPCoding)
|
||||
|
||||
@@ -366,10 +355,13 @@ var CPResponderNextResponderKey = @"CPResponderNextResponderKey";
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_nextResponder = [aCoder decodeObjectForKey:CPResponderNextResponderKey];
|
||||
|
||||
_menu = [aCoder decodeObjectForKey:CPResponderMenuKey];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -382,6 +374,8 @@ var CPResponderNextResponderKey = @"CPResponderNextResponderKey";
|
||||
// This will come out nil on the other side with decodeObjectForKey:
|
||||
if (_nextResponder !== nil)
|
||||
[aCoder encodeConditionalObject:_nextResponder forKey:CPResponderNextResponderKey];
|
||||
|
||||
[aCoder encodeObject:_menu forKey:CPResponderMenuKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
@import <AppKit/CPPanel.j>
|
||||
@import "CPPanel.j"
|
||||
|
||||
|
||||
@implementation CPSavePanel : CPPanel
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
#import "CoreGraphics/CGGeometry.h"
|
||||
#import "Platform/Platform.h"
|
||||
|
||||
@implementation CPScreen : CPObject
|
||||
{
|
||||
|
||||
+386
-96
@@ -20,14 +20,13 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CPView.j"
|
||||
@import "CPBox.j"
|
||||
@import "CPClipView.j"
|
||||
@import "CPScroller.j"
|
||||
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
@import "CPView.j"
|
||||
|
||||
|
||||
/*!
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPScrollView
|
||||
|
||||
@@ -37,23 +36,39 @@
|
||||
*/
|
||||
@implementation CPScrollView : CPView
|
||||
{
|
||||
CPClipView _contentView;
|
||||
CPClipView _headerClipView;
|
||||
CPView _cornerView;
|
||||
CPClipView _contentView;
|
||||
CPClipView _headerClipView;
|
||||
CPView _cornerView;
|
||||
CPView _bottomCornerView;
|
||||
|
||||
BOOL _hasVerticalScroller;
|
||||
BOOL _hasHorizontalScroller;
|
||||
BOOL _autohidesScrollers;
|
||||
|
||||
CPScroller _verticalScroller;
|
||||
CPScroller _horizontalScroller;
|
||||
|
||||
int _recursionCount;
|
||||
|
||||
float _verticalLineScroll;
|
||||
float _verticalPageScroll;
|
||||
float _horizontalLineScroll;
|
||||
float _horizontalPageScroll;
|
||||
BOOL _hasVerticalScroller;
|
||||
BOOL _hasHorizontalScroller;
|
||||
BOOL _autohidesScrollers;
|
||||
|
||||
CPScroller _verticalScroller;
|
||||
CPScroller _horizontalScroller;
|
||||
|
||||
int _recursionCount;
|
||||
|
||||
float _verticalLineScroll;
|
||||
float _verticalPageScroll;
|
||||
float _horizontalLineScroll;
|
||||
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
|
||||
@@ -68,14 +83,18 @@
|
||||
_horizontalLineScroll = 10.0;
|
||||
_horizontalPageScroll = 10.0;
|
||||
|
||||
_contentView = [[CPClipView alloc] initWithFrame:[self bounds]];
|
||||
_borderType = CPNoBorder;
|
||||
|
||||
_contentView = [[CPClipView alloc] initWithFrame:[self _insetBounds]];
|
||||
|
||||
[self addSubview:_contentView];
|
||||
|
||||
_headerClipView = [[CPClipView alloc] init];
|
||||
|
||||
[self addSubview:_headerClipView];
|
||||
|
||||
_bottomCornerView = [[CPView alloc] init];
|
||||
[self addSubview:_bottomCornerView];
|
||||
|
||||
[self setHasVerticalScroller:YES];
|
||||
[self setHasHorizontalScroller:YES];
|
||||
}
|
||||
@@ -83,11 +102,70 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
// Calculating Layout
|
||||
|
||||
+ (CGSize)contentSizeForFrameSize:(CGSize)frameSize hasHorizontalScroller:(BOOL)hFlag hasVerticalScroller:(BOOL)vFlag borderType:(CPBorderType)borderType
|
||||
{
|
||||
var bounds = [self _insetBounds:_CGRectMake(0.0, 0.0, frameSize.width, frameSize.height) borderType:borderType],
|
||||
scrollerWidth = [CPScroller scrollerWidth];
|
||||
|
||||
if (hFlag)
|
||||
bounds.size.height -= scrollerWidth;
|
||||
|
||||
if (vFlag)
|
||||
bounds.size.width -= scrollerWidth;
|
||||
|
||||
return bounds.size;
|
||||
}
|
||||
|
||||
+ (CGSize)frameSizeForContentSize:(CGSize)contentSize hasHorizontalScroller:(BOOL)hFlag hasVerticalScroller:(BOOL)vFlag borderType:(CPBorderType)borderType
|
||||
{
|
||||
var bounds = [self _insetBounds:_CGRectMake(0.0, 0.0, contentSize.width, contentSize.height) borderType:borderType],
|
||||
widthInset = contentSize.width - bounds.size.width,
|
||||
heightInset = contentSize.height - bounds.size.height,
|
||||
frameSize = _CGSizeMake(contentSize.width + widthInset, contentSize.height + heightInset),
|
||||
scrollerWidth = [CPScroller scrollerWidth];
|
||||
|
||||
if (hFlag)
|
||||
frameSize.height -= scrollerWidth;
|
||||
|
||||
if (vFlag)
|
||||
frameSize.width -= scrollerWidth;
|
||||
|
||||
return frameSize;
|
||||
}
|
||||
|
||||
+ (CGRect)_insetBounds:(CGRect)bounds borderType:(CPBorderType)borderType
|
||||
{
|
||||
switch (borderType)
|
||||
{
|
||||
case CPLineBorder:
|
||||
case CPBezelBorder:
|
||||
return _CGRectInset(bounds, 1.0, 1.0);
|
||||
|
||||
case CPGrooveBorder:
|
||||
bounds = _CGRectInset(bounds, 2.0, 2.0);
|
||||
++bounds.origin.y;
|
||||
--bounds.size.height;
|
||||
|
||||
return bounds;
|
||||
|
||||
case CPNoBorder:
|
||||
default:
|
||||
return bounds;
|
||||
}
|
||||
}
|
||||
|
||||
- (CGRect)_insetBounds
|
||||
{
|
||||
return [[self class] _insetBounds:[self bounds] borderType:_borderType];
|
||||
}
|
||||
|
||||
// Determining component sizes
|
||||
/*!
|
||||
Returns the size of the scroll view's content view.
|
||||
*/
|
||||
- (CGRect)contentSize
|
||||
- (CGSize)contentSize
|
||||
{
|
||||
return [_contentView frame].size;
|
||||
}
|
||||
@@ -106,7 +184,7 @@
|
||||
*/
|
||||
- (void)setContentView:(CPClipView)aContentView
|
||||
{
|
||||
if (_contentView !== aContentView || !aContentView)
|
||||
if (_contentView === aContentView || !aContentView)
|
||||
return;
|
||||
|
||||
var documentView = [aContentView documentView];
|
||||
@@ -153,16 +231,16 @@
|
||||
*/
|
||||
- (void)reflectScrolledClipView:(CPClipView)aClipView
|
||||
{
|
||||
if(_contentView !== aClipView)
|
||||
if (_contentView !== aClipView)
|
||||
return;
|
||||
|
||||
if (_recursionCount > 5)
|
||||
return;
|
||||
|
||||
|
||||
++_recursionCount;
|
||||
|
||||
var documentView = [self documentView];
|
||||
|
||||
|
||||
if (!documentView)
|
||||
{
|
||||
if (_autohidesScrollers)
|
||||
@@ -176,7 +254,7 @@
|
||||
// [_horizontalScroller setEnabled:NO];
|
||||
}
|
||||
|
||||
[_contentView setFrame:[self bounds]];
|
||||
[_contentView setFrame:[self _insetBounds]];
|
||||
[_headerClipView setFrame:_CGRectMakeZero()];
|
||||
|
||||
--_recursionCount;
|
||||
@@ -185,7 +263,7 @@
|
||||
}
|
||||
|
||||
var documentFrame = [documentView frame], // the size of the whole document
|
||||
contentFrame = [self bounds], // assume it takes up the entire size of the scrollview (no scrollers)
|
||||
contentFrame = [self _insetBounds], // assume it takes up the entire size of the scrollview (no scrollers)
|
||||
headerClipViewFrame = [self _headerClipViewFrame],
|
||||
headerClipViewHeight = _CGRectGetHeight(headerClipViewFrame);
|
||||
|
||||
@@ -235,11 +313,10 @@
|
||||
|
||||
if (shouldShowVerticalScroller)
|
||||
{
|
||||
var verticalScrollerY = MAX(_CGRectGetHeight([self _cornerViewFrame]), headerClipViewHeight),
|
||||
verticalScrollerHeight = _CGRectGetHeight([self bounds]) - verticalScrollerY;
|
||||
var verticalScrollerY =
|
||||
MAX(_CGRectGetMinY(contentFrame), MAX(_CGRectGetMaxY([self _cornerViewFrame]), _CGRectGetMaxY(headerClipViewFrame)));
|
||||
|
||||
if (shouldShowHorizontalScroller)
|
||||
verticalScrollerHeight -= horizontalScrollerHeight;
|
||||
var verticalScrollerHeight = _CGRectGetMaxY(contentFrame) - verticalScrollerY;
|
||||
|
||||
[_verticalScroller setFloatValue:(difference.height <= 0.0) ? 0.0 : scrollPoint.y / difference.height];
|
||||
[_verticalScroller setKnobProportion:_CGRectGetHeight(contentFrame) / _CGRectGetHeight(documentFrame)];
|
||||
@@ -250,12 +327,12 @@
|
||||
[_verticalScroller setFloatValue:0.0];
|
||||
[_verticalScroller setKnobProportion:1.0];
|
||||
}
|
||||
|
||||
|
||||
if (shouldShowHorizontalScroller)
|
||||
{
|
||||
[_horizontalScroller setFloatValue:(difference.width <= 0.0) ? 0.0 : scrollPoint.x / difference.width];
|
||||
[_horizontalScroller setKnobProportion:_CGRectGetWidth(contentFrame) / _CGRectGetWidth(documentFrame)];
|
||||
[_horizontalScroller setFrame:_CGRectMake(0.0, _CGRectGetMaxY(contentFrame), _CGRectGetWidth(contentFrame), horizontalScrollerHeight)];
|
||||
[_horizontalScroller setFrame:_CGRectMake(_CGRectGetMinX(contentFrame), _CGRectGetMaxY(contentFrame), _CGRectGetWidth(contentFrame), horizontalScrollerHeight)];
|
||||
}
|
||||
else if (wasShowingHorizontalScroller)
|
||||
{
|
||||
@@ -267,9 +344,36 @@
|
||||
[_headerClipView setFrame:headerClipViewFrame];
|
||||
[_cornerView setFrame:[self _cornerViewFrame]];
|
||||
|
||||
[[self bottomCornerView] setFrame:[self _bottomCornerViewFrame]];
|
||||
[[self bottomCornerView] setBackgroundColor:[self currentValueForThemeAttribute:@"bottom-corner-color"]];
|
||||
|
||||
--_recursionCount;
|
||||
}
|
||||
|
||||
// Managing Graphics Attributes
|
||||
|
||||
/*!
|
||||
Sets the type of border to be drawn around the view.
|
||||
*/
|
||||
- (void)setBorderType:(CPBorderType)borderType
|
||||
{
|
||||
if (_borderType == borderType)
|
||||
return;
|
||||
|
||||
_borderType = borderType;
|
||||
|
||||
[self reflectScrolledClipView:_contentView];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the border type drawn around the view.
|
||||
*/
|
||||
- (CPBorderType)borderType
|
||||
{
|
||||
return _borderType;
|
||||
}
|
||||
|
||||
// Managing Scrollers
|
||||
/*!
|
||||
Sets the scroll view's horizontal scroller.
|
||||
@@ -279,13 +383,13 @@
|
||||
{
|
||||
if (_horizontalScroller === aScroller)
|
||||
return;
|
||||
|
||||
|
||||
[_horizontalScroller removeFromSuperview];
|
||||
[_horizontalScroller setTarget:nil];
|
||||
[_horizontalScroller setAction:nil];
|
||||
|
||||
|
||||
_horizontalScroller = aScroller;
|
||||
|
||||
|
||||
[_horizontalScroller setTarget:self];
|
||||
[_horizontalScroller setAction:@selector(_horizontalScrollerDidScroll:)];
|
||||
|
||||
@@ -316,8 +420,10 @@
|
||||
|
||||
if (_hasHorizontalScroller && !_horizontalScroller)
|
||||
{
|
||||
[self setHorizontalScroller:[[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, MAX(_CGRectGetWidth([self bounds]), [CPScroller scrollerWidth]+1), [CPScroller scrollerWidth])]];
|
||||
[[self horizontalScroller] setFrameSize:CGSizeMake(_CGRectGetWidth([self bounds]), [CPScroller scrollerWidth])];
|
||||
var bounds = [self _insetBounds];
|
||||
|
||||
[self setHorizontalScroller:[[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, MAX(_CGRectGetWidth(bounds), [CPScroller scrollerWidth] + 1), [CPScroller scrollerWidth])]];
|
||||
[[self horizontalScroller] setFrameSize:CGSizeMake(_CGRectGetWidth(bounds), [CPScroller scrollerWidth])];
|
||||
}
|
||||
|
||||
[self reflectScrolledClipView:_contentView];
|
||||
@@ -339,13 +445,13 @@
|
||||
{
|
||||
if (_verticalScroller === aScroller)
|
||||
return;
|
||||
|
||||
|
||||
[_verticalScroller removeFromSuperview];
|
||||
[_verticalScroller setTarget:nil];
|
||||
[_verticalScroller setAction:nil];
|
||||
|
||||
|
||||
_verticalScroller = aScroller;
|
||||
|
||||
|
||||
[_verticalScroller setTarget:self];
|
||||
[_verticalScroller setAction:@selector(_verticalScrollerDidScroll:)];
|
||||
|
||||
@@ -377,8 +483,10 @@
|
||||
|
||||
if (_hasVerticalScroller && !_verticalScroller)
|
||||
{
|
||||
[self setVerticalScroller:[[CPScroller alloc] initWithFrame:_CGRectMake(0.0, 0.0, [CPScroller scrollerWidth], MAX(_CGRectGetHeight([self bounds]), [CPScroller scrollerWidth]+1))]];
|
||||
[[self verticalScroller] setFrameSize:CGSizeMake([CPScroller scrollerWidth], _CGRectGetHeight([self bounds]))];
|
||||
var bounds = [self _insetBounds];
|
||||
|
||||
[self setVerticalScroller:[[CPScroller alloc] initWithFrame:_CGRectMake(0.0, 0.0, [CPScroller scrollerWidth], MAX(_CGRectGetHeight(bounds), [CPScroller scrollerWidth] + 1))]];
|
||||
[[self verticalScroller] setFrameSize:CGSizeMake([CPScroller scrollerWidth], _CGRectGetHeight(bounds))];
|
||||
}
|
||||
|
||||
[self reflectScrolledClipView:_contentView];
|
||||
@@ -403,7 +511,7 @@
|
||||
return;
|
||||
|
||||
_autohidesScrollers = autohidesScrollers;
|
||||
|
||||
|
||||
[self reflectScrolledClipView:_contentView];
|
||||
}
|
||||
|
||||
@@ -445,9 +553,7 @@
|
||||
|
||||
- (CPView)_headerView
|
||||
{
|
||||
var headerClipViewSubviews = [_headerClipView subviews];
|
||||
|
||||
return [headerClipViewSubviews count] ? headerClipViewSubviews[0] : nil;
|
||||
return [_headerClipView documentView];
|
||||
}
|
||||
|
||||
- (CGRect)_cornerViewFrame
|
||||
@@ -455,11 +561,11 @@
|
||||
if (!_cornerView)
|
||||
return _CGRectMakeZero();
|
||||
|
||||
var bounds = [self bounds],
|
||||
var bounds = [self _insetBounds],
|
||||
frame = [_cornerView frame];
|
||||
|
||||
frame.origin.x = _CGRectGetMaxX(bounds) - _CGRectGetWidth(frame);
|
||||
frame.origin.y = 0;
|
||||
frame.origin.y = _CGRectGetMinY(bounds);
|
||||
|
||||
return frame;
|
||||
}
|
||||
@@ -471,7 +577,7 @@
|
||||
if (!headerView)
|
||||
return _CGRectMakeZero();
|
||||
|
||||
var frame = [self bounds];
|
||||
var frame = [self _insetBounds];
|
||||
|
||||
frame.size.height = _CGRectGetHeight([headerView frame]);
|
||||
frame.size.width -= _CGRectGetWidth([self _cornerViewFrame]);
|
||||
@@ -479,33 +585,69 @@
|
||||
return frame;
|
||||
}
|
||||
|
||||
- (CGRect)_bottomCornerViewFrame
|
||||
{
|
||||
if ([[self horizontalScroller] isHidden] || [[self verticalScroller] isHidden])
|
||||
return CGRectMakeZero();
|
||||
|
||||
var verticalFrame = [[self verticalScroller] frame],
|
||||
bottomCornerFrame = CGRectMakeZero();
|
||||
|
||||
bottomCornerFrame.origin.x = CGRectGetMinX(verticalFrame);
|
||||
bottomCornerFrame.origin.y = CGRectGetMaxY(verticalFrame);
|
||||
bottomCornerFrame.size.width = [CPScroller scrollerWidth];
|
||||
bottomCornerFrame.size.height = [CPScroller scrollerWidth];
|
||||
|
||||
return bottomCornerFrame;
|
||||
}
|
||||
|
||||
- (void)setBottomCornerView:(CPView)aBottomCornerView
|
||||
{
|
||||
if (_bottomCornerView === aBottomCornerView)
|
||||
return;
|
||||
|
||||
[_bottomCornerView removeFromSuperview];
|
||||
|
||||
[aBottomCornerView setFrame:[self _bottomCornerViewFrame]];
|
||||
[self addSubview:aBottomCornerView];
|
||||
|
||||
_bottomCornerView = aBottomCornerView;
|
||||
|
||||
[self _updateCornerAndHeaderView];
|
||||
}
|
||||
|
||||
- (CPView)bottomCornerView
|
||||
{
|
||||
return _bottomCornerView;
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (void)_verticalScrollerDidScroll:(CPScroller)aScroller
|
||||
{
|
||||
var value = [aScroller floatValue],
|
||||
documentFrame = [[_contentView documentView] frame];
|
||||
var value = [aScroller floatValue],
|
||||
documentFrame = [[_contentView documentView] frame],
|
||||
contentBounds = [_contentView bounds];
|
||||
|
||||
switch ([_verticalScroller hitPart])
|
||||
{
|
||||
case CPScrollerDecrementLine: contentBounds.origin.y -= _verticalLineScroll;
|
||||
break;
|
||||
|
||||
|
||||
case CPScrollerIncrementLine: contentBounds.origin.y += _verticalLineScroll;
|
||||
break;
|
||||
|
||||
|
||||
case CPScrollerDecrementPage: contentBounds.origin.y -= _CGRectGetHeight(contentBounds) - _verticalPageScroll;
|
||||
break;
|
||||
|
||||
|
||||
case CPScrollerIncrementPage: contentBounds.origin.y += _CGRectGetHeight(contentBounds) - _verticalPageScroll;
|
||||
break;
|
||||
|
||||
|
||||
case CPScrollerKnobSlot:
|
||||
case CPScrollerKnob:
|
||||
// We want integral bounds!
|
||||
default: contentBounds.origin.y = ROUND(value * (_CGRectGetHeight(documentFrame) - _CGRectGetHeight(contentBounds)));
|
||||
}
|
||||
|
||||
|
||||
[_contentView scrollToPoint:contentBounds.origin];
|
||||
}
|
||||
|
||||
@@ -515,21 +657,21 @@
|
||||
var value = [aScroller floatValue],
|
||||
documentFrame = [[self documentView] frame],
|
||||
contentBounds = [_contentView bounds];
|
||||
|
||||
|
||||
switch ([_horizontalScroller hitPart])
|
||||
{
|
||||
case CPScrollerDecrementLine: contentBounds.origin.x -= _horizontalLineScroll;
|
||||
break;
|
||||
|
||||
|
||||
case CPScrollerIncrementLine: contentBounds.origin.x += _horizontalLineScroll;
|
||||
break;
|
||||
|
||||
|
||||
case CPScrollerDecrementPage: contentBounds.origin.x -= _CGRectGetWidth(contentBounds) - _horizontalPageScroll;
|
||||
break;
|
||||
|
||||
|
||||
case CPScrollerIncrementPage: contentBounds.origin.x += _CGRectGetWidth(contentBounds) - _horizontalPageScroll;
|
||||
break;
|
||||
|
||||
|
||||
case CPScrollerKnobSlot:
|
||||
case CPScrollerKnob:
|
||||
// We want integral bounds!
|
||||
@@ -554,7 +696,7 @@
|
||||
/*
|
||||
@ignore
|
||||
*/
|
||||
-(void)resizeSubviewsWithOldSize:(CGSize)aSize
|
||||
- (void)resizeSubviewsWithOldSize:(CGSize)aSize
|
||||
{
|
||||
[self reflectScrolledClipView:_contentView];
|
||||
}
|
||||
@@ -664,35 +806,169 @@
|
||||
return _verticalPageScroll;
|
||||
}
|
||||
|
||||
// CPView Overrides
|
||||
|
||||
- (void)drawRect:(CPRect)aRect
|
||||
{
|
||||
[super drawRect:aRect];
|
||||
|
||||
if (_borderType == CPNoBorder)
|
||||
return;
|
||||
|
||||
var strokeRect = [self bounds],
|
||||
context = [[CPGraphicsContext currentContext] graphicsPort];
|
||||
|
||||
CGContextSetLineWidth(context, 1);
|
||||
|
||||
switch (_borderType)
|
||||
{
|
||||
case CPLineBorder:
|
||||
CGContextSetStrokeColor(context, [self currentValueForThemeAttribute:@"border-color"]);
|
||||
CGContextStrokeRect(context, _CGRectInset(strokeRect, 0.5, 0.5));
|
||||
break;
|
||||
|
||||
case CPBezelBorder:
|
||||
[self _drawGrayBezelInContext:context bounds:strokeRect];
|
||||
break;
|
||||
|
||||
case CPGrooveBorder:
|
||||
[self _drawGrooveInContext:context bounds:strokeRect];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_drawGrayBezelInContext:(CGContext)context bounds:(CGRect)aRect
|
||||
{
|
||||
CGContextBeginPath(context);
|
||||
CGContextSetStrokeColor(context, [CPColor colorWithWhite:142.0 / 255.0 alpha:1.0]);
|
||||
|
||||
var y = _CGRectGetMinY(aRect) + 0.5;
|
||||
|
||||
CGContextMoveToPoint(context, _CGRectGetMinX(aRect), y);
|
||||
CGContextAddLineToPoint(context, _CGRectGetMinX(aRect) + 1.0, y);
|
||||
CGContextStrokePath(context);
|
||||
|
||||
CGContextBeginPath(context);
|
||||
CGContextSetStrokeColor(context, [CPColor colorWithWhite:192.0 / 255.0 alpha:1.0]);
|
||||
CGContextMoveToPoint(context, _CGRectGetMinX(aRect) + 1.0, y);
|
||||
CGContextAddLineToPoint(context, _CGRectGetMaxX(aRect) - 1.0, y);
|
||||
CGContextStrokePath(context);
|
||||
|
||||
CGContextBeginPath(context);
|
||||
CGContextSetStrokeColor(context, [CPColor colorWithWhite:142.0 / 255.0 alpha:1.0]);
|
||||
CGContextMoveToPoint(context, _CGRectGetMaxX(aRect) - 1.0, y);
|
||||
CGContextAddLineToPoint(context, _CGRectGetMaxX(aRect), y);
|
||||
CGContextStrokePath(context);
|
||||
|
||||
CGContextBeginPath(context);
|
||||
CGContextSetStrokeColor(context, [CPColor colorWithWhite:190.0 / 255.0 alpha:1.0]);
|
||||
|
||||
var x = _CGRectGetMaxX(aRect) - 0.5;
|
||||
|
||||
CGContextMoveToPoint(context, x, _CGRectGetMinY(aRect) + 1.0);
|
||||
CGContextAddLineToPoint(context, x, _CGRectGetMaxY(aRect));
|
||||
|
||||
CGContextMoveToPoint(context, x - 0.5, _CGRectGetMaxY(aRect) - 0.5);
|
||||
CGContextAddLineToPoint(context, _CGRectGetMinX(aRect), _CGRectGetMaxY(aRect) - 0.5);
|
||||
|
||||
x = _CGRectGetMinX(aRect) + 0.5;
|
||||
|
||||
CGContextMoveToPoint(context, x, _CGRectGetMaxY(aRect));
|
||||
CGContextAddLineToPoint(context, x, _CGRectGetMinY(aRect) + 1.0);
|
||||
|
||||
CGContextStrokePath(context);
|
||||
}
|
||||
|
||||
- (void)_drawGrooveInContext:(CGContext)context bounds:(CGRect)aRect
|
||||
{
|
||||
CGContextBeginPath(context);
|
||||
CGContextSetStrokeColor(context, [CPColor colorWithWhite:159.0 / 255.0 alpha:1.0]);
|
||||
|
||||
var y = _CGRectGetMinY(aRect) + 0.5;
|
||||
|
||||
CGContextMoveToPoint(context, _CGRectGetMinX(aRect), y);
|
||||
CGContextAddLineToPoint(context, _CGRectGetMaxX(aRect), y);
|
||||
|
||||
var x = _CGRectGetMaxX(aRect) - 1.5;
|
||||
|
||||
CGContextMoveToPoint(context, x, _CGRectGetMinY(aRect) + 2.0);
|
||||
CGContextAddLineToPoint(context, x, _CGRectGetMaxY(aRect) - 1.0);
|
||||
|
||||
y = _CGRectGetMaxY(aRect) - 1.5;
|
||||
|
||||
CGContextMoveToPoint(context, _CGRectGetMaxX(aRect) - 1.0, y);
|
||||
CGContextAddLineToPoint(context, _CGRectGetMinX(aRect) + 2.0, y);
|
||||
|
||||
x = _CGRectGetMinX(aRect) + 0.5;
|
||||
|
||||
CGContextMoveToPoint(context, x, _CGRectGetMaxY(aRect));
|
||||
CGContextAddLineToPoint(context, x, _CGRectGetMinY(aRect));
|
||||
|
||||
CGContextStrokePath(context);
|
||||
|
||||
CGContextBeginPath(context);
|
||||
CGContextSetStrokeColor(context, [CPColor whiteColor]);
|
||||
|
||||
var rect = _CGRectOffset(aRect, 1.0, 1.0);
|
||||
|
||||
rect.size.width -= 1.0;
|
||||
rect.size.height -= 1.0;
|
||||
CGContextStrokeRect(context, _CGRectInset(rect, 0.5, 0.5));
|
||||
|
||||
CGContextBeginPath(context);
|
||||
CGContextSetStrokeColor(context, [CPColor colorWithWhite:192.0 / 255.0 alpha:1.0]);
|
||||
|
||||
y = _CGRectGetMinY(aRect) + 2.5;
|
||||
|
||||
CGContextMoveToPoint(context, _CGRectGetMinX(aRect) + 2.0, y);
|
||||
CGContextAddLineToPoint(context, _CGRectGetMaxX(aRect) - 2.0, y);
|
||||
CGContextStrokePath(context);
|
||||
}
|
||||
|
||||
|
||||
// CPResponder Overrides
|
||||
|
||||
/*!
|
||||
Handles a scroll wheel event from the user.
|
||||
@param anEvent the scroll wheel event
|
||||
*/
|
||||
- (void)scrollWheel:(CPEvent)anEvent
|
||||
{
|
||||
var documentFrame = [[self documentView] frame],
|
||||
contentBounds = [_contentView bounds];
|
||||
[self _respondToScrollWheelEventWithDeltaX:[anEvent deltaX] deltaY:[anEvent deltaY]];
|
||||
}
|
||||
|
||||
- (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!
|
||||
contentBounds.origin.x = ROUND(contentBounds.origin.x + [anEvent deltaX] * _horizontalLineScroll);
|
||||
contentBounds.origin.y = ROUND(contentBounds.origin.y + [anEvent deltaY] * _verticalLineScroll);
|
||||
contentBounds.origin.x = ROUND(contentBounds.origin.x + deltaX);
|
||||
contentBounds.origin.y = ROUND(contentBounds.origin.y + deltaY);
|
||||
|
||||
[_contentView scrollToPoint:contentBounds.origin];
|
||||
[_headerClipView scrollToPoint:CGPointMake(contentBounds.origin.x, 0.0)];
|
||||
var constrainedOrigin = [_contentView constrainScrollPoint:CGPointCreateCopy(contentBounds.origin)],
|
||||
extraX = contentBounds.origin.x - constrainedOrigin.x,
|
||||
extraY = contentBounds.origin.y - constrainedOrigin.y;
|
||||
|
||||
[_contentView scrollToPoint:constrainedOrigin];
|
||||
[_headerClipView scrollToPoint:CGPointMake(constrainedOrigin.x, 0.0)];
|
||||
|
||||
if (extraX || extraY)
|
||||
[enclosingScrollView _respondToScrollWheelEventWithDeltaX:extraX deltaY:extraY];
|
||||
}
|
||||
|
||||
- (void)keyDown:(CPEvent)anEvent
|
||||
{
|
||||
[self interpretKeyEvents:[anEvent]];
|
||||
}
|
||||
|
||||
- (void)pageUp:(id)sender
|
||||
- (void)scrollPageUp:(id)sender
|
||||
{
|
||||
var contentBounds = [_contentView bounds];
|
||||
[self moveByOffset:CGSizeMake(0.0, -(_CGRectGetHeight(contentBounds) - _verticalPageScroll))];
|
||||
}
|
||||
|
||||
- (void)pageDown:(id)sender
|
||||
- (void)scrollPageDown:(id)sender
|
||||
{
|
||||
var contentBounds = [_contentView bounds];
|
||||
[self moveByOffset:CGSizeMake(0.0, _CGRectGetHeight(contentBounds) - _verticalPageScroll)];
|
||||
@@ -732,18 +1008,20 @@
|
||||
|
||||
@end
|
||||
|
||||
var CPScrollViewContentViewKey = "CPScrollViewContentView",
|
||||
CPScrollViewHeaderClipViewKey = "CPScrollViewHeaderClipViewKey",
|
||||
CPScrollViewVLineScrollKey = "CPScrollViewVLineScroll",
|
||||
CPScrollViewHLineScrollKey = "CPScrollViewHLineScroll",
|
||||
CPScrollViewVPageScrollKey = "CPScrollViewVPageScroll",
|
||||
CPScrollViewHPageScrollKey = "CPScrollViewHPageScroll",
|
||||
CPScrollViewHasVScrollerKey = "CPScrollViewHasVScroller",
|
||||
CPScrollViewHasHScrollerKey = "CPScrollViewHasHScroller",
|
||||
CPScrollViewVScrollerKey = "CPScrollViewVScroller",
|
||||
CPScrollViewHScrollerKey = "CPScrollViewHScroller",
|
||||
CPScrollViewAutohidesScrollerKey = "CPScrollViewAutohidesScroller",
|
||||
CPScrollViewCornerViewKey = "CPScrollViewCornerViewKey";
|
||||
var CPScrollViewContentViewKey = @"CPScrollViewContentView",
|
||||
CPScrollViewHeaderClipViewKey = @"CPScrollViewHeaderClipViewKey",
|
||||
CPScrollViewVLineScrollKey = @"CPScrollViewVLineScroll",
|
||||
CPScrollViewHLineScrollKey = @"CPScrollViewHLineScroll",
|
||||
CPScrollViewVPageScrollKey = @"CPScrollViewVPageScroll",
|
||||
CPScrollViewHPageScrollKey = @"CPScrollViewHPageScroll",
|
||||
CPScrollViewHasVScrollerKey = @"CPScrollViewHasVScroller",
|
||||
CPScrollViewHasHScrollerKey = @"CPScrollViewHasHScroller",
|
||||
CPScrollViewVScrollerKey = @"CPScrollViewVScroller",
|
||||
CPScrollViewHScrollerKey = @"CPScrollViewHScroller",
|
||||
CPScrollViewAutohidesScrollerKey = @"CPScrollViewAutohidesScroller",
|
||||
CPScrollViewCornerViewKey = @"CPScrollViewCornerViewKey",
|
||||
CPScrollViewBottomCornerViewKey = @"CPScrollViewBottomCornerViewKey",
|
||||
CPScrollViewBorderTypeKey = @"CPScrollViewBorderTypeKey";
|
||||
|
||||
@implementation CPScrollView (CPCoding)
|
||||
|
||||
@@ -756,10 +1034,16 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView",
|
||||
|
||||
_horizontalLineScroll = [aCoder decodeFloatForKey:CPScrollViewHLineScrollKey];
|
||||
_horizontalPageScroll = [aCoder decodeFloatForKey:CPScrollViewHPageScrollKey];
|
||||
|
||||
|
||||
_contentView = [aCoder decodeObjectForKey:CPScrollViewContentViewKey];
|
||||
_headerClipView = [aCoder decodeObjectForKey:CPScrollViewHeaderClipViewKey];
|
||||
|
||||
|
||||
if (!_headerClipView)
|
||||
{
|
||||
_headerClipView = [[CPClipView alloc] init];
|
||||
[self addSubview:_headerClipView];
|
||||
}
|
||||
|
||||
_verticalScroller = [aCoder decodeObjectForKey:CPScrollViewVScrollerKey];
|
||||
_horizontalScroller = [aCoder decodeObjectForKey:CPScrollViewHScrollerKey];
|
||||
|
||||
@@ -767,35 +1051,41 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView",
|
||||
_hasHorizontalScroller = [aCoder decodeBoolForKey:CPScrollViewHasHScrollerKey];
|
||||
_autohidesScrollers = [aCoder decodeBoolForKey:CPScrollViewAutohidesScrollerKey];
|
||||
|
||||
_borderType = [aCoder decodeIntForKey:CPScrollViewBorderTypeKey];
|
||||
|
||||
_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.
|
||||
[[CPRunLoop currentRunLoop] performSelector:@selector(reflectScrolledClipView:) target:self argument:_contentView order:0 modes:[CPDefaultRunLoopMode]];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
|
||||
[aCoder encodeObject:_contentView forKey:CPScrollViewContentViewKey];
|
||||
[aCoder encodeObject:_headerClipView forKey:CPScrollViewHeaderClipViewKey];
|
||||
|
||||
[aCoder encodeObject:_verticalScroller forKey:CPScrollViewVScrollerKey];
|
||||
[aCoder encodeObject:_horizontalScroller forKey:CPScrollViewHScrollerKey];
|
||||
|
||||
|
||||
[aCoder encodeFloat:_verticalLineScroll forKey:CPScrollViewVLineScrollKey];
|
||||
[aCoder encodeFloat:_verticalPageScroll forKey:CPScrollViewVPageScrollKey];
|
||||
[aCoder encodeFloat:_horizontalLineScroll forKey:CPScrollViewHLineScrollKey];
|
||||
[aCoder encodeFloat:_horizontalPageScroll forKey:CPScrollViewHPageScrollKey];
|
||||
|
||||
|
||||
[aCoder encodeBool:_hasVerticalScroller forKey:CPScrollViewHasVScrollerKey];
|
||||
[aCoder encodeBool:_hasHorizontalScroller forKey:CPScrollViewHasHScrollerKey];
|
||||
[aCoder encodeBool:_autohidesScrollers forKey:CPScrollViewAutohidesScrollerKey];
|
||||
|
||||
[aCoder encodeObject:_cornerView forKey:CPScrollViewCornerViewKey];
|
||||
[aCoder encodeObject:_bottomCornerView forKey:CPScrollViewBottomCornerViewKey];
|
||||
|
||||
[aCoder encodeInt:_borderType forKey:CPScrollViewBorderTypeKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+93
-81
@@ -22,8 +22,6 @@
|
||||
|
||||
@import "CPControl.j"
|
||||
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
|
||||
|
||||
// CPScroller Constants
|
||||
CPScrollerNoPart = 0;
|
||||
@@ -41,9 +39,9 @@ CPNoScrollerParts = 0;
|
||||
CPOnlyScrollerArrows = 1;
|
||||
CPAllScrollerParts = 2;
|
||||
|
||||
/*!
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPScroller
|
||||
@class CPScroller
|
||||
*/
|
||||
|
||||
var PARTS_ARRANGEMENT = [CPScrollerKnobSlot, CPScrollerDecrementLine, CPScrollerIncrementLine, CPScrollerKnob],
|
||||
@@ -72,24 +70,25 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
CGPoint _trackingStartPoint;
|
||||
}
|
||||
|
||||
+ (CPString)themeClass
|
||||
+ (CPString)defaultThemeClass
|
||||
{
|
||||
return "scroller";
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[ [CPNull null], [CPNull null], [CPNull null], [CPNull null],
|
||||
_CGSizeMakeZero(), _CGSizeMakeZero(), _CGInsetMakeZero(), _CGInsetMakeZero(), _CGSizeMakeZero()]
|
||||
forKeys:[ @"knob-slot-color",
|
||||
@"decrement-line-color",
|
||||
@"increment-line-color",
|
||||
@"knob-color",
|
||||
@"decrement-line-size",
|
||||
@"increment-line-size",
|
||||
@"track-inset",
|
||||
@"knob-inset",
|
||||
@"minimum-knob-length"]];
|
||||
return [CPDictionary dictionaryWithJSObject:{
|
||||
@"scroller-width": 15.0,
|
||||
@"knob-slot-color": [CPColor lightGrayColor],
|
||||
@"decrement-line-color": [CPNull null],
|
||||
@"increment-line-color": [CPNull null],
|
||||
@"knob-color": [CPColor grayColor],
|
||||
@"decrement-line-size":_CGSizeMakeZero(),
|
||||
@"increment-line-size":_CGSizeMakeZero(),
|
||||
@"track-inset":_CGInsetMakeZero(),
|
||||
@"knob-inset": _CGInsetMakeZero(),
|
||||
@"minimum-knob-length":21.0
|
||||
}]
|
||||
}
|
||||
|
||||
|
||||
@@ -98,7 +97,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_controlSize = CPRegularControlSize;
|
||||
@@ -106,7 +105,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
|
||||
[self setFloatValue:0.0];
|
||||
[self setKnobProportion:1.0];
|
||||
|
||||
|
||||
_hitPart = CPScrollerNoPart;
|
||||
|
||||
[self _calculateIsVertical];
|
||||
@@ -121,7 +120,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
*/
|
||||
+ (float)scrollerWidth
|
||||
{
|
||||
return 15.0;//[self scrollerWidthForControlSize:CPRegularControlSize];
|
||||
return [[[CPScroller alloc] init] currentValueForThemeAttribute:@"scroller-width"];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -130,7 +129,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
*/
|
||||
+ (float)scrollerWidthForControlSize:(CPControlSize)aControlSize
|
||||
{
|
||||
return 15.0;//_CPScrollerWidths[aControlSize];
|
||||
return [self scrollerWidth];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -180,10 +179,10 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
- (id)currentValueForThemeAttribute:(CPString)anAttributeName
|
||||
{
|
||||
var themeState = _themeState;
|
||||
|
||||
|
||||
if (NAMES_FOR_PARTS[_hitPart] + "-color" !== anAttributeName)
|
||||
themeState &= ~CPThemeStateHighlighted;
|
||||
|
||||
|
||||
return [self valueForThemeAttribute:anAttributeName inState:themeState];
|
||||
}
|
||||
|
||||
@@ -205,25 +204,25 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
- (CPScrollerPart)testPart:(CGPoint)aPoint
|
||||
{
|
||||
aPoint = [self convertPoint:aPoint fromView:nil];
|
||||
|
||||
// The ordering of these tests is important. We check the knob and
|
||||
|
||||
// The ordering of these tests is important. We check the knob and
|
||||
// page rects first since they may overlap with the arrows.
|
||||
|
||||
|
||||
if (CGRectContainsPoint([self rectForPart:CPScrollerKnob], aPoint))
|
||||
return CPScrollerKnob;
|
||||
|
||||
|
||||
if (CGRectContainsPoint([self rectForPart:CPScrollerDecrementPage], aPoint))
|
||||
return CPScrollerDecrementPage;
|
||||
|
||||
|
||||
if (CGRectContainsPoint([self rectForPart:CPScrollerIncrementPage], aPoint))
|
||||
return CPScrollerIncrementPage;
|
||||
|
||||
|
||||
if (CGRectContainsPoint([self rectForPart:CPScrollerDecrementLine], aPoint))
|
||||
return CPScrollerDecrementLine;
|
||||
|
||||
|
||||
if (CGRectContainsPoint([self rectForPart:CPScrollerIncrementLine], aPoint))
|
||||
return CPScrollerIncrementLine;
|
||||
|
||||
|
||||
if (CGRectContainsPoint([self rectForPart:CPScrollerKnobSlot], aPoint))
|
||||
return CPScrollerKnobSlot;
|
||||
|
||||
@@ -241,7 +240,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
if (_knobProportion === 1.0)
|
||||
{
|
||||
_usableParts = CPNoScrollerParts;
|
||||
|
||||
|
||||
_partRects[CPScrollerDecrementPage] = CGRectMakeZero();
|
||||
_partRects[CPScrollerKnob] = CGRectMakeZero();
|
||||
_partRects[CPScrollerIncrementPage] = CGRectMakeZero();
|
||||
@@ -250,7 +249,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
|
||||
// In this case, the slot is the entirety of the scroller.
|
||||
_partRects[CPScrollerKnobSlot] = CGRectMakeCopy(bounds);
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -260,8 +259,8 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
var knobInset = [self currentValueForThemeAttribute:@"knob-inset"],
|
||||
trackInset = [self currentValueForThemeAttribute:@"track-inset"],
|
||||
width = _CGRectGetWidth(bounds),
|
||||
height = _CGRectGetHeight(bounds);
|
||||
|
||||
height = _CGRectGetHeight(bounds);
|
||||
|
||||
if ([self isVertical])
|
||||
{
|
||||
var decrementLineSize = [self currentValueForThemeAttribute:"decrement-line-size"],
|
||||
@@ -280,11 +279,11 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
_partRects[CPScrollerKnobSlot] = _CGRectMake(trackInset.left, effectiveDecrementLineHeight, width - trackInset.left - trackInset.right, slotHeight);
|
||||
_partRects[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
|
||||
_partRects[CPScrollerIncrementLine] = _CGRectMake(0.0, height - incrementLineSize.height, incrementLineSize.width, incrementLineSize.height);
|
||||
|
||||
if(height < knobHeight + decrementLineSize.height + incrementLineSize.height + trackInset.top + trackInset.bottom)
|
||||
|
||||
if (height < knobHeight + decrementLineSize.height + incrementLineSize.height + trackInset.top + trackInset.bottom)
|
||||
_partRects[CPScrollerKnob] = _CGRectMakeZero();
|
||||
|
||||
if(height < decrementLineSize.height + incrementLineSize.height - 2)
|
||||
|
||||
if (height < decrementLineSize.height + incrementLineSize.height - 2)
|
||||
{
|
||||
_partRects[CPScrollerIncrementLine] = _CGRectMakeZero();
|
||||
_partRects[CPScrollerDecrementLine] = _CGRectMakeZero();
|
||||
@@ -296,7 +295,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
var decrementLineSize = [self currentValueForThemeAttribute:"decrement-line-size"],
|
||||
incrementLineSize = [self currentValueForThemeAttribute:"increment-line-size"],
|
||||
effectiveDecrementLineWidth = decrementLineSize.width + trackInset.left,
|
||||
effectiveIncrementLineWidth = incrementLineSize.width + trackInset.right;
|
||||
effectiveIncrementLineWidth = incrementLineSize.width + trackInset.right,
|
||||
slotWidth = width - effectiveDecrementLineWidth - effectiveIncrementLineWidth,
|
||||
minimumKnobLength = [self currentValueForThemeAttribute:"minimum-knob-length"],
|
||||
knobWidth = MAX(minimumKnobLength, (slotWidth * _knobProportion)),
|
||||
@@ -309,11 +308,11 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
_partRects[CPScrollerKnobSlot] = _CGRectMake(effectiveDecrementLineWidth, trackInset.top, slotWidth, height - trackInset.top - trackInset.bottom);
|
||||
_partRects[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
|
||||
_partRects[CPScrollerIncrementLine] = _CGRectMake(width - incrementLineSize.width, 0.0, incrementLineSize.width, incrementLineSize.height);
|
||||
|
||||
if(width < knobWidth + decrementLineSize.width + incrementLineSize.width + trackInset.left + trackInset.right)
|
||||
|
||||
if (width < knobWidth + decrementLineSize.width + incrementLineSize.width + trackInset.left + trackInset.right)
|
||||
_partRects[CPScrollerKnob] = _CGRectMakeZero();
|
||||
|
||||
if(width < decrementLineSize.width + incrementLineSize.width - 2)
|
||||
|
||||
if (width < decrementLineSize.width + incrementLineSize.width - 2)
|
||||
{
|
||||
_partRects[CPScrollerIncrementLine] = _CGRectMakeZero();
|
||||
_partRects[CPScrollerDecrementLine] = _CGRectMakeZero();
|
||||
@@ -358,9 +357,9 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
- (CPView)createViewForPart:(CPScrollerPart)aPart
|
||||
{
|
||||
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
|
||||
|
||||
[view setHitTests:NO];
|
||||
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@@ -374,7 +373,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
|
||||
[view setHitTests:NO];
|
||||
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@@ -388,12 +387,12 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var part = PARTS_ARRANGEMENT[index];
|
||||
|
||||
|
||||
if (index === 0)
|
||||
view = [self layoutEphemeralSubviewNamed:part positioned:CPWindowBelow relativeToEphemeralSubviewNamed:PARTS_ARRANGEMENT[index + 1]];
|
||||
else
|
||||
view = [self layoutEphemeralSubviewNamed:part positioned:CPWindowAbove relativeToEphemeralSubviewNamed:PARTS_ARRANGEMENT[index - 1]];
|
||||
|
||||
|
||||
if (view)
|
||||
[view setBackgroundColor:[self currentValueForThemeAttribute:NAMES_FOR_PARTS[part] + "-color"]];
|
||||
}
|
||||
@@ -403,7 +402,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
Caches images for the scroll arrow and knob.
|
||||
*/
|
||||
- (void)drawParts
|
||||
{
|
||||
{
|
||||
[self drawKnobSlot];
|
||||
[self drawKnob];
|
||||
[self drawArrow:CPScrollerDecrementArrow highlight:NO];
|
||||
@@ -426,37 +425,37 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
- (void)trackKnob:(CPEvent)anEvent
|
||||
{
|
||||
var type = [anEvent type];
|
||||
|
||||
|
||||
if (type === CPLeftMouseUp)
|
||||
{
|
||||
_hitPart = CPScrollerNoPart;
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (type === CPLeftMouseDown)
|
||||
{
|
||||
_trackingFloatValue = [self floatValue];
|
||||
_trackingStartPoint = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||
}
|
||||
|
||||
|
||||
else if (type === CPLeftMouseDragged)
|
||||
{
|
||||
var knobRect = [self rectForPart:CPScrollerKnob],
|
||||
knobSlotRect = [self rectForPart:CPScrollerKnobSlot],
|
||||
remainder = ![self isVertical] ? (_CGRectGetWidth(knobSlotRect) - _CGRectGetWidth(knobRect)) : (_CGRectGetHeight(knobSlotRect) - _CGRectGetHeight(knobRect));
|
||||
|
||||
|
||||
if (remainder <= 0)
|
||||
[self setFloatValue:0.0];
|
||||
else
|
||||
{
|
||||
var location = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||
var location = [self convertPoint:[anEvent locationInWindow] fromView:nil],
|
||||
delta = ![self isVertical] ? location.x - _trackingStartPoint.x : location.y - _trackingStartPoint.y;
|
||||
|
||||
[self setFloatValue:_trackingFloatValue + delta / remainder];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[CPApp setTarget:self selector:@selector(trackKnob:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
|
||||
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
@@ -474,26 +473,26 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
{
|
||||
[self highlight:NO];
|
||||
[CPEvent stopPeriodicEvents];
|
||||
|
||||
|
||||
_hitPart = CPScrollerNoPart;
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (type === CPLeftMouseDown)
|
||||
{
|
||||
_trackingPart = [self hitPart];
|
||||
|
||||
|
||||
_trackingStartPoint = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||
|
||||
if ([anEvent modifierFlags] & CPAlternateKeyMask)
|
||||
{
|
||||
if (_trackingPart == CPScrollerDecrementLine)
|
||||
_hitPart = CPScrollerDecrementPage;
|
||||
|
||||
|
||||
else if (_trackingPart == CPScrollerIncrementLine)
|
||||
_hitPart = CPScrollerIncrementPage;
|
||||
|
||||
|
||||
else if (_trackingPart == CPScrollerDecrementPage || _trackingPart == CPScrollerIncrementPage)
|
||||
{
|
||||
var knobRect = [self rectForPart:CPScrollerKnob],
|
||||
@@ -502,42 +501,42 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
remainder = (![self isVertical] ? _CGRectGetWidth(knobSlotRect) : _CGRectGetHeight(knobSlotRect)) - knobWidth;
|
||||
|
||||
[self setFloatValue:((![self isVertical] ? _trackingStartPoint.x - _CGRectGetMinX(knobSlotRect) : _trackingStartPoint.y - _CGRectGetMinY(knobSlotRect)) - knobWidth / 2.0) / remainder];
|
||||
|
||||
|
||||
_hitPart = CPScrollerKnob;
|
||||
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
|
||||
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
|
||||
// Now just track the knob.
|
||||
return [self trackKnob:anEvent];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[self highlight:YES];
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
|
||||
|
||||
[CPEvent startPeriodicEventsAfterDelay:0.5 withPeriod:0.04];
|
||||
}
|
||||
|
||||
|
||||
else if (type === CPLeftMouseDragged)
|
||||
{
|
||||
_trackingStartPoint = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||
|
||||
|
||||
if (_trackingPart == CPScrollerDecrementPage || _trackingPart == CPScrollerIncrementPage)
|
||||
{
|
||||
var hitPart = [self testPart:[anEvent locationInWindow]];
|
||||
|
||||
|
||||
if (hitPart == CPScrollerDecrementPage || hitPart == CPScrollerIncrementPage)
|
||||
{
|
||||
_trackingPart = hitPart;
|
||||
_hitPart = hitPart;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[self highlight:CGRectContainsPoint([self rectForPart:_trackingPart], _trackingStartPoint)];
|
||||
}
|
||||
else if (type == CPPeriodic && CGRectContainsPoint([self rectForPart:_trackingPart], _trackingStartPoint))
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
|
||||
|
||||
[CPApp setTarget:self selector:@selector(trackScrollButtons:) forNextEventMatchingMask:CPPeriodicMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
|
||||
|
||||
}
|
||||
@@ -569,15 +568,15 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
{
|
||||
if (![self isEnabled])
|
||||
return;
|
||||
|
||||
|
||||
_hitPart = [self testPart:[anEvent locationInWindow]];
|
||||
|
||||
|
||||
switch (_hitPart)
|
||||
{
|
||||
case CPScrollerKnob: return [self trackKnob:anEvent];
|
||||
|
||||
case CPScrollerDecrementLine:
|
||||
case CPScrollerIncrementLine:
|
||||
|
||||
case CPScrollerDecrementLine:
|
||||
case CPScrollerIncrementLine:
|
||||
case CPScrollerDecrementPage:
|
||||
case CPScrollerIncrementPage: return [self trackScrollButtons:anEvent];
|
||||
}
|
||||
@@ -603,19 +602,32 @@ var CPScrollerControlSizeKey = "CPScrollerControlSize",
|
||||
_knobProportion = [aCoder decodeFloatForKey:CPScrollerKnobProportionKey];
|
||||
|
||||
_partRects = [];
|
||||
|
||||
|
||||
_hitPart = CPScrollerNoPart;
|
||||
|
||||
[self _calculateIsVertical];
|
||||
|
||||
// Adjust the size of the scroller if the size from cib
|
||||
// isn't equal to the scrollerWidth
|
||||
var frame = [self frame],
|
||||
scrollerWidth = [CPScroller scrollerWidth];
|
||||
|
||||
if ([self isVertical] && CGRectGetWidth(frame) !== scrollerWidth)
|
||||
frame.size.width = scrollerWidth;
|
||||
|
||||
if (![self isVertical] && CGRectGetHeight(frame) !== scrollerWidth)
|
||||
frame.size.height = scrollerWidth;
|
||||
|
||||
[self setFrame:frame];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
|
||||
[aCoder encodeInt:_controlSize forKey:CPScrollerControlSizeKey];
|
||||
[aCoder encodeFloat:_knobProportion forKey:CPScrollerKnobProportionKey];
|
||||
}
|
||||
|
||||
+233
-130
@@ -20,20 +20,28 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CPButton.j"
|
||||
@import "CPTextField.j"
|
||||
|
||||
#include "Platform/Platform.h"
|
||||
|
||||
CPSearchFieldRecentsTitleMenuItemTag = 1000;
|
||||
CPSearchFieldRecentsMenuItemTag = 1001;
|
||||
CPSearchFieldClearRecentsMenuItemTag = 1002;
|
||||
CPSearchFieldNoRecentsMenuItemTag = 1003;
|
||||
CPSearchFieldSeparatorMenuItemTag = 1004;
|
||||
|
||||
var CPSearchFieldSearchImage = nil,
|
||||
CPSearchFieldFindImage = nil,
|
||||
CPSearchFieldCancelImage = nil,
|
||||
CPSearchFieldCancelPressedImage = nil;
|
||||
|
||||
var SEARCH_BUTTON_DEFAULT_WIDTH = 25.0,
|
||||
CANCEL_BUTTON_DEFAULT_WIDTH = 22.0,
|
||||
BUTTON_DEFAULT_HEIGHT = 22.0;
|
||||
|
||||
var RECENT_SEARCH_PREFIX = @" ";
|
||||
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPSearchField
|
||||
@@ -54,32 +62,37 @@ var CPSearchFieldSearchImage = nil,
|
||||
int _maximumRecents;
|
||||
BOOL _sendsWholeSearchString;
|
||||
BOOL _sendsSearchStringImmediately;
|
||||
BOOL _canResignFirstResponder;
|
||||
CPTimer _partialStringTimer;
|
||||
}
|
||||
|
||||
+ (CPString)defaultThemeClass
|
||||
{
|
||||
return @"searchfield"
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self != [CPSearchField class])
|
||||
return;
|
||||
|
||||
var bundle = [CPBundle bundleForClass:self];
|
||||
CPSearchFieldSearchImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldSearch.png"] size:CGSizeMake(25, 22)];
|
||||
CPSearchFieldFindImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldFind.png"] size:CGSizeMake(25, 22)];
|
||||
CPSearchFieldCancelImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancel.png"] size:CGSizeMake(22, 22)];
|
||||
CPSearchFieldCancelPressedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancelPressed.png"] size:CGSizeMake(22, 22)];
|
||||
CPSearchFieldSearchImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldSearch.png"] size:_CGSizeMake(SEARCH_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)];
|
||||
CPSearchFieldFindImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldFind.png"] size:_CGSizeMake(SEARCH_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)];
|
||||
CPSearchFieldCancelImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancel.png"] size:_CGSizeMake(CANCEL_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)];
|
||||
CPSearchFieldCancelPressedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancelPressed.png"] size:_CGSizeMake(CANCEL_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
{
|
||||
if (self = [super initWithFrame:frame])
|
||||
{
|
||||
_recentSearches = [CPArray array];
|
||||
_maximumRecents = 10;
|
||||
_sendsWholeSearchString = NO;
|
||||
_sendsSearchStringImmediately = NO;
|
||||
_recentsAutosaveName = nil;
|
||||
|
||||
[self _initWithFrame:frame];
|
||||
[self _init];
|
||||
#if PLATFORM(DOM)
|
||||
_cancelButton._DOMElement.style.cursor = "default";
|
||||
_searchButton._DOMElement.style.cursor = "default";
|
||||
@@ -89,23 +102,28 @@ var CPSearchFieldSearchImage = nil,
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)_initWithFrame:(CGRect)frame
|
||||
- (void)_init
|
||||
{
|
||||
_recentSearches = [CPArray array];
|
||||
|
||||
[self setBezeled:YES];
|
||||
[self setBezelStyle:CPTextFieldRoundedBezel];
|
||||
[self setBordered:YES];
|
||||
[self setEditable:YES];
|
||||
[self setDelegate:self];
|
||||
[self setContinuous:YES];
|
||||
|
||||
_cancelButton = [[CPButton alloc] initWithFrame:CGRectMake(frame.size.width - 27,(frame.size.height-22)/2,22,22)];
|
||||
var bounds = [self bounds],
|
||||
cancelButton = [[CPButton alloc] initWithFrame:[self cancelButtonRectForBounds:bounds]],
|
||||
searchButton = [[CPButton alloc] initWithFrame:[self searchButtonRectForBounds:bounds]];
|
||||
|
||||
[self setCancelButton:cancelButton];
|
||||
[self resetCancelButton];
|
||||
[_cancelButton setHidden:YES];
|
||||
[_cancelButton setAutoresizingMask:CPViewMinXMargin];
|
||||
[self addSubview:_cancelButton];
|
||||
|
||||
_searchButton = [[CPButton alloc] initWithFrame:CGRectMake(5,(frame.size.height-25)/2,25,25)];
|
||||
[self setSearchButton:searchButton];
|
||||
[self resetSearchButton];
|
||||
[self addSubview:_searchButton];
|
||||
|
||||
_canResignFirstResponder = YES;
|
||||
}
|
||||
|
||||
// Managing Buttons
|
||||
@@ -115,7 +133,15 @@ var CPSearchFieldSearchImage = nil,
|
||||
*/
|
||||
- (void)setSearchButton:(CPButton)button
|
||||
{
|
||||
_searchButton = button;
|
||||
if (button != _searchButton)
|
||||
{
|
||||
[_searchButton removeFromSuperview];
|
||||
_searchButton = button;
|
||||
|
||||
[_searchButton setFrame:[self searchButtonRectForBounds:[self bounds]]];
|
||||
[_searchButton setAutoresizingMask:CPViewMaxXMargin];
|
||||
[self addSubview:_searchButton];
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -133,30 +159,13 @@ var CPSearchFieldSearchImage = nil,
|
||||
*/
|
||||
- (void)resetSearchButton
|
||||
{
|
||||
var searchButtonImage,
|
||||
action,
|
||||
target,
|
||||
button = [self searchButton];
|
||||
|
||||
if (_searchMenuTemplate === nil)
|
||||
{
|
||||
searchButtonImage = CPSearchFieldSearchImage;
|
||||
action = @selector(_sendAction:);
|
||||
target = self;
|
||||
}
|
||||
else
|
||||
{
|
||||
searchButtonImage = CPSearchFieldFindImage;
|
||||
action = @selector(_showMenu:);
|
||||
target = self;
|
||||
}
|
||||
var button = [self searchButton],
|
||||
searchButtonImage = (_searchMenuTemplate === nil) ? CPSearchFieldSearchImage : CPSearchFieldFindImage;
|
||||
|
||||
[button setBordered:NO];
|
||||
[button setImageScaling:CPScaleToFit];
|
||||
[button setImage:searchButtonImage];
|
||||
[button setAutoresizingMask:CPViewMaxXMargin];
|
||||
[button setTarget:target];
|
||||
[button setAction:action];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -165,7 +174,18 @@ var CPSearchFieldSearchImage = nil,
|
||||
*/
|
||||
- (void)setCancelButton:(CPButton)button
|
||||
{
|
||||
_cancelButton = button;
|
||||
if (button != _cancelButton)
|
||||
{
|
||||
[_cancelButton removeFromSuperview];
|
||||
_cancelButton = button;
|
||||
|
||||
[_cancelButton setFrame:[self cancelButtonRectForBounds:[self bounds]]];
|
||||
[_cancelButton setAutoresizingMask:CPViewMinXMargin];
|
||||
[_cancelButton setTarget:self];
|
||||
[_cancelButton setAction:@selector(_searchFieldCancel:)];
|
||||
[self _updateCancelButtonVisibility];
|
||||
[self addSubview:_cancelButton];
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -200,23 +220,25 @@ var CPSearchFieldSearchImage = nil,
|
||||
@return The updated bounding rectangle to use for the search text field. The default value is the value passed into the rect parameter.
|
||||
Subclasses can override this method to return a new bounding rectangle for the text-field object. You might use this method to provide a custom layout for the search field control.
|
||||
*/
|
||||
- (CPRect)searchTextRectForBounds:(CPRect)rect
|
||||
- (CGRect)searchTextRectForBounds:(CGRect)rect
|
||||
{
|
||||
var leftOffset = 0, width = rect.size.width;
|
||||
var leftOffset = 0,
|
||||
width = _CGRectGetWidth(rect),
|
||||
bounds = [self bounds];
|
||||
|
||||
if (_searchButton)
|
||||
{
|
||||
var searchRect = [_searchButton frame];
|
||||
leftOffset = searchRect.origin.x + searchRect.size.width;
|
||||
var searchBounds = [self searchButtonRectForBounds:bounds];
|
||||
leftOffset = _CGRectGetMaxX(searchBounds) + 2;
|
||||
}
|
||||
|
||||
if (_cancelButton)
|
||||
{
|
||||
var cancelRect = [_cancelButton frame];
|
||||
width = cancelRect.origin.x - leftOffset;
|
||||
var cancelRect = [self cancelButtonRectForBounds:bounds];
|
||||
width = _CGRectGetMinX(cancelRect) - leftOffset;
|
||||
}
|
||||
|
||||
return CPMakeRect(leftOffset,rect.origin.y,width,rect.size.height);
|
||||
return _CGRectMake(leftOffset, _CGRectGetMinY(rect), width, _CGRectGetHeight(rect));
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -224,9 +246,9 @@ var CPSearchFieldSearchImage = nil,
|
||||
@param rect The current bounding rectangle for the search button.
|
||||
Subclasses can override this method to return a new bounding rectangle for the search button. You might use this method to provide a custom layout for the search field control.
|
||||
*/
|
||||
- (CPRect)searchButtonRectForBounds:(CPRect)rect
|
||||
- (CGRect)searchButtonRectForBounds:(CGRect)rect
|
||||
{
|
||||
return [_searchButton frame];
|
||||
return _CGRectMake(5, (_CGRectGetHeight(rect) - BUTTON_DEFAULT_HEIGHT) / 2, SEARCH_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -234,9 +256,9 @@ var CPSearchFieldSearchImage = nil,
|
||||
@param rect The updated bounding rectangle to use for the cancel button. The default value is the value passed into the rect parameter.
|
||||
Subclasses can override this method to return a new bounding rectangle for the cancel button. You might use this method to provide a custom layout for the search field control.
|
||||
*/
|
||||
- (CPRect)cancelButtonRectForBounds:(CPRect)rect
|
||||
{
|
||||
return [_cancelButton frame];
|
||||
- (CGRect)cancelButtonRectForBounds:(CGRect)rect
|
||||
{
|
||||
return _CGRectMake(_CGRectGetWidth(rect) - CANCEL_BUTTON_DEFAULT_WIDTH - 5, (_CGRectGetHeight(rect) - CANCEL_BUTTON_DEFAULT_WIDTH) / 2, BUTTON_DEFAULT_HEIGHT, BUTTON_DEFAULT_HEIGHT);
|
||||
}
|
||||
|
||||
// Managing Menu Templates
|
||||
@@ -254,9 +276,9 @@ var CPSearchFieldSearchImage = nil,
|
||||
@param menu The menu template to use.
|
||||
The receiver looks for the tag constants described in ŇMenu tagsÓ to determine how to populate the menu with items related to recent searches. See ŇConfiguring a Search MenuÓ for a sample of how you might set up the search menu template.
|
||||
*/
|
||||
- (void)setSearchMenuTemplate:(CPMenu)menu
|
||||
- (void)setSearchMenuTemplate:(CPMenu)aMenu
|
||||
{
|
||||
_searchMenuTemplate = menu;
|
||||
_searchMenuTemplate = aMenu;
|
||||
|
||||
[self resetSearchButton];
|
||||
[self _loadRecentSearchList];
|
||||
@@ -373,7 +395,7 @@ var CPSearchFieldSearchImage = nil,
|
||||
|
||||
// Private methods and subclassing
|
||||
|
||||
- (CPRect)contentRectForBounds:(CPRect)bounds
|
||||
- (CGRect)contentRectForBounds:(CGRect)bounds
|
||||
{
|
||||
var superbounds = [super contentRectForBounds:bounds];
|
||||
return [self searchTextRectForBounds:superbounds];
|
||||
@@ -447,37 +469,78 @@ var CPSearchFieldSearchImage = nil,
|
||||
[self _updateSearchMenu];
|
||||
}
|
||||
|
||||
- (BOOL)trackMouse:(CPEvent)event
|
||||
- (CPView)hitTest:(CGPoint)aPoint
|
||||
{
|
||||
var rect,
|
||||
point,
|
||||
location = [event locationInWindow];
|
||||
|
||||
point = [self convertPoint:location fromView:nil];
|
||||
|
||||
rect = [self searchButtonRectForBounds:[self frame]];
|
||||
if (CPRectContainsPoint(rect,point))
|
||||
{
|
||||
return [[self searchButton] trackMouse:event];
|
||||
}
|
||||
|
||||
rect = [self cancelButtonRectForBounds:[self frame]];
|
||||
if (CPRectContainsPoint(rect,point))
|
||||
{
|
||||
return [[self cancelButton] trackMouse:event];
|
||||
}
|
||||
|
||||
return [super trackMouse:event];
|
||||
// Make sure a hit anywhere within the search field returns the search field itself
|
||||
if (_CGRectContainsPoint([self frame], aPoint))
|
||||
return self;
|
||||
else
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (CPMenu)_defaultSearchMenuTemplate
|
||||
- (BOOL)resignFirstResponder
|
||||
{
|
||||
var template, item;
|
||||
return _canResignFirstResponder && [super resignFirstResponder];
|
||||
}
|
||||
|
||||
- (void)mouseDown:(CPEvent)anEvent
|
||||
{
|
||||
var location = [anEvent locationInWindow],
|
||||
point = [self convertPoint:location fromView:nil];
|
||||
|
||||
if (_CGRectContainsPoint([self searchButtonRectForBounds:[self bounds]], point))
|
||||
{
|
||||
if (_searchMenuTemplate == nil)
|
||||
[self _sendAction:self];
|
||||
else
|
||||
[self _showMenu];
|
||||
}
|
||||
else if (_CGRectContainsPoint([self cancelButtonRectForBounds:[self bounds]], point))
|
||||
[_cancelButton mouseDown:anEvent];
|
||||
else
|
||||
[super mouseDown:anEvent];
|
||||
}
|
||||
|
||||
/*!
|
||||
Provides the common case items for a recent searches menu. If there are not recent searches,
|
||||
displays a single disabled item:
|
||||
|
||||
template = [[CPMenu alloc] init];
|
||||
No Recent Searches
|
||||
|
||||
If there are 1 more recent searches, it displays:
|
||||
|
||||
item = [[CPMenuItem alloc] initWithTitle:@"Recent searches"
|
||||
action:NULL
|
||||
Recent Searches
|
||||
recent search 1
|
||||
recent search 2
|
||||
etc.
|
||||
---------------------
|
||||
Clear Recent Searches
|
||||
|
||||
If you wish to add items before or after the template, you can. If you put items
|
||||
before, a separator will automatically be placed before the default template item.
|
||||
If you add items after the default template, it is your responsibility to add a separator.
|
||||
|
||||
To add a custom item:
|
||||
|
||||
item = [[CPMenuItem alloc] initWithTitle:@"google"
|
||||
action:@selector(google:)
|
||||
keyEquivalent:@""];
|
||||
[item setTag:700];
|
||||
[item setTarget:self];
|
||||
[template addItem:item];
|
||||
|
||||
Be sure that your custom items do not use tags in the range 1000-1004 inclusive.
|
||||
If you wish to maintain state in custom menu items that you add, you will need to maintain
|
||||
the item state yourself, then in the action method of the custom items, modify the items
|
||||
in the search menu template and send [searchField setSearchMenuTemplate:template] to update the menu.
|
||||
*/
|
||||
- (CPMenu)defaultSearchMenuTemplate
|
||||
{
|
||||
var template = [[CPMenu alloc] init],
|
||||
item;
|
||||
|
||||
item = [[CPMenuItem alloc] initWithTitle:@"Recent Searches"
|
||||
action:nil
|
||||
keyEquivalent:@""];
|
||||
[item setTag:CPSearchFieldRecentsTitleMenuItemTag];
|
||||
[item setEnabled:NO];
|
||||
@@ -490,15 +553,15 @@ var CPSearchFieldSearchImage = nil,
|
||||
[item setTarget:self];
|
||||
[template addItem:item];
|
||||
|
||||
item = [[CPMenuItem alloc] initWithTitle:@"Clear recent searches"
|
||||
item = [[CPMenuItem alloc] initWithTitle:@"Clear Recent Searches"
|
||||
action:@selector(_searchFieldClearRecents:)
|
||||
keyEquivalent:@""];
|
||||
[item setTag:CPSearchFieldClearRecentsMenuItemTag];
|
||||
[item setTarget:self];
|
||||
[template addItem:item];
|
||||
|
||||
item = [[CPMenuItem alloc] initWithTitle:@"No recent searches"
|
||||
action:NULL
|
||||
item = [[CPMenuItem alloc] initWithTitle:@"No Recent Searches"
|
||||
action:nil
|
||||
keyEquivalent:@""];
|
||||
[item setTag:CPSearchFieldNoRecentsMenuItemTag];
|
||||
[item setEnabled:NO];
|
||||
@@ -512,61 +575,96 @@ var CPSearchFieldSearchImage = nil,
|
||||
if (_searchMenuTemplate === nil)
|
||||
return;
|
||||
|
||||
var i, menu = [[CPMenu alloc] init],
|
||||
var menu = [[CPMenu alloc] init],
|
||||
countOfRecents = [_recentSearches count],
|
||||
numberOfItems = [_searchMenuTemplate numberOfItems];
|
||||
|
||||
for (i = 0; i < numberOfItems; i++)
|
||||
for (var i = 0; i < numberOfItems; i++)
|
||||
{
|
||||
var item = [_searchMenuTemplate itemAtIndex:i],
|
||||
tag = [item tag];
|
||||
|
||||
if (!(tag === CPSearchFieldRecentsTitleMenuItemTag && countOfRecents === 0) &&
|
||||
!(tag === CPSearchFieldClearRecentsMenuItemTag && countOfRecents === 0) &&
|
||||
!(tag === CPSearchFieldNoRecentsMenuItemTag && countOfRecents != 0) &&
|
||||
!(tag === CPSearchFieldRecentsMenuItemTag))
|
||||
{
|
||||
var itemAction, itemTarget;
|
||||
switch (tag)
|
||||
{
|
||||
case CPSearchFieldRecentsTitleMenuItemTag : itemAction = NULL; itemTarget = NULL; break;
|
||||
case CPSearchFieldClearRecentsMenuItemTag : itemAction = @selector(_searchFieldClearRecents:); itemTarget = self; break;
|
||||
case CPSearchFieldNoRecentsMenuItemTag : itemAction = NULL; itemTarget = NULL; break;
|
||||
default: itemAction = [item action]; itemTarget = [item target]; break;
|
||||
}
|
||||
var item = [[_searchMenuTemplate itemAtIndex:i] copy];
|
||||
|
||||
if (tag === CPSearchFieldClearRecentsMenuItemTag || tag === CPSearchFieldRecentsTitleMenuItemTag)
|
||||
{
|
||||
var separator = [CPMenuItem separatorItem];
|
||||
[separator setEnabled:NO];
|
||||
[menu addItem:separator];
|
||||
}
|
||||
|
||||
var templateItem = [[CPMenuItem alloc] initWithTitle:[item title]
|
||||
action:itemAction
|
||||
keyEquivalent:[item keyEquivalent]];
|
||||
[templateItem setTarget:itemTarget];
|
||||
[templateItem setEnabled:([item isEnabled] && itemAction != NULL)];
|
||||
[templateItem setTag:tag];
|
||||
[menu addItem:templateItem];
|
||||
}
|
||||
else if (tag === CPSearchFieldRecentsMenuItemTag)
|
||||
switch ([item tag])
|
||||
{
|
||||
var j;
|
||||
for (j = 0; j < countOfRecents; j++)
|
||||
case CPSearchFieldRecentsTitleMenuItemTag:
|
||||
if (countOfRecents === 0)
|
||||
continue;
|
||||
|
||||
if ([menu numberOfItems] > 0)
|
||||
[self _addSeparatorToMenu:menu];
|
||||
break;
|
||||
|
||||
case CPSearchFieldRecentsMenuItemTag:
|
||||
{
|
||||
var rencentItem = [[CPMenuItem alloc] initWithTitle:[_recentSearches objectAtIndex:j]
|
||||
action:@selector(_searchFieldSearch:)
|
||||
keyEquivalent:[item keyEquivalent]];
|
||||
[rencentItem setTarget:self];
|
||||
[menu addItem:rencentItem];
|
||||
var itemAction = @selector(_searchFieldSearch:);
|
||||
|
||||
for (var recentIndex = 0; recentIndex < countOfRecents; ++recentIndex)
|
||||
{
|
||||
// RECENT_SEARCH_PREFIX is a hack until CPMenuItem -setIndentationLevel works
|
||||
var recentItem = [[CPMenuItem alloc] initWithTitle:RECENT_SEARCH_PREFIX + [_recentSearches objectAtIndex:recentIndex]
|
||||
action:itemAction
|
||||
keyEquivalent:[item keyEquivalent]];
|
||||
[item setTarget:self];
|
||||
[menu addItem:recentItem];
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
case CPSearchFieldClearRecentsMenuItemTag:
|
||||
if (countOfRecents === 0)
|
||||
continue;
|
||||
|
||||
if ([menu numberOfItems] > 0)
|
||||
[self _addSeparatorToMenu:menu];
|
||||
|
||||
[item setAction:@selector(_searchFieldClearRecents:)];
|
||||
[item setTarget:self];
|
||||
break;
|
||||
|
||||
case CPSearchFieldNoRecentsMenuItemTag:
|
||||
if (countOfRecents !== 0)
|
||||
continue;
|
||||
|
||||
if ([menu numberOfItems] > 0)
|
||||
[self _addSeparatorToMenu:menu];
|
||||
break;
|
||||
|
||||
case CPSearchFieldSeparatorMenuItemTag:
|
||||
item = [CPMenuItem separatorItem];
|
||||
[item setEnabled:NO];
|
||||
[menu addItem:item];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
[item setEnabled:([item isEnabled] && [item action] != nil && [item target] != nil)];
|
||||
[menu addItem:item];
|
||||
}
|
||||
|
||||
[menu setDelegate:self];
|
||||
|
||||
_searchMenu = menu;
|
||||
}
|
||||
|
||||
- (void)_showMenu:(id)sender
|
||||
- (void)_addSeparatorToMenu:(CPMenu)aMenu
|
||||
{
|
||||
var separator = [CPMenuItem separatorItem];
|
||||
[separator setEnabled:NO];
|
||||
[aMenu addItem:separator];
|
||||
}
|
||||
|
||||
- (void)menuWillOpen:(CPMenu)menu
|
||||
{
|
||||
_canResignFirstResponder = NO;
|
||||
}
|
||||
|
||||
- (void)menuDidClose:(CPMenu)menu
|
||||
{
|
||||
_canResignFirstResponder = YES;
|
||||
|
||||
[self becomeFirstResponder];
|
||||
}
|
||||
|
||||
- (void)_showMenu
|
||||
{
|
||||
if (_searchMenu === nil || [_searchMenu numberOfItems] === 0 || ![self isEnabled])
|
||||
return;
|
||||
@@ -576,12 +674,14 @@ var CPSearchFieldSearchImage = nil,
|
||||
|
||||
var anEvent = [CPEvent mouseEventWithType:CPRightMouseDown location:location modifierFlags:0 timestamp:[[CPApp currentEvent] timestamp] windowNumber:[[self window] windowNumber] context:nil eventNumber:1 clickCount:1 pressure:0];
|
||||
|
||||
[CPMenu popUpContextMenu:_searchMenu withEvent:anEvent forView:sender];
|
||||
[self selectAll:nil];
|
||||
[CPMenu popUpContextMenu:_searchMenu withEvent:anEvent forView:self];
|
||||
}
|
||||
|
||||
- (void)_sendPartialString
|
||||
{
|
||||
[[self target] performSelector:[self action] withObject:self];
|
||||
[super sendAction:[self action] to:[self target]];
|
||||
[_partialStringTimer invalidate];
|
||||
}
|
||||
|
||||
- (void)_searchFieldCancel:(id)sender
|
||||
@@ -593,14 +693,15 @@ var CPSearchFieldSearchImage = nil,
|
||||
|
||||
- (void)_searchFieldSearch:(id)sender
|
||||
{
|
||||
var searchString = [sender title];
|
||||
var searchString = [[sender title] substringFromIndex:[RECENT_SEARCH_PREFIX length]];
|
||||
|
||||
if ([sender tag] != CPSearchFieldRecentsMenuItemTag)
|
||||
[self _addStringToRecentSearches:searchString];
|
||||
|
||||
[self setObjectValue:searchString];
|
||||
[self _sendPartialString];
|
||||
|
||||
[self selectAll:nil];
|
||||
|
||||
[self _updateCancelButtonVisibility];
|
||||
}
|
||||
|
||||
@@ -608,6 +709,8 @@ var CPSearchFieldSearchImage = nil,
|
||||
{
|
||||
[self setRecentSearches:[CPArray array]];
|
||||
[self _updateSearchMenu];
|
||||
[self setStringValue:@""];
|
||||
[self _updateCancelButtonVisibility];
|
||||
}
|
||||
|
||||
- (void)_registerForAutosaveNotification
|
||||
@@ -668,7 +771,7 @@ var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
|
||||
CPSendsWholeSearchStringKey = @"CPSendsWholeSearchStringKey",
|
||||
CPSendsSearchStringImmediatelyKey = @"CPSendsSearchStringImmediatelyKey",
|
||||
CPMaximumRecentsKey = @"CPMaximumRecentsKey",
|
||||
CPSearchMenuTemplateKey = @"CPSearchMenuTemplateKey";
|
||||
CPSearchMenuTemplateKey = @"CPSearchMenuTemplateKey";
|
||||
|
||||
@implementation CPSearchField (CPCoding)
|
||||
|
||||
@@ -690,6 +793,7 @@ var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
|
||||
|
||||
if (_recentsAutosaveName)
|
||||
[coder encodeObject:_recentsAutosaveName forKey:CPRecentsAutosaveNameKey];
|
||||
|
||||
if (_searchMenuTemplate)
|
||||
[coder encodeObject:_searchMenuTemplate forKey:CPSearchMenuTemplateKey];
|
||||
}
|
||||
@@ -698,18 +802,17 @@ var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
|
||||
{
|
||||
if (self = [super initWithCoder:coder])
|
||||
{
|
||||
[self _initWithFrame:[self frame]];
|
||||
|
||||
_recentsAutosaveName = [coder decodeObjectForKey:CPRecentsAutosaveNameKey];
|
||||
_sendsWholeSearchString = [coder decodeBoolForKey:CPSendsWholeSearchStringKey];
|
||||
_sendsSearchStringImmediately = [coder decodeBoolForKey:CPSendsSearchStringImmediatelyKey];
|
||||
_maximumRecents = [coder decodeIntForKey:CPMaximumRecentsKey];
|
||||
|
||||
|
||||
var template = [coder decodeObjectForKey:CPSearchMenuTemplateKey];
|
||||
|
||||
if (template)
|
||||
[self setSearchMenuTemplate:template];
|
||||
|
||||
[self setDelegate:self];
|
||||
[self _init];
|
||||
}
|
||||
|
||||
return self;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
|
||||
@import "CPTextField.j"
|
||||
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
*/
|
||||
|
||||
+132
-133
@@ -24,13 +24,12 @@
|
||||
|
||||
@import "CPControl.j"
|
||||
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
|
||||
CPSegmentSwitchTrackingSelectOne = 0;
|
||||
CPSegmentSwitchTrackingSelectAny = 1;
|
||||
CPSegmentSwitchTrackingMomentary = 2;
|
||||
|
||||
/*!
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPSegmentedControl
|
||||
|
||||
@@ -49,7 +48,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
BOOL _trackingHighlighted;
|
||||
}
|
||||
|
||||
+ (CPString)themeClass
|
||||
+ (CPString)defaultThemeClass
|
||||
{
|
||||
return "segmented-control";
|
||||
}
|
||||
@@ -64,16 +63,16 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
{
|
||||
_segments = [];
|
||||
_themeStates = [];
|
||||
|
||||
|
||||
self = [super initWithFrame:aRect];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_selectedSegment = -1;
|
||||
|
||||
|
||||
_trackingMode = CPSegmentSwitchTrackingSelectOne;
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -82,7 +81,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (int)selectedTag
|
||||
{
|
||||
return _segments[_selectedSegment].tag;
|
||||
return [_segments[_selectedSegment] tag];
|
||||
}
|
||||
|
||||
// Specifying the number of segments
|
||||
@@ -94,11 +93,11 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
{
|
||||
if (_segments.length == aCount)
|
||||
return;
|
||||
|
||||
|
||||
var height = CGRectGetHeight([self bounds]);
|
||||
|
||||
|
||||
if (_segments.length < aCount)
|
||||
{
|
||||
{
|
||||
for (var index = _segments.length; index < aCount; ++index)
|
||||
{
|
||||
_segments[index] = [[_CPSegmentItem alloc] init];
|
||||
@@ -151,15 +150,15 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
- (BOOL)selectSegmentWithTag:(int)aTag
|
||||
{
|
||||
var index = 0;
|
||||
|
||||
|
||||
for (; index < _segments.length; ++index)
|
||||
if (_segments[index].tag == aTag)
|
||||
{
|
||||
[self setSelectedSegment:index];
|
||||
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
@@ -174,28 +173,28 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
{
|
||||
if (_trackingMode == aTrackingMode)
|
||||
return;
|
||||
|
||||
|
||||
_trackingMode = aTrackingMode;
|
||||
|
||||
|
||||
if (_trackingMode == CPSegmentSwitchTrackingSelectOne)
|
||||
{
|
||||
var index = 0,
|
||||
selected = NO;
|
||||
|
||||
|
||||
for (; index < _segments.length; ++index)
|
||||
if (_segments[index].selected)
|
||||
if ([_segments[index] selected])
|
||||
if (selected)
|
||||
[self setSelected:NO forSegment:index];
|
||||
else
|
||||
selected = YES;
|
||||
}
|
||||
|
||||
|
||||
else if (_trackingMode == CPSegmentSwitchTrackingMomentary)
|
||||
{
|
||||
var index = 0;
|
||||
|
||||
|
||||
for (; index < _segments.length; ++index)
|
||||
if (_segments[index].selected)
|
||||
if ([_segments[index] selected])
|
||||
[self setSelected:NO forSegment:index];
|
||||
}
|
||||
}
|
||||
@@ -217,8 +216,8 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (void)setWidth:(float)aWidth forSegment:(unsigned)aSegment
|
||||
{
|
||||
_segments[aSegment].width = aWidth;
|
||||
|
||||
[_segments[aSegment] setWidth:aWidth];
|
||||
|
||||
[self tileWithChangedSegment:aSegment];
|
||||
}
|
||||
|
||||
@@ -229,7 +228,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (float)widthForSegment:(unsigned)aSegment
|
||||
{
|
||||
return _segments[aSegment].width;
|
||||
return [_segments[aSegment] width];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -240,9 +239,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (void)setImage:(CPImage)anImage forSegment:(unsigned)aSegment
|
||||
{
|
||||
var segment = _segments[aSegment];
|
||||
|
||||
segment.image = anImage;
|
||||
[_segments[aSegment] setImage:anImage];
|
||||
|
||||
[self tileWithChangedSegment:aSegment];
|
||||
}
|
||||
@@ -254,7 +251,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (CPImage)imageForSegment:(unsigned)aSegment
|
||||
{
|
||||
return _segments[aSegment].image;
|
||||
return [_segments[aSegment] image];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -265,10 +262,8 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (void)setLabel:(CPString)aLabel forSegment:(unsigned)aSegment
|
||||
{
|
||||
var segment = _segments[aSegment];
|
||||
|
||||
_segments[aSegment].label = aLabel;
|
||||
|
||||
[_segments[aSegment] setLabel:aLabel];
|
||||
|
||||
[self tileWithChangedSegment:aSegment];
|
||||
}
|
||||
|
||||
@@ -279,7 +274,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (CPString)labelForSegment:(unsigned)aSegment
|
||||
{
|
||||
return _segments[aSegment].label;
|
||||
return [_segments[aSegment] label];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -290,7 +285,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (void)setMenu:(CPMenu)aMenu forSegment:(unsigned)aSegment
|
||||
{
|
||||
_segments[aSegment].menu = aMenu;
|
||||
[_segments[aSegment] setMenu:aMenu];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -300,7 +295,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (CPMenu)menuForSegment:(unsigned)aSegment
|
||||
{
|
||||
return _segments[aSegment].menu;
|
||||
return [_segments[aSegment] menu];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -313,12 +308,12 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
- (void)setSelected:(BOOL)isSelected forSegment:(unsigned)aSegment
|
||||
{
|
||||
var segment = _segments[aSegment];
|
||||
|
||||
|
||||
// If we're already in this state, bail.
|
||||
if (segment.selected == isSelected)
|
||||
if ([segment selected] == isSelected)
|
||||
return;
|
||||
|
||||
segment.selected = isSelected;
|
||||
|
||||
[segment setSelected:isSelected];
|
||||
|
||||
_themeStates[aSegment] = isSelected ? CPThemeStateSelected : CPThemeStateNormal;
|
||||
|
||||
@@ -326,18 +321,18 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
if (isSelected)
|
||||
{
|
||||
var oldSelectedSegment = _selectedSegment;
|
||||
|
||||
|
||||
_selectedSegment = aSegment;
|
||||
|
||||
|
||||
if (_trackingMode == CPSegmentSwitchTrackingSelectOne && oldSelectedSegment != aSegment && oldSelectedSegment != -1)
|
||||
{
|
||||
_segments[oldSelectedSegment].selected = NO;
|
||||
[_segments[oldSelectedSegment] setSelected:NO];
|
||||
_themeStates[oldSelectedSegment] = CPThemeStateNormal;
|
||||
|
||||
[self drawSegmentBezel:oldSelectedSegment highlight:NO];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (_trackingMode != CPSegmentSwitchTrackingMomentary)
|
||||
[self drawSegmentBezel:aSegment highlight:NO];
|
||||
|
||||
@@ -352,7 +347,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (BOOL)isSelectedForSegment:(unsigned)aSegment
|
||||
{
|
||||
return _segments[aSegment].selected;
|
||||
return [_segments[aSegment] selected];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -363,6 +358,8 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (void)setEnabled:(BOOL)isEnabled forSegment:(unsigned)aSegment
|
||||
{
|
||||
[_segments[aSegment] setEnabled:isEnabled];
|
||||
|
||||
if (isEnabled)
|
||||
_themeStates[aSegment] &= ~CPThemeStateDisabled;
|
||||
else
|
||||
@@ -379,7 +376,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (BOOL)isEnabledForSegment:(unsigned)aSegment
|
||||
{
|
||||
return !(_themeStates[aSegment] & CPThemeStateDisabled)
|
||||
return [_segments[aSegment] enabled];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -389,7 +386,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (void)setTag:(int)aTag forSegment:(unsigned)aSegment
|
||||
{
|
||||
_segments[aSegment].tag = aTag;
|
||||
[_segments[aSegment] setTag:aTag];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -398,7 +395,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (int)tagForSegment:(unsigned)aSegment
|
||||
{
|
||||
return _segments[aSegment].tag;
|
||||
return [_segments[aSegment] tag];
|
||||
}
|
||||
|
||||
// Drawings
|
||||
@@ -461,7 +458,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
else if (aName.indexOf("segment-bezel") === 0)
|
||||
{
|
||||
var segment = parseInt(aName.substring("segment-bezel-".length), 10),
|
||||
frame = CGRectCreateCopy(_segments[segment].frame);
|
||||
frame = CGRectCreateCopy([_segments[segment] frame]);
|
||||
|
||||
if (segment === 0)
|
||||
{
|
||||
@@ -495,7 +492,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
|
||||
- (CPView)createEphemeralSubviewNamed:(CPString)aName
|
||||
{
|
||||
if (aName.substring(0, "segment-content".length) == "segment-content")
|
||||
if ([aName hasPrefix:@"segment-content"])
|
||||
return [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
|
||||
return [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
@@ -510,10 +507,10 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
|
||||
themeState |= _themeState & CPThemeStateDisabled;
|
||||
|
||||
var leftCapColor = [self valueForThemeAttribute:@"left-segment-bezel-color"
|
||||
inState:themeState];
|
||||
var leftCapColor = [self valueForThemeAttribute:@"left-segment-bezel-color"
|
||||
inState:themeState],
|
||||
|
||||
var leftBezelView = [self layoutEphemeralSubviewNamed:@"left-segment-bezel"
|
||||
leftBezelView = [self layoutEphemeralSubviewNamed:@"left-segment-bezel"
|
||||
positioned:CPWindowBelow
|
||||
relativeToEphemeralSubviewNamed:nil];
|
||||
|
||||
@@ -523,41 +520,39 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
|
||||
themeState |= _themeState & CPThemeStateDisabled;
|
||||
|
||||
var rightCapColor = [self valueForThemeAttribute:@"right-segment-bezel-color"
|
||||
inState:themeState];
|
||||
var rightCapColor = [self valueForThemeAttribute:@"right-segment-bezel-color"
|
||||
inState:themeState],
|
||||
|
||||
var rightBezelView = [self layoutEphemeralSubviewNamed:@"right-segment-bezel"
|
||||
rightBezelView = [self layoutEphemeralSubviewNamed:@"right-segment-bezel"
|
||||
positioned:CPWindowBelow
|
||||
relativeToEphemeralSubviewNamed:nil];
|
||||
|
||||
[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];
|
||||
|
||||
themeState |= _themeState & CPThemeStateDisabled;
|
||||
|
||||
var bezelColor = [self valueForThemeAttribute:@"center-segment-bezel-color"
|
||||
inState:themeState];
|
||||
var bezelColor = [self valueForThemeAttribute:@"center-segment-bezel-color"
|
||||
inState:themeState],
|
||||
|
||||
var bezelView = [self layoutEphemeralSubviewNamed:"segment-bezel-"+i
|
||||
positioned:CPWindowBelow
|
||||
bezelView = [self layoutEphemeralSubviewNamed:"segment-bezel-" + i
|
||||
positioned:CPWindowBelow
|
||||
relativeToEphemeralSubviewNamed:nil];
|
||||
|
||||
[bezelView setBackgroundColor:bezelColor];
|
||||
|
||||
|
||||
//layout image/title views
|
||||
var segment = _segments[i];
|
||||
|
||||
|
||||
var contentView = [self layoutEphemeralSubviewNamed:@"segment-content-"+i
|
||||
// layout image/title views
|
||||
var segment = _segments[i],
|
||||
contentView = [self layoutEphemeralSubviewNamed:@"segment-content-" + i
|
||||
positioned:CPWindowAbove
|
||||
relativeToEphemeralSubviewNamed:@"segment-bezel-"+i];
|
||||
relativeToEphemeralSubviewNamed:@"segment-bezel-" + i];
|
||||
|
||||
[contentView setText:segment.label];
|
||||
[contentView setImage:segment.image];
|
||||
[contentView setText:[segment label]];
|
||||
[contentView setImage:[segment image]];
|
||||
|
||||
[contentView setFont:[self valueForThemeAttribute:@"font" inState:themeState]];
|
||||
[contentView setTextColor:[self valueForThemeAttribute:@"text-color" inState:themeState]];
|
||||
@@ -566,27 +561,27 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
[contentView setLineBreakMode:[self valueForThemeAttribute:@"line-break-mode" inState:themeState]];
|
||||
[contentView setTextShadowColor:[self valueForThemeAttribute:@"text-shadow-color" inState:themeState]];
|
||||
[contentView setTextShadowOffset:[self valueForThemeAttribute:@"text-shadow-offset" inState:themeState]];
|
||||
[contentView setImageScaling:[self valueForThemeAttribute:@"image-scaling" inState:themeState]];
|
||||
|
||||
if (segment.image && segment.label)
|
||||
[contentView setImageScaling:[self valueForThemeAttribute:@"image-scaling" inState:themeState]];
|
||||
|
||||
if ([segment image] && [segment label])
|
||||
[contentView setImagePosition:[self valueForThemeAttribute:@"image-position" inState:themeState]];
|
||||
else if (segment.image)
|
||||
else if ([segment image])
|
||||
[contentView setImagePosition:CPImageOnly];
|
||||
|
||||
if (i == count - 1)
|
||||
continue;
|
||||
|
||||
var borderState = _themeStates[i] | _themeStates[i+1];
|
||||
|
||||
var borderState = _themeStates[i] | _themeStates[i + 1];
|
||||
|
||||
borderState = (borderState & CPThemeStateSelected & ~CPThemeStateHighlighted) ? CPThemeStateSelected : CPThemeStateNormal;
|
||||
|
||||
borderState |= _themeState & CPThemeStateDisabled;
|
||||
|
||||
var borderColor = [self valueForThemeAttribute:@"divider-bezel-color"
|
||||
inState:borderState];
|
||||
inState:borderState],
|
||||
|
||||
var borderView = [self layoutEphemeralSubviewNamed:"divider-bezel-"+i
|
||||
positioned:CPWindowBelow
|
||||
borderView = [self layoutEphemeralSubviewNamed:"divider-bezel-" + i
|
||||
positioned:CPWindowBelow
|
||||
relativeToEphemeralSubviewNamed:nil];
|
||||
|
||||
[borderView setBackgroundColor:borderColor];
|
||||
@@ -609,48 +604,53 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
return;
|
||||
|
||||
var segment = _segments[aSegment],
|
||||
segmentWidth = segment.width,
|
||||
segmentWidth = [segment width],
|
||||
themeState = _themeStates[aSegment] | (_themeState & CPThemeStateDisabled),
|
||||
contentInset = [self valueForThemeAttribute:@"content-inset" inState:themeState],
|
||||
font = [self valueForThemeAttribute:@"font" inState:themeState];
|
||||
|
||||
if (!segmentWidth)
|
||||
{
|
||||
if (segment.image && segment.label)
|
||||
segmentWidth = [segment.label sizeWithFont:font].width + [segment.image size].width + contentInset.left + contentInset.right;
|
||||
if ([segment image] && [segment label])
|
||||
segmentWidth = [[segment label] sizeWithFont:font].width + [[segment image] size].width + contentInset.left + contentInset.right;
|
||||
else if (segment.image)
|
||||
segmentWidth = [segment.image size].width + contentInset.left + contentInset.right;
|
||||
segmentWidth = [[segment image] size].width + contentInset.left + contentInset.right;
|
||||
else if (segment.label)
|
||||
segmentWidth = [segment.label sizeWithFont:font].width + contentInset.left + contentInset.right;
|
||||
segmentWidth = [[segment label] sizeWithFont:font].width + contentInset.left + contentInset.right;
|
||||
else
|
||||
segmentWidth = 0.0;
|
||||
}
|
||||
|
||||
var delta = segmentWidth - CGRectGetWidth(segment.frame);
|
||||
var delta = segmentWidth - CGRectGetWidth([segment frame]);
|
||||
|
||||
if (!delta)
|
||||
return;
|
||||
{
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
|
||||
// Update Contorl Size
|
||||
return;
|
||||
}
|
||||
|
||||
// Update control size
|
||||
var frame = [self frame];
|
||||
|
||||
|
||||
[self setFrameSize:CGSizeMake(CGRectGetWidth(frame) + delta, CGRectGetHeight(frame))];
|
||||
|
||||
// Update Segment Width
|
||||
segment.width = segmentWidth;
|
||||
segment.frame = [self frameForSegment:aSegment];;
|
||||
// Update segment width
|
||||
[segment setWidth:segmentWidth];
|
||||
[segment setFrame:[self frameForSegment:aSegment]];
|
||||
|
||||
// Update Following Segments Widths
|
||||
// Update following segments widths
|
||||
var index = aSegment + 1;
|
||||
|
||||
|
||||
for (; index < _segments.length; ++index)
|
||||
{
|
||||
_segments[index].frame.origin.x += delta;
|
||||
|
||||
[_segments[index] frame].origin.x += delta;
|
||||
|
||||
[self drawSegmentBezel:index highlight:NO];
|
||||
[self drawSegment:index highlight:NO];
|
||||
}
|
||||
|
||||
|
||||
[self drawSegmentBezel:aSegment highlight:NO];
|
||||
[self drawSegment:aSegment highlight:NO];
|
||||
|
||||
@@ -696,14 +696,14 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
{
|
||||
var location = [self convertPoint:aPoint fromView:nil],
|
||||
count = _segments.length;
|
||||
|
||||
|
||||
while (count--)
|
||||
if (CGRectContainsPoint(_segments[count].frame, aPoint))
|
||||
if (CGRectContainsPoint([_segments[count] frame], aPoint))
|
||||
return count;
|
||||
|
||||
if (_segments.length)
|
||||
{
|
||||
var adjustedLastFrame = CGRectCreateCopy(_segments[_segments.length - 1].frame);
|
||||
var adjustedLastFrame = CGRectCreateCopy([_segments[_segments.length - 1] frame]);
|
||||
adjustedLastFrame.size.width = CGRectGetWidth([self bounds]) - adjustedLastFrame.origin.x;
|
||||
|
||||
if (CGRectContainsPoint(adjustedLastFrame, aPoint))
|
||||
@@ -717,7 +717,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
{
|
||||
if (![self isEnabled])
|
||||
return;
|
||||
|
||||
|
||||
[self trackSegment:anEvent];
|
||||
}
|
||||
|
||||
@@ -731,10 +731,10 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
@param anEvent the event to handle
|
||||
*/
|
||||
- (void)trackSegment:(CPEvent)anEvent
|
||||
{
|
||||
{
|
||||
var type = [anEvent type],
|
||||
location = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||
|
||||
|
||||
if (type == CPLeftMouseUp)
|
||||
{
|
||||
if (_trackingSegment == -1)
|
||||
@@ -745,30 +745,30 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
if (_trackingMode == CPSegmentSwitchTrackingSelectAny)
|
||||
{
|
||||
[self setSelected:![self isSelectedForSegment:_trackingSegment] forSegment:_trackingSegment];
|
||||
|
||||
|
||||
// With ANY, _selectedSegment means last pressed.
|
||||
_selectedSegment = _trackingSegment;
|
||||
}
|
||||
else
|
||||
[self setSelected:YES forSegment:_trackingSegment];
|
||||
|
||||
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
|
||||
|
||||
if (_trackingMode == CPSegmentSwitchTrackingMomentary)
|
||||
{
|
||||
[self setSelected:NO forSegment:_trackingSegment];
|
||||
|
||||
|
||||
_selectedSegment = -1;
|
||||
}
|
||||
}
|
||||
|
||||
[self drawSegmentBezel:_trackingSegment highlight:NO];
|
||||
|
||||
|
||||
_trackingSegment = -1;
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (type == CPLeftMouseDown)
|
||||
{
|
||||
var trackingSegment = [self testSegment:location];
|
||||
@@ -779,7 +779,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
[self drawSegmentBezel:_trackingSegment highlight:YES];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
else if (type == CPLeftMouseDragged)
|
||||
{
|
||||
if (_trackingSegment == -1)
|
||||
@@ -793,14 +793,14 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
[self drawSegmentBezel:_trackingSegment highlight:_trackingHighlighted];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[CPApp setTarget:self selector:@selector(trackSegment:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
|
||||
}
|
||||
|
||||
- (void)setFont:(CPFont)aFont
|
||||
{
|
||||
[super setFont:aFont];
|
||||
|
||||
|
||||
[self tileWithChangedSegment:0];
|
||||
}
|
||||
|
||||
@@ -816,12 +816,12 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
var frame = [self frame],
|
||||
originalWidth = frame.size.width;
|
||||
|
||||
|
||||
frame.size.width = 0;
|
||||
|
||||
[self setFrame:frame];
|
||||
@@ -832,38 +832,38 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
|
||||
|
||||
if ([aCoder containsValueForKey:CPSegmentedControlSelectedKey])
|
||||
_selectedSegment = [aCoder decodeIntForKey:CPSegmentedControlSelectedKey];
|
||||
else
|
||||
else
|
||||
_selectedSegment = -1;
|
||||
|
||||
|
||||
if ([aCoder containsValueForKey:CPSegmentedControlTrackingModeKey])
|
||||
_trackingMode = [aCoder decodeIntForKey:CPSegmentedControlTrackingModeKey];
|
||||
else
|
||||
_trackingMode = CPSegmentSwitchTrackingSelectOne;
|
||||
|
||||
|
||||
// HACK
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
var difference = MAX(originalWidth - [self frame].size.width, 0.0),
|
||||
remainingWidth = FLOOR(difference / _segments.length);
|
||||
|
||||
for (var i=0; i < _segments.length; i++)
|
||||
[self setWidth:_segments[i].width + remainingWidth forSegment:i];
|
||||
for (var i = 0; i < _segments.length; i++)
|
||||
[self setWidth:[_segments[i] width] + remainingWidth forSegment:i];
|
||||
|
||||
[self tileWithChangedSegment:0];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
|
||||
[aCoder encodeObject:_segments forKey:CPSegmentedControlSegmentsKey];
|
||||
[aCoder encodeInt:_selectedSegment forKey:CPSegmentedControlSelectedKey];
|
||||
[aCoder encodeInt:_segmentStyle forKey:CPSegmentedControlSegmentStyleKey];
|
||||
@@ -875,15 +875,15 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
|
||||
|
||||
@implementation _CPSegmentItem : CPObject
|
||||
{
|
||||
CPImage image;
|
||||
CPString label;
|
||||
CPMenu menu;
|
||||
BOOL selected;
|
||||
BOOL enabled;
|
||||
int tag;
|
||||
int width;
|
||||
CPImage image @accessors;
|
||||
CPString label @accessors;
|
||||
CPMenu menu @accessors;
|
||||
BOOL selected @accessors;
|
||||
BOOL enabled @accessors;
|
||||
int tag @accessors;
|
||||
int width @accessors;
|
||||
|
||||
CGRect frame;
|
||||
CGRect frame @accessors;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
@@ -894,8 +894,8 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
|
||||
label = @"";
|
||||
menu = nil;
|
||||
selected = NO;
|
||||
enabled = NO;
|
||||
tag = 0;
|
||||
enabled = YES;
|
||||
tag = -1;
|
||||
width = 0;
|
||||
|
||||
frame = CGRectMakeZero();
|
||||
@@ -918,7 +918,7 @@ var CPSegmentItemImageKey = "CPSegmentItemImageKey",
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
image = [aCoder decodeObjectForKey:CPSegmentItemImageKey];
|
||||
@@ -931,7 +931,7 @@ var CPSegmentItemImageKey = "CPSegmentItemImageKey",
|
||||
|
||||
frame = CGRectMakeZero();
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -947,4 +947,3 @@ var CPSegmentItemImageKey = "CPSegmentItemImageKey",
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
+41
-18
@@ -28,19 +28,17 @@
|
||||
@import "CPView.j"
|
||||
|
||||
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
|
||||
CPLightShadow = 0;
|
||||
CPHeavyShadow = 1;
|
||||
|
||||
var CPShadowViewLightBackgroundColor = nil,
|
||||
CPShadowViewHeavyBackgroundColor = nil;
|
||||
|
||||
|
||||
var LIGHT_LEFT_INSET = 3.0,
|
||||
LIGHT_RIGHT_INSET = 3.0,
|
||||
LIGHT_TOP_INSET = 3.0,
|
||||
LIGHT_BOTTOM_INSET = 5.0,
|
||||
|
||||
|
||||
HEAVY_LEFT_INSET = 7.0,
|
||||
HEAVY_RIGHT_INSET = 7.0,
|
||||
HEAVY_TOP_INSET = 5.0,
|
||||
@@ -61,51 +59,76 @@ var LIGHT_LEFT_INSET = 3.0,
|
||||
return;
|
||||
|
||||
var bundle = [CPBundle bundleForClass:[self class]];
|
||||
|
||||
|
||||
CPShadowViewLightBackgroundColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
|
||||
[
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightTopLeft.png"] size:CGSizeMake(9.0, 9.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightTop.png"] size:CGSizeMake(1.0, 9.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightTopRight.png"] size:CGSizeMake(9.0, 9.0)],
|
||||
|
||||
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightLeft.png"] size:CGSizeMake(9.0, 1.0)],
|
||||
nil,
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightRight.png"] size:CGSizeMake(9.0, 1.0)],
|
||||
|
||||
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightBottomLeft.png"] size:CGSizeMake(9.0, 9.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightBottom.png"] size:CGSizeMake(1.0, 9.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightBottomRight.png"] size:CGSizeMake(9.0, 9.0)]
|
||||
]]];
|
||||
|
||||
|
||||
CPShadowViewHeavyBackgroundColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
|
||||
[
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyTopLeft.png"] size:CGSizeMake(17.0, 17.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyTop.png"] size:CGSizeMake(1.0, 17.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyTopRight.png"] size:CGSizeMake(17.0, 17.0)],
|
||||
|
||||
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyLeft.png"] size:CGSizeMake(17.0, 1.0)],
|
||||
nil,
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyRight.png"] size:CGSizeMake(17.0, 1.0)],
|
||||
|
||||
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyBottomLeft.png"] size:CGSizeMake(17.0, 17.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyBottom.png"] size:CGSizeMake(1.0, 17.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyBottomRight.png"] size:CGSizeMake(17.0, 17.0)]
|
||||
]]];
|
||||
}
|
||||
|
||||
+ (id)shadowViewEnclosingView:(CPView)aView
|
||||
{
|
||||
return [self shadowViewEnclosingView:aView withWeight:CPLightShadow];
|
||||
}
|
||||
|
||||
+ (id)shadowViewEnclosingView:(CPView)aView withWeight:(CPShadowWeight)aWeight
|
||||
{
|
||||
var shadowView = [[CPShadowView alloc] initWithFrame:[aView frame]];
|
||||
[shadowView setWeight:aWeight];
|
||||
|
||||
var size = [shadowView frame].size,
|
||||
width = size.width - [shadowView leftInset] - [shadowView rightInset],
|
||||
height = size.height - [shadowView topInset] - [shadowView bottomInset],
|
||||
enclosingView = [aView superview];
|
||||
|
||||
[shadowView setHitTests:[aView hitTests]];
|
||||
[shadowView setAutoresizingMask:[aView autoresizingMask]];
|
||||
[aView removeFromSuperview];
|
||||
[shadowView addSubview:aView];
|
||||
[aView setFrame:CGRectMake([shadowView leftInset], [shadowView topInset], width, height)]
|
||||
[enclosingView addSubview:shadowView];
|
||||
|
||||
return shadowView;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_weight = CPLightShadow;
|
||||
|
||||
|
||||
[self setBackgroundColor:CPShadowViewLightBackgroundColor];
|
||||
|
||||
|
||||
[self setHitTests:NO];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -113,9 +136,9 @@ var LIGHT_LEFT_INSET = 3.0,
|
||||
{
|
||||
if (_weight == aWeight)
|
||||
return;
|
||||
|
||||
|
||||
_weight = aWeight;
|
||||
|
||||
|
||||
if (_weight == CPLightShadow)
|
||||
[self setBackgroundColor:CPShadowViewLightBackgroundColor];
|
||||
|
||||
@@ -147,7 +170,7 @@ var LIGHT_LEFT_INSET = 3.0,
|
||||
{
|
||||
if (_weight == CPLightShadow)
|
||||
return LIGHT_LEFT_INSET + LIGHT_RIGHT_INSET;
|
||||
|
||||
|
||||
return HEAVY_LEFT_INSET + HEAVY_RIGHT_INSET;
|
||||
}
|
||||
|
||||
@@ -155,7 +178,7 @@ var LIGHT_LEFT_INSET = 3.0,
|
||||
{
|
||||
if (_weight == CPLightShadow)
|
||||
return LIGHT_TOP_INSET + LIGHT_BOTTOM_INSET;
|
||||
|
||||
|
||||
return HEAVY_TOP_INSET + HEAVY_BOTTOM_INSET;
|
||||
}
|
||||
|
||||
|
||||
+50
-40
@@ -22,7 +22,6 @@
|
||||
|
||||
@import "CPControl.j"
|
||||
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
|
||||
/*! SLIDER STATES */
|
||||
|
||||
@@ -42,7 +41,7 @@ CPCircularSlider = 1;
|
||||
BOOL _isVertical;
|
||||
}
|
||||
|
||||
+ (CPString)themeClass
|
||||
+ (CPString)defaultThemeClass
|
||||
{
|
||||
return "slider";
|
||||
}
|
||||
@@ -61,14 +60,14 @@ CPCircularSlider = 1;
|
||||
{
|
||||
_minValue = 0.0;
|
||||
_maxValue = 100.0;
|
||||
|
||||
|
||||
[self setObjectValue:50.0];
|
||||
|
||||
|
||||
[self setContinuous:YES];
|
||||
|
||||
[self _recalculateIsVertical];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -76,11 +75,11 @@ CPCircularSlider = 1;
|
||||
{
|
||||
if (_minValue === aMinimumValue)
|
||||
return;
|
||||
|
||||
|
||||
_minValue = aMinimumValue;
|
||||
|
||||
var doubleValue = [self doubleValue];
|
||||
|
||||
|
||||
if (doubleValue < _minValue)
|
||||
[self setDoubleValue:_minValue];
|
||||
|
||||
@@ -98,11 +97,11 @@ CPCircularSlider = 1;
|
||||
{
|
||||
if (_maxValue === aMaximumValue)
|
||||
return;
|
||||
|
||||
|
||||
_maxValue = aMaximumValue;
|
||||
|
||||
|
||||
var doubleValue = [self doubleValue];
|
||||
|
||||
|
||||
if (doubleValue > _maxValue)
|
||||
[self setDoubleValue:_maxValue];
|
||||
|
||||
@@ -169,27 +168,27 @@ CPCircularSlider = 1;
|
||||
bounds.size.height = trackWidth;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return bounds;
|
||||
}
|
||||
|
||||
- (CGRect)knobRectForBounds:(CGRect)bounds
|
||||
{
|
||||
var knobSize = [self currentValueForThemeAttribute:@"knob-size"];
|
||||
|
||||
|
||||
if (knobSize.width <= 0 || knobSize.height <= 0)
|
||||
return _CGRectMakeZero();
|
||||
|
||||
|
||||
var knobRect = _CGRectMake(0.0, 0.0, knobSize.width, knobSize.height),
|
||||
trackRect = [self trackRectForBounds:bounds];
|
||||
|
||||
|
||||
// No track, do our best to approximate a place for this thing.
|
||||
if (!trackRect || _CGRectIsEmpty(trackRect))
|
||||
trackRect = bounds;
|
||||
|
||||
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;
|
||||
|
||||
knobRect.origin.x = radius * COS(angle) + CGRectGetMidX(trackRect) - 3.0;
|
||||
@@ -198,7 +197,7 @@ CPCircularSlider = 1;
|
||||
else if ([self isVertical])
|
||||
{
|
||||
knobRect.origin.x = _CGRectGetMidX(trackRect) - knobSize.width / 2.0;
|
||||
knobRect.origin.y = (([self doubleValue] - _minValue) / (_maxValue - _minValue)) * (_CGRectGetHeight(trackRect) - knobSize.height);
|
||||
knobRect.origin.y = ((_maxValue - [self doubleValue]) / (_maxValue - _minValue)) * (_CGRectGetHeight(trackRect) - knobSize.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -213,10 +212,10 @@ CPCircularSlider = 1;
|
||||
{
|
||||
if (aName === "track-view")
|
||||
return [self trackRectForBounds:[self bounds]];
|
||||
|
||||
|
||||
else if (aName === "knob-view")
|
||||
return [self knobRectForBounds:[self bounds]];
|
||||
|
||||
|
||||
return [super rectForEphemeralSubviewNamed:aName];
|
||||
}
|
||||
|
||||
@@ -225,12 +224,12 @@ CPCircularSlider = 1;
|
||||
if (aName === "track-view" || aName === "knob-view")
|
||||
{
|
||||
var view = [[CPView alloc] init];
|
||||
|
||||
|
||||
[view setHitTests:NO];
|
||||
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
|
||||
return [super createEphemeralSubviewNamed:aName];
|
||||
}
|
||||
|
||||
@@ -256,7 +255,7 @@ CPCircularSlider = 1;
|
||||
var bounds = [self bounds],
|
||||
width = _CGRectGetWidth(bounds),
|
||||
height = _CGRectGetHeight(bounds);
|
||||
|
||||
|
||||
_isVertical = width < height ? 1 : (width > height ? 0 : -1);
|
||||
|
||||
if (_isVertical === 1)
|
||||
@@ -282,7 +281,7 @@ CPCircularSlider = 1;
|
||||
var knobView = [self layoutEphemeralSubviewNamed:@"knob-view"
|
||||
positioned:CPWindowAbove
|
||||
relativeToEphemeralSubviewNamed:@"track-view"];
|
||||
|
||||
|
||||
if (knobView)
|
||||
[knobView setBackgroundColor:[self currentValueForThemeAttribute:"knob-color"]];
|
||||
}
|
||||
@@ -320,7 +319,7 @@ CPCircularSlider = 1;
|
||||
|
||||
var minValue = [self minValue];
|
||||
|
||||
return MAX(0.0, MIN(1.0, (aPoint.y - _CGRectGetMinY(trackRect)) / _CGRectGetHeight(trackRect))) * ([self maxValue] - minValue) + minValue;
|
||||
return MAX(0.0, MIN(1.0, (_CGRectGetMaxY(trackRect) - aPoint.y) / _CGRectGetHeight(trackRect))) * ([self maxValue] - minValue) + minValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -339,44 +338,43 @@ CPCircularSlider = 1;
|
||||
{
|
||||
var bounds = [self bounds],
|
||||
knobRect = [self knobRectForBounds:_CGRectMakeCopy(bounds)];
|
||||
|
||||
|
||||
if (_CGRectContainsPoint(knobRect, aPoint))
|
||||
_dragOffset = _CGSizeMake(_CGRectGetMidX(knobRect) - aPoint.x, _CGRectGetMidY(knobRect) - aPoint.y);
|
||||
|
||||
else
|
||||
else
|
||||
{
|
||||
var trackRect = [self trackRectForBounds:bounds];
|
||||
|
||||
|
||||
if (trackRect && _CGRectContainsPoint(trackRect, aPoint))
|
||||
{
|
||||
_dragOffset = _CGSizeMakeZero();
|
||||
|
||||
|
||||
[self setObjectValue:[self _valueAtPoint:aPoint]];
|
||||
}
|
||||
|
||||
|
||||
else
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
[self setHighlighted:YES];
|
||||
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
|
||||
return YES;
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)continueTracking:(CGPoint)lastPoint at:(CGPoint)aPoint
|
||||
{
|
||||
[self setObjectValue:[self _valueAtPoint:_CGPointMake(aPoint.x + _dragOffset.width, aPoint.y + _dragOffset.height)]];
|
||||
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp
|
||||
{
|
||||
[self setHighlighted:NO];
|
||||
|
||||
|
||||
if ([_target respondsToSelector:@selector(sliderDidFinish:)])
|
||||
[_target sliderDidFinish:self];
|
||||
|
||||
@@ -392,10 +390,22 @@ CPCircularSlider = 1;
|
||||
{
|
||||
if (flag)
|
||||
_sendActionOn |= CPLeftMouseDraggedMask;
|
||||
else
|
||||
else
|
||||
_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
|
||||
|
||||
var CPSliderMinValueKey = "CPSliderMinValueKey",
|
||||
@@ -442,14 +452,14 @@ var CPSliderMinValueKey = "CPSliderMinValueKey",
|
||||
- (id)value
|
||||
{
|
||||
CPLog.warn("[CPSlider value] is deprecated, use doubleValue or objectValue instead.");
|
||||
|
||||
return [self doubleValue];
|
||||
|
||||
return [self doubleValue];
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue
|
||||
{
|
||||
CPLog.warn("[CPSlider setValue:] is deprecated, use setDoubleValue: or setObjectValue: instead.");
|
||||
|
||||
|
||||
[self setObjectValue:aValue];
|
||||
}
|
||||
|
||||
|
||||
+103
-167
@@ -20,8 +20,10 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CPView.j"
|
||||
@import "CPColorPicker.j"
|
||||
|
||||
|
||||
/*
|
||||
@ignore
|
||||
*/
|
||||
@@ -45,16 +47,15 @@
|
||||
CPTextField _saturationLabel;
|
||||
CPTextField _brightnessLabel;
|
||||
CPTextField _hexLabel;
|
||||
CPTextField _hexValue;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
DOMElement _redValue;
|
||||
DOMElement _greenValue;
|
||||
DOMElement _blueValue;
|
||||
DOMElement _hueValue;
|
||||
DOMElement _saturationValue;
|
||||
DOMElement _brightnessValue;
|
||||
DOMElement _hexValue;
|
||||
#endif
|
||||
CPTextField _hexValue;
|
||||
CPTextField _redValue;
|
||||
CPTextField _greenValue;
|
||||
CPTextField _blueValue;
|
||||
CPTextField _hueValue;
|
||||
CPTextField _saturationValue;
|
||||
CPTextField _brightnessValue;
|
||||
}
|
||||
|
||||
- (id)initWithPickerMask:(int)mask colorPanel:(CPColorPanel)owningColorPanel
|
||||
@@ -84,73 +85,13 @@
|
||||
[_redSlider setAction: @selector(sliderChanged:)];
|
||||
[_redSlider setAutoresizingMask: CPViewWidthSizable];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
var updateFunction = function(aDOMEvent)
|
||||
{
|
||||
if(isNaN(this.value))
|
||||
return;
|
||||
|
||||
switch(this)
|
||||
{
|
||||
case _redValue: [_redSlider setFloatValue:MAX(MIN(ROUND(this.value), 255) / 255.0, 0)];
|
||||
//[self sliderChanged: _redSlider];
|
||||
break;
|
||||
|
||||
case _greenValue: [_greenSlider setFloatValue:MAX(MIN(ROUND(this.value), 255) / 255.0, 0)];
|
||||
//[self sliderChanged: _greenSlider];
|
||||
break;
|
||||
|
||||
case _blueValue: [_blueSlider setFloatValue:MAX(MIN(ROUND(this.value), 255) / 255.0, 0)];
|
||||
//[self sliderChanged: _blueSlider];
|
||||
break;
|
||||
|
||||
case _hueValue: [_hueSlider setFloatValue:MAX(MIN(ROUND(this.value), 360), 0)];
|
||||
//[self sliderChanged: _hueSlider];
|
||||
break;
|
||||
|
||||
case _saturationValue: [_saturationSlider setFloatValue:MAX(MIN(ROUND(this.value), 100), 0)];
|
||||
//[self sliderChanged: _saturationSlider];
|
||||
break;
|
||||
|
||||
case _brightnessValue: [_brightnessSlider setFloatValue:MAX(MIN(ROUND(this.value), 100), 0)];
|
||||
//[self sliderChanged: _brightnessSlider];
|
||||
break;
|
||||
}
|
||||
|
||||
this.blur();
|
||||
};
|
||||
|
||||
var keypressFunction = function(aDOMEvent)
|
||||
{
|
||||
aDOMEvent = aDOMEvent || window.event;
|
||||
if (aDOMEvent.keyCode == 13)
|
||||
{
|
||||
updateFunction(aDOMEvent);
|
||||
|
||||
if(aDOMEvent.preventDefault)
|
||||
aDOMEvent.preventDefault();
|
||||
else if(aDOMEvent.stopPropagation)
|
||||
aDOMEvent.stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
//red value input box
|
||||
var redValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 35, 45, 20)];
|
||||
[redValue setAutoresizingMask: CPViewMinXMargin];
|
||||
|
||||
_redValue = document.createElement("input");
|
||||
_redValue.style.width = "40px";
|
||||
_redValue.style.backgroundColor = "transparent";
|
||||
_redValue.style.border = "1px solid black";
|
||||
_redValue.style.color = "black";
|
||||
_redValue.style.position = "absolute";
|
||||
_redValue.style.top = "0px";
|
||||
_redValue.style.left = "0px";
|
||||
_redValue.onchange = updateFunction;
|
||||
|
||||
redValue._DOMElement.appendChild(_redValue);
|
||||
[_contentView addSubview: redValue];
|
||||
#endif
|
||||
// red value input box
|
||||
_redValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 30, 45, 29)];
|
||||
[_redValue setAutoresizingMask: CPViewMinXMargin];
|
||||
[_redValue setEditable: YES];
|
||||
[_redValue setBezeled: YES];
|
||||
[_redValue setDelegate: self];
|
||||
[_contentView addSubview: _redValue];
|
||||
|
||||
_greenLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 58, 15, 20)];
|
||||
[_greenLabel setStringValue: "G"];
|
||||
@@ -163,17 +104,13 @@
|
||||
[_greenSlider setAction: @selector(sliderChanged:)];
|
||||
[_greenSlider setAutoresizingMask: CPViewWidthSizable];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
//green value input box
|
||||
var greenValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 58, 45, 20)];
|
||||
[greenValue setAutoresizingMask: CPViewMinXMargin];
|
||||
|
||||
_greenValue = _redValue.cloneNode(false);
|
||||
_greenValue.onchange = updateFunction;
|
||||
|
||||
greenValue._DOMElement.appendChild(_greenValue);
|
||||
[_contentView addSubview: greenValue];
|
||||
#endif
|
||||
// green value input box
|
||||
_greenValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 53, 45, 29)];
|
||||
[_greenValue setAutoresizingMask: CPViewMinXMargin];
|
||||
[_greenValue setEditable: YES];
|
||||
[_greenValue setBezeled: YES];
|
||||
[_greenValue setDelegate: self];
|
||||
[_contentView addSubview: _greenValue];
|
||||
|
||||
_blueLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 81, 15, 20)];
|
||||
[_blueLabel setStringValue: "B"];
|
||||
@@ -186,17 +123,14 @@
|
||||
[_blueSlider setAction: @selector(sliderChanged:)];
|
||||
[_blueSlider setAutoresizingMask: CPViewWidthSizable];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
//blue value input box
|
||||
var blueValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 81, 45, 20)];
|
||||
[blueValue setAutoresizingMask: CPViewMinXMargin];
|
||||
// blue value input box
|
||||
_blueValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 76, 45, 29)];
|
||||
[_blueValue setAutoresizingMask: CPViewMinXMargin];
|
||||
[_blueValue setEditable: YES];
|
||||
[_blueValue setBezeled: YES];
|
||||
[_blueValue setDelegate: self];
|
||||
[_contentView addSubview: _blueValue];
|
||||
|
||||
_blueValue = _redValue.cloneNode(false);
|
||||
_blueValue.onchange = updateFunction;
|
||||
|
||||
blueValue._DOMElement.appendChild(_blueValue);
|
||||
[_contentView addSubview: blueValue];
|
||||
#endif
|
||||
_hsbLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 120, 190, 20)];
|
||||
[_hsbLabel setStringValue: "Hue, Saturation, Brightness"];
|
||||
[_hsbLabel setTextColor:[CPColor blackColor]];
|
||||
@@ -212,17 +146,14 @@
|
||||
[_hueSlider setAction: @selector(sliderChanged:)];
|
||||
[_hueSlider setAutoresizingMask: CPViewWidthSizable];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
//red value input box
|
||||
var hueValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 145, 45, 20)];
|
||||
[hueValue setAutoresizingMask: CPViewMinXMargin];
|
||||
// hue value input box
|
||||
_hueValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 140, 45, 29)];
|
||||
[_hueValue setAutoresizingMask: CPViewMinXMargin];
|
||||
[_hueValue setEditable: YES];
|
||||
[_hueValue setBezeled: YES];
|
||||
[_hueValue setDelegate: self];
|
||||
[_contentView addSubview: _hueValue];
|
||||
|
||||
_hueValue = _redValue.cloneNode(false);
|
||||
_hueValue.onchange = updateFunction;
|
||||
|
||||
hueValue._DOMElement.appendChild(_hueValue);
|
||||
[_contentView addSubview: hueValue];
|
||||
#endif
|
||||
_saturationLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 168, 15, 20)];
|
||||
[_saturationLabel setStringValue: "S"];
|
||||
[_saturationLabel setTextColor:[CPColor blackColor]];
|
||||
@@ -234,17 +165,14 @@
|
||||
[_saturationSlider setAction: @selector(sliderChanged:)];
|
||||
[_saturationSlider setAutoresizingMask: CPViewWidthSizable];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
//green value input box
|
||||
var saturationValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 168, 45, 20)];
|
||||
[saturationValue setAutoresizingMask: CPViewMinXMargin];
|
||||
// saturation value input box
|
||||
_saturationValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 163, 45, 29)];
|
||||
[_saturationValue setAutoresizingMask: CPViewMinXMargin];
|
||||
[_saturationValue setEditable: YES];
|
||||
[_saturationValue setBezeled: YES];
|
||||
[_saturationValue setDelegate: self];
|
||||
[_contentView addSubview: _saturationValue];
|
||||
|
||||
_saturationValue = _redValue.cloneNode(false);
|
||||
_saturationValue.onchange = updateFunction;
|
||||
|
||||
saturationValue._DOMElement.appendChild(_saturationValue);
|
||||
[_contentView addSubview: saturationValue];
|
||||
#endif
|
||||
_brightnessLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 191, 15, 20)];
|
||||
[_brightnessLabel setStringValue: "B"];
|
||||
[_brightnessLabel setTextColor:[CPColor blackColor]];
|
||||
@@ -256,51 +184,24 @@
|
||||
[_brightnessSlider setAction: @selector(sliderChanged:)];
|
||||
[_brightnessSlider setAutoresizingMask: CPViewWidthSizable];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
//blue value input box
|
||||
var brightnessValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 191, 45, 20)];
|
||||
[brightnessValue setAutoresizingMask: CPViewMinXMargin];
|
||||
// brightness value input box
|
||||
_brightnessValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 186, 45, 29)];
|
||||
[_brightnessValue setAutoresizingMask: CPViewMinXMargin];
|
||||
[_brightnessValue setEditable: YES];
|
||||
[_brightnessValue setBezeled: YES];
|
||||
[_brightnessValue setDelegate: self];
|
||||
[_contentView addSubview: _brightnessValue];
|
||||
|
||||
_brightnessValue = _redValue.cloneNode(false);
|
||||
_brightnessValue.onchange = updateFunction;
|
||||
|
||||
brightnessValue._DOMElement.appendChild(_brightnessValue);
|
||||
[_contentView addSubview: brightnessValue];
|
||||
#endif
|
||||
_hexLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 230, 30, 20)];
|
||||
[_hexLabel setStringValue: "Hex"];
|
||||
[_hexLabel setTextColor:[CPColor blackColor]];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
//hex input box
|
||||
_hexValue = _redValue.cloneNode(false);
|
||||
_hexValue.style.top = "228px";
|
||||
_hexValue.style.width = "80px";
|
||||
_hexValue.style.left = "35px";
|
||||
_hexValue.onkeypress = function(aDOMEvent)
|
||||
{
|
||||
aDOMEvent = aDOMEvent || window.event;
|
||||
if (aDOMEvent.keyCode == 13)
|
||||
{
|
||||
var newColor = [CPColor colorWithHexString: this.value];
|
||||
|
||||
if(newColor)
|
||||
{
|
||||
[self setColor: newColor];
|
||||
[[self colorPanel] setColor: newColor];
|
||||
}
|
||||
|
||||
if(aDOMEvent.preventDefault)
|
||||
aDOMEvent.preventDefault();
|
||||
else if(aDOMEvent.stopPropagation)
|
||||
aDOMEvent.stopPropagation();
|
||||
|
||||
this.blur();
|
||||
}
|
||||
};
|
||||
|
||||
_contentView._DOMElement.appendChild(_hexValue);
|
||||
#endif
|
||||
_hexValue = [[CPTextField alloc] initWithFrame: CGRectMake(32, 225, 80, 29)];
|
||||
[_hexValue setEditable: YES];
|
||||
[_hexValue setBezeled: YES];
|
||||
[_hexValue setDelegate: self];
|
||||
[_contentView addSubview: _hexValue];
|
||||
|
||||
[_contentView addSubview: _rgbLabel];
|
||||
[_contentView addSubview: _redLabel];
|
||||
@@ -392,9 +293,7 @@
|
||||
|
||||
- (void)updateHex:(CPColor)aColor
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
_hexValue.value = [aColor hexString];
|
||||
#endif
|
||||
[_hexValue setStringValue:[aColor hexString]];
|
||||
}
|
||||
|
||||
- (void)updateRGBSliders:(CPColor)aColor
|
||||
@@ -408,15 +307,13 @@
|
||||
|
||||
- (void)updateLabels
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
_hueValue.value = ROUND([_hueSlider floatValue]);
|
||||
_saturationValue.value = ROUND([_saturationSlider floatValue]);
|
||||
_brightnessValue.value = ROUND([_brightnessSlider floatValue]);
|
||||
[_hueValue setStringValue: ROUND([_hueSlider floatValue])];
|
||||
[_saturationValue setStringValue: ROUND([_saturationSlider floatValue])];
|
||||
[_brightnessValue setStringValue: ROUND([_brightnessSlider floatValue])];
|
||||
|
||||
_redValue.value = ROUND([_redSlider floatValue] * 255);
|
||||
_greenValue.value = ROUND([_greenSlider floatValue] * 255);
|
||||
_blueValue.value = ROUND([_blueSlider floatValue] * 255);
|
||||
#endif
|
||||
[_redValue setStringValue: ROUND([_redSlider floatValue] * 255)];
|
||||
[_greenValue setStringValue: ROUND([_greenSlider floatValue] * 255)];
|
||||
[_blueValue setStringValue: ROUND([_blueSlider floatValue] * 255)];
|
||||
}
|
||||
|
||||
- (CPImage)provideNewButtonImage
|
||||
@@ -429,4 +326,43 @@
|
||||
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:CPColorPicker] pathForResource:"slider_button_h.png"] size:CGSizeMake(32, 32)];
|
||||
}
|
||||
|
||||
- (void)controlTextDidEndEditing:(CPNotification)aNotification
|
||||
{
|
||||
var field = [aNotification object],
|
||||
value = [[field stringValue] stringByTrimmingWhitespace];
|
||||
if (field === _hexValue) {
|
||||
var newColor = [CPColor colorWithHexString: value];
|
||||
if (newColor) {
|
||||
[self setColor: newColor];
|
||||
[[self colorPanel] setColor: newColor];
|
||||
}
|
||||
} else {
|
||||
switch(field) {
|
||||
case _redValue: [_redSlider setFloatValue:MAX(MIN(ROUND(value), 255) / 255.0, 0)];
|
||||
[self sliderChanged: _redSlider];
|
||||
break;
|
||||
|
||||
case _greenValue: [_greenSlider setFloatValue:MAX(MIN(ROUND(value), 255) / 255.0, 0)];
|
||||
[self sliderChanged: _greenSlider];
|
||||
break;
|
||||
|
||||
case _blueValue: [_blueSlider setFloatValue:MAX(MIN(ROUND(value), 255) / 255.0, 0)];
|
||||
[self sliderChanged: _blueSlider];
|
||||
break;
|
||||
|
||||
case _hueValue: [_hueSlider setFloatValue:MAX(MIN(ROUND(value), 360), 0)];
|
||||
[self sliderChanged: _hueSlider];
|
||||
break;
|
||||
|
||||
case _saturationValue: [_saturationSlider setFloatValue:MAX(MIN(ROUND(value), 100), 0)];
|
||||
[self sliderChanged: _saturationSlider];
|
||||
break;
|
||||
|
||||
case _brightnessValue: [_brightnessSlider setFloatValue:MAX(MIN(ROUND(value), 100), 0)];
|
||||
[self sliderChanged: _brightnessSlider];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+54
-32
@@ -24,10 +24,6 @@
|
||||
@import "CPImage.j"
|
||||
@import "CPView.j"
|
||||
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
#include "Platform/Platform.h"
|
||||
#include "Platform/DOM/CPDOMDisplayServer.h"
|
||||
|
||||
|
||||
CPSplitViewDidResizeSubviewsNotification = @"CPSplitViewDidResizeSubviewsNotification";
|
||||
CPSplitViewWillResizeSubviewsNotification = @"CPSplitViewWillResizeSubviewsNotification";
|
||||
@@ -47,6 +43,7 @@ var CPSplitViewHorizontalImage = nil,
|
||||
|
||||
int _currentDivider;
|
||||
float _initialOffset;
|
||||
float _preCollapsePosition;
|
||||
|
||||
CPString _originComponent;
|
||||
CPString _sizeComponent;
|
||||
@@ -60,6 +57,17 @@ var CPSplitViewHorizontalImage = nil,
|
||||
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
|
||||
*/
|
||||
@@ -90,7 +98,7 @@ var CPSplitViewHorizontalImage = nil,
|
||||
|
||||
- (float)dividerThickness
|
||||
{
|
||||
return _isPaneSplitter ? 1.0 : 10.0;
|
||||
return [self currentValueForThemeAttribute:[self isPaneSplitter] ? @"pane-divider-thickness" : @"divider-thickness"];
|
||||
}
|
||||
|
||||
- (BOOL)isVertical
|
||||
@@ -151,8 +159,8 @@ var CPSplitViewHorizontalImage = nil,
|
||||
|
||||
_isPaneSplitter = shouldBePaneSplitter;
|
||||
|
||||
if(_DOMDividerElements[_drawingDivider])
|
||||
[self _setupDOMDivider]
|
||||
if (_DOMDividerElements[_drawingDivider])
|
||||
[self _setupDOMDivider];
|
||||
|
||||
// The divider changes size when pane splitter mode is toggled, so the
|
||||
// subviews need to change size too.
|
||||
@@ -185,9 +193,8 @@ var CPSplitViewHorizontalImage = nil,
|
||||
|
||||
- (CGRect)effectiveRectOfDividerAtIndex:(int)aDivider
|
||||
{
|
||||
var realRect = [self rectOfDividerAtIndex:aDivider];
|
||||
|
||||
var padding = 2;
|
||||
var realRect = [self rectOfDividerAtIndex:aDivider],
|
||||
padding = 2;
|
||||
|
||||
realRect.size[_sizeComponent] += padding * 2;
|
||||
realRect.origin[_originComponent] -= padding;
|
||||
@@ -217,10 +224,9 @@ var CPSplitViewHorizontalImage = nil,
|
||||
_DOMDividerElements[_drawingDivider].style.backgroundRepeat = "repeat";
|
||||
|
||||
CPDOMDisplayServerAppendChild(_DOMElement, _DOMDividerElements[_drawingDivider]);
|
||||
|
||||
[self _setupDOMDivider];
|
||||
}
|
||||
|
||||
[self _setupDOMDivider];
|
||||
CPDOMDisplayServerSetStyleLeftTop(_DOMDividerElements[_drawingDivider], NULL, _CGRectGetMinX(aRect), _CGRectGetMinY(aRect));
|
||||
CPDOMDisplayServerSetStyleSize(_DOMDividerElements[_drawingDivider], _CGRectGetWidth(aRect), _CGRectGetHeight(aRect));
|
||||
#endif
|
||||
@@ -230,7 +236,7 @@ var CPSplitViewHorizontalImage = nil,
|
||||
{
|
||||
if (_isPaneSplitter)
|
||||
{
|
||||
_DOMDividerElements[_drawingDivider].style.backgroundColor = "#A5A5A5";
|
||||
_DOMDividerElements[_drawingDivider].style.backgroundColor = [[self currentValueForThemeAttribute:@"pane-divider-color"] cssString];
|
||||
_DOMDividerElements[_drawingDivider].style.backgroundImage = "";
|
||||
}
|
||||
else
|
||||
@@ -294,7 +300,7 @@ var CPSplitViewHorizontalImage = nil,
|
||||
if ([_delegate respondsToSelector:@selector(splitView:additionalEffectiveRectOfDividerAtIndex:)])
|
||||
additionalRect = [_delegate splitView:self additionalEffectiveRectOfDividerAtIndex:anIndex];
|
||||
|
||||
return CGRectContainsPoint(effectiveRect, aPoint) ||
|
||||
return CGRectContainsPoint(effectiveRect, aPoint) ||
|
||||
(additionalRect && CGRectContainsPoint(additionalRect, aPoint)) ||
|
||||
(buttonBarRect && CGRectContainsPoint(buttonBarRect, aPoint));
|
||||
}
|
||||
@@ -304,9 +310,9 @@ var CPSplitViewHorizontalImage = nil,
|
||||
if ([self isHidden] || ![self hitTests] || !CGRectContainsPoint([self frame], aPoint))
|
||||
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++)
|
||||
{
|
||||
if ([self cursorAtPoint:point hitDividerAtIndex:i])
|
||||
@@ -359,14 +365,14 @@ var CPSplitViewHorizontalImage = nil,
|
||||
if ([_delegate splitView:self canCollapseSubview:_subviews[i]] && [_delegate splitView:self shouldCollapseSubview:_subviews[i] forDoubleClickOnDividerAtIndex:i])
|
||||
{
|
||||
if ([self isSubviewCollapsed:_subviews[i]])
|
||||
[self setPosition:(minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i];
|
||||
[self setPosition:_preCollapsePosition ? _preCollapsePosition : (minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i];
|
||||
else
|
||||
[self setPosition:minPosition ofDividerAtIndex:i];
|
||||
}
|
||||
else if ([_delegate splitView:self canCollapseSubview:_subviews[i+1]] && [_delegate splitView:self shouldCollapseSubview:_subviews[i+1] forDoubleClickOnDividerAtIndex:i])
|
||||
else if ([_delegate splitView:self canCollapseSubview:_subviews[i + 1]] && [_delegate splitView:self shouldCollapseSubview:_subviews[i + 1] forDoubleClickOnDividerAtIndex:i])
|
||||
{
|
||||
if ([self isSubviewCollapsed:_subviews[i+1]])
|
||||
[self setPosition:(minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i];
|
||||
if ([self isSubviewCollapsed:_subviews[i + 1]])
|
||||
[self setPosition:_preCollapsePosition ? _preCollapsePosition : (minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i];
|
||||
else
|
||||
[self setPosition:maxPosition ofDividerAtIndex:i];
|
||||
}
|
||||
@@ -445,11 +451,19 @@ var CPSplitViewHorizontalImage = nil,
|
||||
if (_currentDivider === i || (_currentDivider == CPNotFound && [self cursorAtPoint:point hitDividerAtIndex:i]))
|
||||
{
|
||||
var frame = [_subviews[i] frame],
|
||||
startPosition = frame.origin[_originComponent] + frame.size[_sizeComponent],
|
||||
canShrink = [self _realPositionForPosition:startPosition-1 ofDividerAtIndex:i] < startPosition,
|
||||
canGrow = [self _realPositionForPosition:startPosition+1 ofDividerAtIndex:i] > startPosition,
|
||||
size = frame.size[_sizeComponent],
|
||||
startPosition = frame.origin[_originComponent] + size,
|
||||
canShrink = [self _realPositionForPosition:startPosition - 1 ofDividerAtIndex:i] < startPosition,
|
||||
canGrow = [self _realPositionForPosition:startPosition + 1 ofDividerAtIndex:i] > startPosition,
|
||||
cursor = [CPCursor arrowCursor];
|
||||
|
||||
if (size === 0)
|
||||
canGrow = YES; // Subview is collapsed.
|
||||
else if (!canShrink &&
|
||||
[_delegate respondsToSelector:@selector(splitView:canCollapseSubview:)] &&
|
||||
[_delegate splitView:self canCollapseSubview:_subviews[i]])
|
||||
canShrink = YES; // Subview is collapsible.
|
||||
|
||||
if (_isVertical && canShrink && canGrow)
|
||||
cursor = [CPCursor resizeLeftRightCursor];
|
||||
else if (_isVertical && canShrink)
|
||||
@@ -504,10 +518,10 @@ var CPSplitViewHorizontalImage = nil,
|
||||
actualMax = proposedMax,
|
||||
actualMin = proposedMin;
|
||||
|
||||
if([_delegate respondsToSelector:@selector(splitView:constrainMinCoordinate:ofSubviewAt:)])
|
||||
if ([_delegate respondsToSelector:@selector(splitView:constrainMinCoordinate:ofSubviewAt:)])
|
||||
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];
|
||||
|
||||
var viewA = _subviews[dividerIndex],
|
||||
@@ -532,10 +546,18 @@ var CPSplitViewHorizontalImage = nil,
|
||||
viewB = _subviews[dividerIndex + 1],
|
||||
frameB = [viewB frame];
|
||||
|
||||
_preCollapsePosition = 0;
|
||||
|
||||
var preSize = frameA.size[_sizeComponent];
|
||||
frameA.size[_sizeComponent] = realPosition - frameA.origin[_originComponent];
|
||||
if (preSize !== 0 && frameA.size[_sizeComponent] === 0)
|
||||
_preCollapsePosition = preSize;
|
||||
[_subviews[dividerIndex] setFrame:frameA];
|
||||
|
||||
preSize = frameB.size[_sizeComponent];
|
||||
frameB.size[_sizeComponent] = frameB.origin[_originComponent] + frameB.size[_sizeComponent] - realPosition - [self dividerThickness];
|
||||
if (preSize !== 0 && frameB.size[_sizeComponent] === 0)
|
||||
_preCollapsePosition = preSize;
|
||||
frameB.origin[_originComponent] = realPosition + [self dividerThickness];
|
||||
[_subviews[dividerIndex + 1] setFrame:frameB];
|
||||
|
||||
@@ -590,8 +612,8 @@ var CPSplitViewHorizontalImage = nil,
|
||||
|
||||
var nonSizableSpace = totalSizableSpace ? bounds.size[_sizeComponent] - totalSizableSpace : 0,
|
||||
remainingFlexibleSpace = bounds.size[_sizeComponent] - oldSize[_sizeComponent],
|
||||
oldDimension = (oldSize[_sizeComponent]- totalDividers*dividerThickness - nonSizableSpace),
|
||||
ratio = oldDimension <= 0 ? 0 : (bounds.size[_sizeComponent] - totalDividers*dividerThickness - nonSizableSpace) / oldDimension;
|
||||
oldDimension = (oldSize[_sizeComponent] - totalDividers * dividerThickness - nonSizableSpace),
|
||||
ratio = oldDimension <= 0 ? 0 : (bounds.size[_sizeComponent] - totalDividers * dividerThickness - nonSizableSpace) / oldDimension;
|
||||
|
||||
for (index = 0; index < count; ++index)
|
||||
{
|
||||
@@ -642,14 +664,14 @@ var CPSplitViewHorizontalImage = nil,
|
||||
|
||||
/*!
|
||||
Set the button bar who's resize control should act as a control for this splitview.
|
||||
Each divider can have at most one button bar assigned to it, and that button bar must be
|
||||
Each divider can have at most one button bar assigned to it, and that button bar must be
|
||||
a subview of one of the split view's subviews.
|
||||
|
||||
Calling this method with nil as the button bar will remove any currently assigned button bar
|
||||
for the divider at that index. Indexes will not be adjusted as new subviews are added, so you
|
||||
should usually call this method after adding all the desired subviews to the split view.
|
||||
|
||||
This method will automatically configure the hasResizeControl and resizeControlIsLeftAligned
|
||||
This method will automatically configure the hasResizeControl and resizeControlIsLeftAligned
|
||||
parameters of the button bar, and will override any currently set values.
|
||||
*/
|
||||
- (void)setButtonBar:(CPButtonBar)aButtonBar forDividerAtIndex:(unsigned)dividerIndex
|
||||
@@ -670,7 +692,7 @@ var CPSplitViewHorizontalImage = nil,
|
||||
}
|
||||
|
||||
if (view !== self)
|
||||
[CPException raise:CPInvalidArgumentException
|
||||
[CPException raise:CPInvalidArgumentException
|
||||
reason:@"CPSplitView button bar must be a subview of the split view."];
|
||||
|
||||
var viewIndex = [[self subviews] indexOfObject:subview];
|
||||
@@ -678,7 +700,7 @@ var CPSplitViewHorizontalImage = nil,
|
||||
[aButtonBar setHasResizeControl:YES];
|
||||
[aButtonBar setResizeControlIsLeftAligned:dividerIndex < viewIndex];
|
||||
|
||||
_buttonBars[dividerIndex] = aButtonBar;
|
||||
_buttonBars[dividerIndex] = aButtonBar;
|
||||
}
|
||||
|
||||
- (void)_postNotificationWillResize
|
||||
@@ -715,7 +737,7 @@ var CPSplitViewDelegateKey = "CPSplitViewDelegateKey",
|
||||
_DOMDividerElements = [];
|
||||
|
||||
_buttonBars = [aCoder decodeObjectForKey:CPSplitViewButtonBarsKey] || [];
|
||||
|
||||
|
||||
_delegate = [aCoder decodeObjectForKey:CPSplitViewDelegateKey];
|
||||
|
||||
_isPaneSplitter = [aCoder decodeBoolForKey:CPSplitViewIsPaneSplitterKey];
|
||||
|
||||
@@ -25,8 +25,20 @@
|
||||
@import "CPPlatformString.j"
|
||||
|
||||
|
||||
var CPStringSizeWithFontInWidthCache = {};
|
||||
|
||||
CPStringSizeCachingEnabled = YES;
|
||||
|
||||
@implementation CPString (CPStringDrawing)
|
||||
|
||||
/*!
|
||||
Returns a dictionary with the items "ascender", "descender", "lineHeight"
|
||||
*/
|
||||
+ (CPDictionary)metricsOfFont:(CPFont)aFont
|
||||
{
|
||||
return [CPPlatformString metricsOfFont:aFont];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the string
|
||||
*/
|
||||
@@ -42,7 +54,19 @@
|
||||
|
||||
- (CGSize)sizeWithFont:(CPFont)aFont inWidth:(float)aWidth
|
||||
{
|
||||
return [CPPlatformString sizeOfString:self withFont:aFont forWidth:aWidth];
|
||||
if (!CPStringSizeCachingEnabled)
|
||||
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
|
||||
|
||||
+202
-553
@@ -1,32 +1,8 @@
|
||||
/*
|
||||
* 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 "CPBox.j"
|
||||
@import "CPSegmentedControl.j"
|
||||
@import "CPTabViewItem.j"
|
||||
@import "CPView.j"
|
||||
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
|
||||
|
||||
/*
|
||||
Places tabs on top with a bezeled border.
|
||||
@global
|
||||
@@ -34,7 +10,7 @@
|
||||
*/
|
||||
CPTopTabsBezelBorder = 0;
|
||||
//CPLeftTabsBezelBorder = 1;
|
||||
//CPBottomTabsBezelBorder = 2;
|
||||
CPBottomTabsBezelBorder = 2;
|
||||
//CPRightTabsBezelBorder = 3;
|
||||
/*
|
||||
Displays no tabs and has a bezeled border.
|
||||
@@ -55,173 +31,55 @@ CPNoTabsLineBorder = 5;
|
||||
*/
|
||||
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,
|
||||
CPTabViewShouldSelectTabViewItemSelector = 2,
|
||||
CPTabViewWillSelectTabViewItemSelector = 4,
|
||||
CPTabViewDidChangeNumberOfTabViewItemsSelector = 8;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPTabView
|
||||
var HEIGHT_OF_SEGMENTED_CONTROL = 24;
|
||||
|
||||
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
|
||||
{
|
||||
CPView _labelsView;
|
||||
CPView _backgroundView;
|
||||
CPView _separatorView;
|
||||
|
||||
CPView _auxiliaryView;
|
||||
CPView _contentView;
|
||||
|
||||
CPArray _tabViewItems;
|
||||
CPTabViewItem _selectedTabViewItem;
|
||||
CPArray items;
|
||||
|
||||
CPTabViewType _tabViewType;
|
||||
|
||||
id _delegate;
|
||||
unsigned _delegateSelectors;
|
||||
}
|
||||
CPSegmentedControl tabs;
|
||||
CPBox box;
|
||||
|
||||
/*
|
||||
@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,
|
||||
CPNumber selectedIndex;
|
||||
|
||||
bezelBorderLeftImage,
|
||||
backgroundImage,
|
||||
bezelBorderRightImage,
|
||||
CPTabViewType type;
|
||||
|
||||
bezelBorderLeftImage,
|
||||
bezerBorderImage,
|
||||
bezelBorderRightImage
|
||||
]]];
|
||||
|
||||
CPTabViewBezelBorderColor = [CPColor colorWithPatternImage:bezerBorderImage];
|
||||
}
|
||||
|
||||
/*
|
||||
@ignore
|
||||
*/
|
||||
+ (CPColor)bezelBorderColor
|
||||
{
|
||||
return CPTabViewBezelBorderColor;
|
||||
id delegate;
|
||||
unsigned delegateSelectors;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_tabViewType = CPTopTabsBezelBorder;
|
||||
_tabViewItems = [];
|
||||
items = [CPArray array];
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
- (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
|
||||
/*!
|
||||
Adds a CPTabViewItem to the tab view.
|
||||
@@ -229,7 +87,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (void)addTabViewItem:(CPTabViewItem)aTabViewItem
|
||||
{
|
||||
[self insertTabViewItem:aTabViewItem atIndex:[_tabViewItems count]];
|
||||
[self insertTabViewItem:aTabViewItem atIndex:[items count]];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -240,20 +98,13 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (void)insertTabViewItem:(CPTabViewItem)aTabViewItem atIndex:(unsigned)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];
|
||||
[items insertObject:aTabViewItem atIndex:anIndex];
|
||||
|
||||
if (_delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
|
||||
[_delegate tabViewDidChangeNumberOfTabViewItems:self];
|
||||
[self _updateItems];
|
||||
[self _repositionTabs];
|
||||
|
||||
if (delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
|
||||
[delegate tabViewDidChangeNumberOfTabViewItems:self];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -262,16 +113,19 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (void)removeTabViewItem:(CPTabViewItem)aTabViewItem
|
||||
{
|
||||
var index = [self indexOfTabViewItem:aTabViewItem];
|
||||
for (var i = 0; i < [items count]; i++)
|
||||
{
|
||||
if ([items objectAtIndex:i] === aTabViewItem)
|
||||
{
|
||||
[items removeObjectAtIndex:i];
|
||||
}
|
||||
}
|
||||
|
||||
[_tabViewItems removeObjectIdenticalTo:aTabViewItem];
|
||||
|
||||
[_labelsView tabView:self didRemoveTabViewItemAtIndex:index];
|
||||
|
||||
[aTabViewItem _setTabView:nil];
|
||||
|
||||
if (_delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
|
||||
[_delegate tabViewDidChangeNumberOfTabViewItems:self];
|
||||
[self _updateItems];
|
||||
[self _repositionTabs];
|
||||
|
||||
if (delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
|
||||
[delegate tabViewDidChangeNumberOfTabViewItems:self];
|
||||
}
|
||||
|
||||
// Accessing Tabs
|
||||
@@ -281,7 +135,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (int)indexOfTabViewItem:(CPTabViewItem)aTabViewItem
|
||||
{
|
||||
return [_tabViewItems indexOfObjectIdenticalTo:aTabViewItem];
|
||||
return [items indexOfObjectIdenticalTo:aTabViewItem];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -290,14 +144,11 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (int)indexOfTabViewItemWithIdentifier:(CPString)anIdentifier
|
||||
{
|
||||
var index = 0,
|
||||
count = [_tabViewItems count];
|
||||
|
||||
for (; index < count; ++index)
|
||||
if ([[_tabViewItems[index] identifier] isEqual:anIdentifier])
|
||||
for (var index = [items count]; index >= 0; index--)
|
||||
if ([[items[index] identifier] isEqual:anIdentifier])
|
||||
return index;
|
||||
|
||||
return index;
|
||||
return CPNotFound;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -305,7 +156,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (unsigned)numberOfTabViewItems
|
||||
{
|
||||
return [_tabViewItems count];
|
||||
return [items count];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -313,7 +164,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (CPTabViewItem)tabViewItemAtIndex:(unsigned)anIndex
|
||||
{
|
||||
return _tabViewItems[anIndex];
|
||||
return [items objectAtIndex:anIndex];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -321,7 +172,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (CPArray)tabViewItems
|
||||
{
|
||||
return _tabViewItems;
|
||||
return [items copy]; // Copy?
|
||||
}
|
||||
|
||||
// Selecting a Tab
|
||||
@@ -331,10 +182,10 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (void)selectFirstTabViewItem:(id)aSender
|
||||
{
|
||||
var count = [_tabViewItems count];
|
||||
|
||||
if (count)
|
||||
[self selectTabViewItemAtIndex:0];
|
||||
if ([items count] === 0)
|
||||
return; // throw?
|
||||
|
||||
[self selectTabViewItemAtIndex:0];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -343,10 +194,10 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (void)selectLastTabViewItem:(id)aSender
|
||||
{
|
||||
var count = [_tabViewItems count];
|
||||
|
||||
if (count)
|
||||
[self selectTabViewItemAtIndex:count - 1];
|
||||
if ([items count] === 0)
|
||||
return; // throw?
|
||||
|
||||
[self selectTabViewItemAtIndex:[items count] - 1];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -355,13 +206,16 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (void)selectNextTabViewItem:(id)aSender
|
||||
{
|
||||
if (!_selectedTabViewItem)
|
||||
if (selectedIndex === CPNotFound)
|
||||
return;
|
||||
|
||||
var index = [self indexOfTabViewItem:_selectedTabViewItem],
|
||||
count = [_tabViewItems count];
|
||||
|
||||
[self selectTabViewItemAtIndex:index + 1 % count];
|
||||
|
||||
var nextIndex = selectedIndex + 1;
|
||||
|
||||
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:)
|
||||
return;
|
||||
|
||||
[self selectTabViewItemAtIndex:nextIndex];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -370,13 +224,15 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (void)selectPreviousTabViewItem:(id)aSender
|
||||
{
|
||||
if (!_selectedTabViewItem)
|
||||
if (selectedIndex === CPNotFound)
|
||||
return;
|
||||
|
||||
var index = [self indexOfTabViewItem:_selectedTabViewItem],
|
||||
count = [_tabViewItems count];
|
||||
|
||||
[self selectTabViewItemAtIndex:index == 0 ? count : index - 1];
|
||||
|
||||
var previousIndex = selectedIndex - 1;
|
||||
|
||||
if (previousIndex < 0)
|
||||
return; // does nothing. See above.
|
||||
|
||||
[self selectTabViewItemAtIndex:previousIndex];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -385,41 +241,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (void)selectTabViewItem:(CPTabViewItem)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];
|
||||
[self selectTabViewItemAtIndex:[self indexOfTabViewItem:aTabViewItem]];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -428,7 +250,24 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (void)selectTabViewItemAtIndex:(unsigned)anIndex
|
||||
{
|
||||
[self selectTabViewItem:_tabViewItems[anIndex]];
|
||||
var aTabViewItem = [items objectAtIndex: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];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -436,32 +275,43 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (CPTabViewItem)selectedTabViewItem
|
||||
{
|
||||
return _selectedTabViewItem;
|
||||
return [items objectAtIndex:selectedIndex];
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
/*!
|
||||
Sets the tab view type.
|
||||
@param aTabViewType the view type
|
||||
*/
|
||||
- (void)setTabViewType:(CPTabViewType)aTabViewType
|
||||
{
|
||||
if (_tabViewType == aTabViewType)
|
||||
if (type === aTabViewType)
|
||||
return;
|
||||
|
||||
_tabViewType = aTabViewType;
|
||||
|
||||
if (_tabViewType == CPNoTabsBezelBorder || _tabViewType == CPNoTabsLineBorder || _tabViewType == CPNoTabsNoBorder)
|
||||
[_labelsView removeFromSuperview];
|
||||
else if (![_labelsView superview])
|
||||
[self addSubview:_labelsView];
|
||||
|
||||
if (_tabViewType == CPNoTabsLineBorder || _tabViewType == CPNoTabsNoBorder)
|
||||
[_backgroundView removeFromSuperview];
|
||||
else if (![_backgroundView superview])
|
||||
[self addSubview:_backgroundView];
|
||||
|
||||
[self layoutSubviews];
|
||||
|
||||
if ((type === CPTopTabsBezelBorder || type === CPBottomTabsBezelBorder)
|
||||
&& (aTabViewType !== CPTopTabsBezelBorder && aTabViewType !== CPBottomTabsBezelBorder))
|
||||
[tabs removeFromSuperview];
|
||||
|
||||
if ((type === CPNoTabsBezelBorder || type === CPNoTabsLineBorder || type === CPNoTabsNoBorder)
|
||||
&& (aTabViewType !== CPNoTabsBezelBorder && aTabViewType !== CPNoTabsBezelBorder && aTabViewType !== CPNoTabsNoBorder))
|
||||
[self addSubview:tabs];
|
||||
|
||||
type = aTabViewType;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case CPTopTabsBezelBorder:
|
||||
case CPBottomTabsBezelBorder:
|
||||
case CPNoTabsBezelBorder:
|
||||
[box setBorderType:CPBezelBorder];
|
||||
break;
|
||||
case CPNoTabsLineBorder:
|
||||
[box setBorderType:CPLineBorder];
|
||||
break;
|
||||
case CPNoTabsNoBorder:
|
||||
[box setBorderType:CPNoBorder];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -469,31 +319,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (CPTabViewType)tabViewType
|
||||
{
|
||||
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;
|
||||
return type;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -501,7 +327,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (id)delegate
|
||||
{
|
||||
return _delegate;
|
||||
return delegate;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -510,35 +336,74 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (void)setDelegate:(id)aDelegate
|
||||
{
|
||||
if (_delegate == aDelegate)
|
||||
if (delegate == aDelegate)
|
||||
return;
|
||||
|
||||
_delegate = aDelegate;
|
||||
|
||||
_delegateSelectors = 0;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(tabView:shouldSelectTabViewItem:)])
|
||||
_delegateSelectors |= CPTabViewShouldSelectTabViewItemSelector;
|
||||
delegate = aDelegate;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(tabView:willSelectTabViewItem:)])
|
||||
_delegateSelectors |= CPTabViewWillSelectTabViewItemSelector;
|
||||
delegateSelectors = 0;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(tabView:didSelectTabViewItem:)])
|
||||
_delegateSelectors |= CPTabViewDidSelectTabViewItemSelector;
|
||||
if ([delegate respondsToSelector:@selector(tabView:shouldSelectTabViewItem:)])
|
||||
delegateSelectors |= CPTabViewShouldSelectTabViewItemSelector;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(tabViewDidChangeNumberOfTabViewItems:)])
|
||||
_delegateSelectors |= CPTabViewDidChangeNumberOfTabViewItemsSelector;
|
||||
if ([delegate respondsToSelector:@selector(tabView:willSelectTabViewItem:)])
|
||||
delegateSelectors |= CPTabViewWillSelectTabViewItemSelector;
|
||||
|
||||
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
|
||||
{
|
||||
var location = [_labelsView convertPoint:[anEvent locationInWindow] fromView:nil],
|
||||
tabViewItem = [_labelsView representedTabViewItemAtPoint:location];
|
||||
|
||||
if (tabViewItem)
|
||||
[self selectTabViewItem:tabViewItem];
|
||||
var segmentIndex = [tabs testSegment:[tabs convertPoint:[anEvent locationInWindow] fromView:nil]];
|
||||
|
||||
if (segmentIndex != CPNotFound)
|
||||
{
|
||||
[self selectTabViewItemAtIndex:segmentIndex];
|
||||
[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
|
||||
@@ -554,20 +419,17 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
|
||||
{
|
||||
if (self = [super initWithCoder:aCoder])
|
||||
{
|
||||
_tabViewType = [aCoder decodeIntForKey:CPTabViewTypeKey];
|
||||
_tabViewItems = [];
|
||||
|
||||
// FIXME: this is somewhat hacky
|
||||
[self _createBezelBorder];
|
||||
|
||||
var items = [aCoder decodeObjectForKey:CPTabViewItemsKey];
|
||||
for (var i = 0; items && i < items.length; i++)
|
||||
[self insertTabViewItem:items[i] atIndex:i];
|
||||
|
||||
type = [aCoder decodeIntForKey:CPTabViewTypeKey];
|
||||
items = [];
|
||||
|
||||
var encodedItems = [aCoder decodeObjectForKey:CPTabViewItemsKey];
|
||||
for (var i = 0; encodedItems && i < encodedItems.length; i++)
|
||||
[self insertTabViewItem:encodedItems[i] atIndex:i];
|
||||
|
||||
var selected = [aCoder decodeObjectForKey:CPTabViewSelectedItemKey];
|
||||
if (selected)
|
||||
[self selectTabViewItem:selected];
|
||||
|
||||
|
||||
[self setDelegate:[aCoder decodeObjectForKey:CPTabViewDelegateKey]];
|
||||
}
|
||||
|
||||
@@ -576,227 +438,14 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
var actualSubviews = _subviews;
|
||||
_subviews = [];
|
||||
[super encodeWithCoder:aCoder];
|
||||
_subviews = actualSubviews;
|
||||
|
||||
[aCoder encodeObject:_tabViewItems forKey:CPTabViewItemsKey];;
|
||||
[aCoder encodeObject:_selectedTabViewItem forKey:CPTabViewSelectedItemKey];
|
||||
|
||||
[aCoder encodeInt:_tabViewType forKey:CPTabViewTypeKey];
|
||||
|
||||
[aCoder encodeConditionalObject:_delegate forKey:CPTabViewDelegateKey];
|
||||
}
|
||||
|
||||
@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]];
|
||||
|
||||
[aCoder encodeObject:items forKey:CPTabViewItemsKey];;
|
||||
[aCoder encodeObject:[self selectedTabViewItem] forKey:CPTabViewSelectedItemKey];
|
||||
|
||||
[aCoder encodeInt:type forKey:CPTabViewTypeKey];
|
||||
|
||||
[aCoder encodeConditionalObject:delegate forKey:CPTabViewDelegateKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
@import <AppKit/CPView.j>
|
||||
@import "CPView.j"
|
||||
|
||||
|
||||
/*
|
||||
|
||||
+112
-28
@@ -22,12 +22,12 @@
|
||||
|
||||
@import <Foundation/CPDictionary.j>
|
||||
@import <Foundation/CPObject.j>
|
||||
@import <Foundation/CPIndexSet.j>
|
||||
@import <Foundation/CPSortDescriptor.j>
|
||||
@import <Foundation/CPString.j>
|
||||
|
||||
@import "CPTableHeaderView.j"
|
||||
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
|
||||
CPTableColumnNoResizing = 0;
|
||||
CPTableColumnAutoresizingMask = 1 << 0;
|
||||
@@ -50,7 +50,7 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
CPSortDescriptor _sortDescriptorPrototype;
|
||||
BOOL _isHidden;
|
||||
CPString _headerToolTip;
|
||||
|
||||
|
||||
BOOL _disableResizingPosting @accessors(property=disableResizingPosting);
|
||||
}
|
||||
|
||||
@@ -72,19 +72,13 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
_maxWidth = 1000000.0;
|
||||
_resizingMask = CPTableColumnAutoresizingMask | CPTableColumnUserResizingMask;
|
||||
_disableResizingPosting = NO;
|
||||
|
||||
|
||||
[self setIdentifier:anIdentifier];
|
||||
|
||||
var header = [[_CPTableColumnHeaderView alloc] initWithFrame:CGRectMakeZero()];
|
||||
[self setHeaderView:header];
|
||||
|
||||
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];
|
||||
|
||||
[self setDataView:[CPTextField new]];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -123,19 +117,19 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
{
|
||||
var index = [[tableView tableColumns] indexOfObjectIdenticalTo:self],
|
||||
dirtyTableColumnRangeIndex = tableView._dirtyTableColumnRangeIndex;
|
||||
|
||||
|
||||
if (dirtyTableColumnRangeIndex < 0)
|
||||
tableView._dirtyTableColumnRangeIndex = index;
|
||||
else
|
||||
tableView._dirtyTableColumnRangeIndex = MIN(index, tableView._dirtyTableColumnRangeIndex);
|
||||
|
||||
|
||||
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.
|
||||
[tableView _layoutDataViewsInRows:rows columns:columns];
|
||||
[tableView tile];
|
||||
|
||||
|
||||
if (!_disableResizingPosting)
|
||||
[self _postDidResizeNotificationWithOldWidth:oldWidth];
|
||||
}
|
||||
@@ -232,12 +226,12 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
|
||||
/*!
|
||||
This method set's the "prototype" view which will be used to create all table cells in this column.
|
||||
|
||||
It creates a snapshot of aView, using keyed archiving, which is then copied over and over for each
|
||||
|
||||
It creates a snapshot of aView, using keyed archiving, which is then copied over and over for each
|
||||
individual cell that is shown. As a result, changes made after calling this method won't be reflected.
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
[tableColumn setDataView:someView]; // snapshot taken
|
||||
[[tableColumn dataView] setSomething:x]; //won't work
|
||||
|
||||
@@ -248,12 +242,11 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
*/
|
||||
- (void)setDataView:(CPView)aView
|
||||
{
|
||||
if (_dataView === aView)
|
||||
return;
|
||||
|
||||
if (_dataView)
|
||||
_dataViewData[[_dataView UID]] = nil;
|
||||
|
||||
[aView setThemeState:CPThemeStateTableDataView];
|
||||
|
||||
_dataView = aView;
|
||||
_dataViewData[[aView UID]] = [CPKeyedArchiver archivedDataWithRootObject:aView];
|
||||
}
|
||||
@@ -292,7 +285,10 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
// unarchive the data view cache
|
||||
var newDataView = [CPKeyedUnarchiver unarchiveObjectWithData:_dataViewData[dataViewUID]];
|
||||
newDataView.identifier = dataViewUID;
|
||||
|
||||
|
||||
// make sure only we have control over the size and placement
|
||||
[newDataView setAutoresizingMask:CPViewNotSizable];
|
||||
|
||||
return newDataView;
|
||||
}
|
||||
|
||||
@@ -325,7 +321,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.
|
||||
*/
|
||||
- (BOOL)isEditable
|
||||
@@ -348,7 +344,14 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
|
||||
- (void)setHidden:(BOOL)shouldBeHidden
|
||||
{
|
||||
shouldBeHidden = !!shouldBeHidden
|
||||
if (_isHidden === shouldBeHidden)
|
||||
return;
|
||||
|
||||
_isHidden = shouldBeHidden;
|
||||
|
||||
[[self headerView] setHidden:shouldBeHidden];
|
||||
[[self tableView] _tableColumnVisibilityDidChange:self];
|
||||
}
|
||||
|
||||
- (BOOL)isHidden
|
||||
@@ -359,7 +362,7 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
//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.
|
||||
*/
|
||||
- (void)setHeaderToolTip:(CPString)aToolTip
|
||||
@@ -382,13 +385,86 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
|
||||
@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",
|
||||
CPTableColumnHeaderViewKey = @"CPTableColumnHeaderViewKey",
|
||||
CPTableColumnDataViewKey = @"CPTableColumnDataViewKey",
|
||||
CPTableColumnWidthKey = @"CPTableColumnWidthKey",
|
||||
CPTableColumnMinWidthKey = @"CPTableColumnMinWidthKey",
|
||||
CPTableColumnMaxWidthKey = @"CPTableColumnMaxWidthKey",
|
||||
CPTableColumnResizingMaskKey = @"CPTableColumnResizingMaskKey";
|
||||
CPTableColumnResizingMaskKey = @"CPTableColumnResizingMaskKey",
|
||||
CPTableColumnIsHiddenKey = @"CPTableColumnIsHiddenKey",
|
||||
CPSortDescriptorPrototypeKey = @"CPSortDescriptorPrototypeKey",
|
||||
CPTableColumnIsEditableKey = @"CPTableColumnIsEditableKey";
|
||||
|
||||
@implementation CPTableColumn (CPCoding)
|
||||
|
||||
@@ -409,7 +485,11 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
|
||||
[self setDataView:[aCoder decodeObjectForKey:CPTableColumnDataViewKey]];
|
||||
[self setHeaderView:[aCoder decodeObjectForKey:CPTableColumnHeaderViewKey]];
|
||||
|
||||
_resizingMask = [aCoder decodeBoolForKey:CPTableColumnResizingMaskKey];
|
||||
_resizingMask = [aCoder decodeIntForKey:CPTableColumnResizingMaskKey];
|
||||
_isHidden = [aCoder decodeBoolForKey:CPTableColumnIsHiddenKey];
|
||||
_isEditable = [aCoder decodeBoolForKey:CPTableColumnIsEditableKey];
|
||||
|
||||
_sortDescriptorPrototype = [aCoder decodeObjectForKey:CPSortDescriptorPrototypeKey];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -427,6 +507,10 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
|
||||
[aCoder encodeObject:_dataView forKey:CPTableColumnDataViewKey];
|
||||
|
||||
[aCoder encodeObject:_resizingMask forKey:CPTableColumnResizingMaskKey];
|
||||
[aCoder encodeBool:_isHidden forKey:CPTableColumnIsHiddenKey];
|
||||
[aCoder encodeBool:_isEditable forKey:CPTableColumnIsEditableKey];
|
||||
|
||||
[aCoder encodeObject:_sortDescriptorPrototype forKey:CPSortDescriptorPrototypeKey];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -463,4 +547,4 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
|
||||
reason:@"dataCellForRow: is not supported. Use -dataViewForRow:row instead."];
|
||||
}
|
||||
|
||||
@end
|
||||
@end
|
||||
|
||||
+379
-193
@@ -20,54 +20,64 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <Foundation/CPIndexSet.j>
|
||||
|
||||
@import "CPTableColumn.j"
|
||||
@import "CPTableView.j"
|
||||
@import "CPView.j"
|
||||
|
||||
|
||||
|
||||
@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
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
if (self)
|
||||
{
|
||||
[self _init];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)_init
|
||||
{
|
||||
_textField = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(5, 1, CGRectGetWidth([self bounds]) - 10, CGRectGetHeight([self bounds]) - 1)];
|
||||
_textField = [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
|
||||
[_textField setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
|
||||
|
||||
|
||||
[_textField setLineBreakMode:CPLineBreakByTruncatingTail];
|
||||
[_textField setTextColor: [CPColor colorWithHexString: @"333333"]];
|
||||
[_textField setFont:[CPFont boldSystemFontOfSize:12.0]];
|
||||
[_textField setAlignment:CPLeftTextAlignment];
|
||||
[_textField setVerticalAlignment:CPCenterVerticalTextAlignment];
|
||||
[_textField setTextShadowColor:[CPColor whiteColor]];
|
||||
[_textField setTextShadowOffset:CGSizeMake(0,1)];
|
||||
|
||||
[self addSubview:_textField];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
var themeState = [self themeState];
|
||||
[self setBackgroundColor:[self currentValueForThemeAttribute:@"background-color"]];
|
||||
|
||||
if(themeState & CPThemeStateSelected && themeState & CPThemeStateHighlighted)
|
||||
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-highlighted-pressed.png", CGSizeMake(1.0, 22.0))]];
|
||||
else if (themeState & CPThemeStateSelected)
|
||||
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-highlighted.png", CGSizeMake(1.0, 22.0))]];
|
||||
else if (themeState & CPThemeStateHighlighted)
|
||||
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-pressed.png", CGSizeMake(1.0, 22.0))]];
|
||||
else
|
||||
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview.png", CGSizeMake(1.0, 22.0))]];
|
||||
var inset = [self currentValueForThemeAttribute:@"text-inset"],
|
||||
bounds = [self bounds];
|
||||
|
||||
[_textField setFrame:_CGRectMake(inset.right, inset.top, bounds.size.width - inset.right - inset.left, bounds.size.height - inset.top - inset.bottom)];
|
||||
[_textField setTextColor:[self currentValueForThemeAttribute:@"text-color"]];
|
||||
[_textField setFont:[self currentValueForThemeAttribute:@"text-font"]];
|
||||
[_textField setTextShadowColor:[self currentValueForThemeAttribute:@"text-shadow-color"]];
|
||||
[_textField setTextShadowOffset:[self currentValueForThemeAttribute:@"text-shadow-offset"]];
|
||||
[_textField setAlignment:[self currentValueForThemeAttribute:@"text-alignment"]];
|
||||
}
|
||||
|
||||
- (void)setStringValue:(CPString)string
|
||||
@@ -95,11 +105,6 @@
|
||||
[_textField setFont:aFont];
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue forThemeAttribute:(id)aKey
|
||||
{
|
||||
[_textField setValue:aValue forThemeAttribute:aKey];
|
||||
}
|
||||
|
||||
- (void)_setIndicatorImage:(CPImage)anImage
|
||||
{
|
||||
if (anImage)
|
||||
@@ -137,7 +142,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
|
||||
[aCoder encodeObject:[_textField text] forKey:_CPTableColumnHeaderViewStringValueKey];
|
||||
[aCoder encodeObject:[_textField image] forKey:_CPTableColumnHeaderViewImageKey];
|
||||
[aCoder encodeObject:[_textField font] forKey:_CPTableColumnHeaderViewFontKey];
|
||||
@@ -147,27 +152,47 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
|
||||
@implementation CPTableHeaderView : CPView
|
||||
{
|
||||
int _resizedColumn @accessors(readonly, property=resizedColumn);
|
||||
int _draggedColumn @accessors(readonly, property=draggedColumn);
|
||||
int _pressedColumn @accessors(readonly, property=pressedColumn);
|
||||
|
||||
float _draggedDistance @accessors(readonly, property=draggedDistance);
|
||||
float _lastLocation;
|
||||
float _columnOldWidth;
|
||||
|
||||
CPTableView _tableView @accessors(property=tableView);
|
||||
CGPoint _mouseDownLocation;
|
||||
CGPoint _previousTrackingLocation;
|
||||
int _activeColumn;
|
||||
int _pressedColumn;
|
||||
|
||||
BOOL _isResizing;
|
||||
BOOL _isDragging;
|
||||
BOOL _isTrackingColumn;
|
||||
BOOL _drawsColumnLines;
|
||||
|
||||
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
|
||||
{
|
||||
_resizedColumn = -1;
|
||||
_draggedColumn = -1;
|
||||
_mouseDownLocation = _CGPointMakeZero();
|
||||
_previousTrackingLocation = _CGPointMakeZero();
|
||||
_activeColumn = -1;
|
||||
_pressedColumn = -1;
|
||||
_draggedDistance = 0.0;
|
||||
_lastLocation = nil;
|
||||
_columnOldWidth = nil;
|
||||
|
||||
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview.png", CGSizeMake(1.0, 22.0))]];
|
||||
_isResizing = NO;
|
||||
_isDragging = NO;
|
||||
_isTrackingColumn = NO;
|
||||
_drawsColumnLines = YES;
|
||||
|
||||
_columnOldWidth = 0.0;
|
||||
|
||||
[self setBackgroundColor:[self currentValueForThemeAttribute:@"background-color"]];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
@@ -182,39 +207,41 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
|
||||
- (int)columnAtPoint:(CGPoint)aPoint
|
||||
{
|
||||
return [_tableView columnAtPoint:CGPointMake(aPoint.x, 0)];
|
||||
return [_tableView columnAtPoint:CGPointMake(aPoint.x, aPoint.y)];
|
||||
}
|
||||
|
||||
- (CGRect)headerRectOfColumn:(int)aColumnIndex
|
||||
{
|
||||
var tableColumns = [_tableView tableColumns];
|
||||
var headerRect = [self bounds],
|
||||
columnRect = [_tableView rectOfColumn:aColumnIndex];
|
||||
|
||||
if (aColumnIndex < 0 || aColumnIndex > [tableColumns count])
|
||||
[CPException raise:"invalid" reason:"tried to get headerRectOfColumn: on invalid column"];
|
||||
headerRect.origin.x = _CGRectGetMinX(columnRect);
|
||||
headerRect.size.width = _CGRectGetWidth(columnRect);
|
||||
|
||||
// UPDATE COLUMN RANGES ?
|
||||
|
||||
var tableRange = _tableView._tableColumnRanges[aColumnIndex],
|
||||
bounds = [self bounds];
|
||||
return headerRect;
|
||||
}
|
||||
|
||||
var rMinX = ROUND(tableRange.location);
|
||||
bounds.origin.x = rMinX;
|
||||
bounds.size.width = FLOOR(tableRange.length + tableRange.location - rMinX);
|
||||
|
||||
return bounds;
|
||||
- (void)setDrawsColumnLines:(BOOL)aFlag
|
||||
{
|
||||
_drawsColumnLines = aFlag;
|
||||
}
|
||||
|
||||
- (BOOL)drawsColumnLines
|
||||
{
|
||||
return _drawsColumnLines;
|
||||
}
|
||||
|
||||
- (CGRect)_cursorRectForColumn:(int)column
|
||||
{
|
||||
if (column == -1 || !([_tableView._tableColumns[column] resizingMask] & CPTableColumnUserResizingMask))
|
||||
return CGRectMakeZero();
|
||||
return _CGRectMakeZero();
|
||||
|
||||
var rect = [self headerRectOfColumn:column];
|
||||
|
||||
rect.origin.x = CGRectGetMaxX(rect) - 5;
|
||||
rect.origin.x = _CGRectGetMaxX(rect) - 5;
|
||||
rect.size.width = 20;
|
||||
|
||||
return rect;
|
||||
return rect;
|
||||
}
|
||||
|
||||
- (void)_setPressedColumn:(CPInteger)column
|
||||
@@ -223,117 +250,293 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
{
|
||||
var headerView = [_tableView._tableColumns[_pressedColumn] headerView];
|
||||
[headerView unsetThemeState:CPThemeStateHighlighted];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (column != -1)
|
||||
{
|
||||
var headerView = [_tableView._tableColumns[column] headerView];
|
||||
[headerView setThemeState:CPThemeStateHighlighted];
|
||||
}
|
||||
|
||||
|
||||
_pressedColumn = column;
|
||||
}
|
||||
|
||||
- (void)mouseDown:(CPEvent)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];
|
||||
}
|
||||
[self trackMouse:theEvent];
|
||||
}
|
||||
|
||||
- (void)trackMouseWithEvent:(CPEvent)theEvent
|
||||
- (void)trackMouse:(CPEvent)theEvent
|
||||
{
|
||||
var type = [theEvent type];
|
||||
|
||||
if (type == CPLeftMouseUp)
|
||||
{
|
||||
var location = [self convertPoint:[theEvent locationInWindow] fromView:nil],
|
||||
clickedColumn = [self columnAtPoint:location];
|
||||
var type = [theEvent type],
|
||||
currentLocation = [self convertPoint:[theEvent locationInWindow] fromView:nil];
|
||||
|
||||
[self _setPressedColumn:-1];
|
||||
|
||||
if (clickedColumn != -1)
|
||||
[_tableView _didClickTableColumn:clickedColumn modifierFlags:[theEvent modifierFlags]];
|
||||
|
||||
return;
|
||||
}
|
||||
// Take the right columns resize tracking area into account
|
||||
currentLocation.x -= 5.0;
|
||||
|
||||
[CPApp setTarget:self selector:@selector(trackMouseWithEvent:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPLeftMouseDownMask untilDate:nil inMode:nil dequeue:YES];
|
||||
}
|
||||
|
||||
- (void)trackResizeWithEvent:(CPEvent)anEvent
|
||||
{
|
||||
var location = [self convertPoint:[anEvent locationInWindow] fromView:nil],
|
||||
tableColumn = [[_tableView tableColumns] objectAtIndex:_resizedColumn],
|
||||
type = [anEvent type];
|
||||
|
||||
if (_lastLocation == nil)
|
||||
_lastLocation = location;
|
||||
|
||||
if (_columnOldWidth == nil)
|
||||
_columnOldWidth = [tableColumn width];
|
||||
var columnIndex = [self columnAtPoint:currentLocation],
|
||||
shouldResize = [self shouldResizeTableColumn:columnIndex at:_CGPointMake(currentLocation.x + 5.0, currentLocation.y)];
|
||||
|
||||
if (type === CPLeftMouseUp)
|
||||
{
|
||||
[self _updateResizeCursor:anEvent];
|
||||
|
||||
[tableColumn _postDidResizeNotificationWithOldWidth:_columnOldWidth];
|
||||
[tableColumn setDisableResizingPosting:NO];
|
||||
[_tableView setDisableAutomaticResizing:NO];
|
||||
|
||||
_resizedColumn = -1;
|
||||
_lastLocation = nil;
|
||||
_columnOldWidth = nil;
|
||||
|
||||
return;
|
||||
}
|
||||
else if (type === CPLeftMouseDragged)
|
||||
{
|
||||
var newWidth = [tableColumn width] + location.x - _lastLocation.x;
|
||||
|
||||
if (newWidth < [tableColumn minWidth])
|
||||
[[CPCursor resizeRightCursor] set];
|
||||
else if (newWidth > [tableColumn maxWidth])
|
||||
[[CPCursor resizeLeftCursor] set];
|
||||
if (shouldResize)
|
||||
[self stopResizingTableColumn:_activeColumn at:currentLocation];
|
||||
else if ([self _shouldStopTrackingTableColumn:columnIndex at:currentLocation])
|
||||
{
|
||||
[_tableView _didClickTableColumn:columnIndex modifierFlags:[theEvent modifierFlags]];
|
||||
[self stopTrackingTableColumn:columnIndex at:currentLocation];
|
||||
|
||||
_isTrackingColumn = NO;
|
||||
}
|
||||
|
||||
[self _updateResizeCursor:[CPApp currentEvent]];
|
||||
|
||||
_activeColumn = CPNotFound;
|
||||
return;
|
||||
}
|
||||
|
||||
if (type === CPLeftMouseDown)
|
||||
{
|
||||
if (columnIndex === -1)
|
||||
return;
|
||||
|
||||
_mouseDownLocation = currentLocation;
|
||||
_activeColumn = columnIndex;
|
||||
|
||||
[_tableView _sendDelegateDidMouseDownInHeader:columnIndex];
|
||||
|
||||
if (shouldResize)
|
||||
[self startResizingTableColumn:columnIndex at:currentLocation];
|
||||
else
|
||||
{
|
||||
_tableView._lastColumnShouldSnap = NO;
|
||||
[tableColumn setWidth:newWidth];
|
||||
// FIXME: there has to be a better way to do this...
|
||||
// We should refactor the auto resizing crap.
|
||||
// We need to figure out the exact cocoa behavior here though.
|
||||
_lastLocation = location;
|
||||
[self startTrackingTableColumn:columnIndex at:currentLocation];
|
||||
_isTrackingColumn = YES;
|
||||
}
|
||||
}
|
||||
else if (type === CPLeftMouseDragged)
|
||||
{
|
||||
if (shouldResize)
|
||||
[self continueResizingTableColumn:_activeColumn at:currentLocation];
|
||||
else
|
||||
{
|
||||
if (_activeColumn === columnIndex && _CGRectContainsPoint([self headerRectOfColumn:columnIndex], currentLocation))
|
||||
{
|
||||
if (_isTrackingColumn && _pressedColumn !== -1)
|
||||
{
|
||||
if (![self continueTrackingTableColumn:columnIndex at:currentLocation])
|
||||
return; // Stop tracking the column, because it's being dragged
|
||||
} else
|
||||
[self startTrackingTableColumn:columnIndex at:currentLocation];
|
||||
|
||||
[[CPCursor resizeLeftRightCursor] set];
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
} else if (_isTrackingColumn && _pressedColumn !== -1)
|
||||
[self stopTrackingTableColumn:_activeColumn at:currentLocation];
|
||||
}
|
||||
}
|
||||
|
||||
[CPApp setTarget:self selector:@selector(trackResizeWithEvent:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
|
||||
_previousTrackingLocation = currentLocation;
|
||||
[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
|
||||
@@ -345,15 +548,15 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
return;
|
||||
}
|
||||
|
||||
var mouseLocation = [self convertPoint:[theEvent locationInWindow] fromView:nil],
|
||||
var mouseLocation = [self convertPoint:[theEvent locationInWindow] fromView:nil],
|
||||
mouseOverLocation = CGPointMake(mouseLocation.x - 5, mouseLocation.y),
|
||||
overColumn = [self columnAtPoint:mouseOverLocation];
|
||||
|
||||
if (overColumn >= 0 && CGRectContainsPoint([self _cursorRectForColumn:overColumn], mouseLocation))
|
||||
|
||||
if (overColumn >= 0 && _CGRectContainsPoint([self _cursorRectForColumn:overColumn], mouseLocation))
|
||||
{
|
||||
var tableColumn = [[_tableView tableColumns] objectAtIndex:overColumn],
|
||||
width = [tableColumn width];
|
||||
|
||||
|
||||
if (width == [tableColumn minWidth])
|
||||
[[CPCursor resizeRightCursor] set];
|
||||
else if (width == [tableColumn maxWidth])
|
||||
@@ -365,14 +568,8 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
[[CPCursor arrowCursor] set];
|
||||
}
|
||||
|
||||
- (void)viewDidMoveToWindow
|
||||
{
|
||||
//if ([_tableView allowsColumnResizing])
|
||||
// [[self window] setAcceptsMouseMovedEvents:YES];
|
||||
}
|
||||
|
||||
- (void)mouseEntered:(CPEvent)theEvent
|
||||
{
|
||||
{
|
||||
[self _updateResizeCursor:theEvent];
|
||||
}
|
||||
|
||||
@@ -390,31 +587,33 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
var tableColumns = [_tableView tableColumns],
|
||||
count = [tableColumns count];
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
count = [tableColumns count];
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var column = [tableColumns objectAtIndex:i],
|
||||
headerView = [column headerView];
|
||||
|
||||
|
||||
var frame = [self headerRectOfColumn:i];
|
||||
frame.size.height -= 0.5;
|
||||
if (i > 0)
|
||||
if (i > 0)
|
||||
{
|
||||
frame.origin.x += 0.5;
|
||||
frame.size.width -= 1;
|
||||
}
|
||||
|
||||
|
||||
[headerView setFrame:frame];
|
||||
|
||||
|
||||
if([headerView superview] != self)
|
||||
[self addSubview:headerView];
|
||||
}
|
||||
|
||||
[self setBackgroundColor:[self currentValueForThemeAttribute:@"background-color"]];
|
||||
}
|
||||
|
||||
- (void)drawRect:(CGRect)aRect
|
||||
{
|
||||
if (!_tableView)
|
||||
if (!_tableView || ![self drawsColumnLines])
|
||||
return;
|
||||
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||
@@ -426,55 +625,41 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
exposedRange = CPMakeRange(firstIndex, [exposedTableColumns lastIndex] - firstIndex + 1);
|
||||
|
||||
CGContextSetLineWidth(context, 1);
|
||||
CGContextSetStrokeColor(context, [_tableView gridColor]);
|
||||
CGContextSetStrokeColor(context, [self currentValueForThemeAttribute:@"divider-color"]);
|
||||
|
||||
[exposedColumnIndexes getIndexes:columnsArray maxCount:-1 inIndexRange:exposedRange];
|
||||
|
||||
var columnArrayIndex = 0,
|
||||
columnArrayCount = columnsArray.length,
|
||||
columnMaxX;
|
||||
|
||||
|
||||
CGContextBeginPath(context);
|
||||
for(; columnArrayIndex < columnArrayCount; columnArrayIndex++)
|
||||
{
|
||||
// grab each column rect and add vertical lines
|
||||
var columnIndex = columnsArray[columnArrayIndex],
|
||||
columnToStroke = [self headerRectOfColumn:columnIndex];
|
||||
|
||||
columnMaxX = CGRectGetMaxX(columnToStroke);
|
||||
|
||||
CGContextMoveToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(CGRectGetMinY(columnToStroke)));
|
||||
CGContextAddLineToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(CGRectGetMaxY(columnToStroke)));
|
||||
|
||||
columnMaxX = _CGRectGetMaxX(columnToStroke);
|
||||
|
||||
CGContextMoveToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(_CGRectGetMinY(columnToStroke)));
|
||||
CGContextAddLineToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(_CGRectGetMaxY(columnToStroke)));
|
||||
}
|
||||
|
||||
|
||||
CGContextClosePath(context);
|
||||
CGContextStrokePath(context);
|
||||
|
||||
/*
|
||||
var maxY = CGRectGetMaxY([self bounds]);
|
||||
// draw normal gradient for remaining space
|
||||
if (supportsCanvasGradient)
|
||||
|
||||
/*if (_isDragging)
|
||||
{
|
||||
aRect.origin.x = columnMaxX - 0.5;
|
||||
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);
|
||||
*/
|
||||
CGContextSetFillColor(context, [CPColor grayColor]);
|
||||
CGContextFillRect(context, [self headerRectOfColumn:_activeColumn])
|
||||
}*/
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey";
|
||||
var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey",
|
||||
CPTableHeaderViewDrawsColumnLines = @"CPTableHeaderViewDrawsColumnLines";
|
||||
|
||||
@implementation CPTableHeaderView (CPCoding)
|
||||
|
||||
@@ -484,6 +669,7 @@ var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey";
|
||||
{
|
||||
[self _init];
|
||||
_tableView = [aCoder decodeObjectForKey:CPTableHeaderViewTableViewKey];
|
||||
_drawsColumnLines = [aCoder decodeBoolForKey:CPTableHeaderViewDrawsColumnLines];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -493,7 +679,7 @@ var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey";
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
[aCoder encodeObject:_tableView forKey:CPTableHeaderViewTableViewKey];
|
||||
[aCoder encodeBool:_drawsColumnLines forKey:CPTableHeaderViewDrawsColumnLines];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
+1040
-527
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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";
|
||||
+266
-119
@@ -26,9 +26,6 @@
|
||||
@import "CPCompatibility.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. */
|
||||
CPTextFieldRoundedBezel = 1; /*! A textfield bezel with rounded corners. */
|
||||
@@ -49,7 +46,7 @@ var CPTextFieldDOMInputElement = nil,
|
||||
CPTextFieldCachedSelectStartFunction = nil,
|
||||
CPTextFieldCachedDragFunction = nil,
|
||||
CPTextFieldBlurFunction = nil;
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
var CPSecureTextFieldCharacter = "\u2022";
|
||||
@@ -80,15 +77,18 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
BOOL _isEditable;
|
||||
BOOL _isSelectable;
|
||||
BOOL _isSecure;
|
||||
BOOL _willBecomeFirstResponderByClick;
|
||||
|
||||
BOOL _drawsBackground;
|
||||
|
||||
|
||||
CPColor _textFieldBackgroundColor;
|
||||
|
||||
|
||||
id _placeholderString;
|
||||
|
||||
id _originalPlaceholderString;
|
||||
BOOL _currentValueIsPlaceholder;
|
||||
|
||||
id _delegate;
|
||||
|
||||
|
||||
CPString _textDidChangeValue;
|
||||
|
||||
// NS-style Display Properties
|
||||
@@ -155,7 +155,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
return textField;
|
||||
}
|
||||
|
||||
+ (CPString)themeClass
|
||||
+ (CPString)defaultThemeClass
|
||||
{
|
||||
return "textfield";
|
||||
}
|
||||
@@ -199,7 +199,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
}
|
||||
|
||||
CPTextFieldHandleBlur = function(anEvent)
|
||||
{
|
||||
{
|
||||
CPTextFieldInputOwner = nil;
|
||||
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
@@ -207,10 +207,10 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
//FIXME make this not onblur
|
||||
CPTextFieldDOMInputElement.onblur = CPTextFieldBlurFunction;
|
||||
|
||||
|
||||
CPTextFieldDOMStandardInputElement = CPTextFieldDOMInputElement;
|
||||
}
|
||||
|
||||
|
||||
if (CPFeatureIsCompatible(CPInputTypeCanBeChangedFeature))
|
||||
{
|
||||
if ([self isSecure])
|
||||
@@ -237,14 +237,14 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
CPTextFieldDOMPasswordInputElement.onblur = CPTextFieldBlurFunction;
|
||||
}
|
||||
|
||||
|
||||
CPTextFieldDOMInputElement = CPTextFieldDOMPasswordInputElement;
|
||||
}
|
||||
else
|
||||
{
|
||||
CPTextFieldDOMInputElement = CPTextFieldDOMStandardInputElement;
|
||||
}
|
||||
|
||||
|
||||
return CPTextFieldDOMInputElement;
|
||||
}
|
||||
#endif
|
||||
@@ -262,18 +262,29 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
[self setValue:CPLeftTextAlignment forThemeAttribute:@"alignment"];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark Controlling Editability and Selectability
|
||||
|
||||
/*!
|
||||
Sets whether or not the receiver text field can be edited
|
||||
/*!
|
||||
Sets whether or not the receiver text field can be edited. If NO, any
|
||||
ongoing edit is ended.
|
||||
*/
|
||||
- (void)setEditable:(BOOL)shouldBeEditable
|
||||
{
|
||||
if (_isEditable === shouldBeEditable)
|
||||
return;
|
||||
|
||||
_isEditable = shouldBeEditable;
|
||||
|
||||
if (shouldBeEditable)
|
||||
_isSelectable = YES;
|
||||
|
||||
// We only allow first responder status if the field is editable and enabled.
|
||||
if (!shouldBeEditable && [[self window] firstResponder] === self)
|
||||
[[self window] makeFirstResponder:nil];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -284,6 +295,19 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
return _isEditable;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets whether the field reacts to events. If NO, any ongoing edit is
|
||||
ended.
|
||||
*/
|
||||
- (void)setEnabled:(BOOL)shouldBeEnabled
|
||||
{
|
||||
[super setEnabled:shouldBeEnabled];
|
||||
|
||||
// We only allow first responder status if the field is editable and enabled.
|
||||
if (!shouldBeEnabled && [[self window] firstResponder] === self)
|
||||
[[self window] makeFirstResponder:nil];
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets whether the field's text is selectable by the user.
|
||||
@param aFlag \c YES makes the text selectable
|
||||
@@ -346,7 +370,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
- (void)setBezelStyle:(CPTextFieldBezelStyle)aBezelStyle
|
||||
{
|
||||
var shouldBeRounded = aBezelStyle === CPTextFieldRoundedBezel;
|
||||
|
||||
|
||||
if (shouldBeRounded)
|
||||
[self setThemeState:CPTextFieldStateRounded];
|
||||
else
|
||||
@@ -392,9 +416,9 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
{
|
||||
if (_drawsBackground == shouldDrawBackground)
|
||||
return;
|
||||
|
||||
|
||||
_drawsBackground = shouldDrawBackground;
|
||||
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
@@ -415,9 +439,9 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
{
|
||||
if (_textFieldBackgroundColor == aColor)
|
||||
return;
|
||||
|
||||
|
||||
_textFieldBackgroundColor = aColor;
|
||||
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
@@ -480,24 +504,31 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
_DOMElement.appendChild(element);
|
||||
|
||||
window.setTimeout(function()
|
||||
{
|
||||
window.setTimeout(function()
|
||||
{
|
||||
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]];
|
||||
CPTextFieldInputOwner = self;
|
||||
}, 0.0);
|
||||
|
||||
|
||||
element.value = [self stringValue];
|
||||
|
||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
|
||||
|
||||
CPTextFieldInputIsActive = YES;
|
||||
|
||||
if (document.attachEvent)
|
||||
{
|
||||
CPTextFieldCachedSelectStartFunction = [[self window] platformWindow]._DOMBodyElement.onselectstart;
|
||||
CPTextFieldCachedDragFunction = [[self window] platformWindow]._DOMBodyElement.ondrag;
|
||||
|
||||
|
||||
[[self window] platformWindow]._DOMBodyElement.ondrag = function () {};
|
||||
[[self window] platformWindow]._DOMBodyElement.onselectstart = function () {};
|
||||
}
|
||||
@@ -519,14 +550,15 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
var element = [self _inputElement];
|
||||
|
||||
[self setObjectValue:element.value];
|
||||
if ([self stringValue] !== element.value)
|
||||
[self _setStringValue:element.value];
|
||||
|
||||
CPTextFieldInputResigning = YES;
|
||||
element.blur();
|
||||
|
||||
|
||||
if (!CPTextFieldInputDidBlur)
|
||||
CPTextFieldBlurFunction();
|
||||
|
||||
|
||||
CPTextFieldInputDidBlur = NO;
|
||||
CPTextFieldInputResigning = NO;
|
||||
|
||||
@@ -537,13 +569,13 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
if (document.attachEvent)
|
||||
{
|
||||
CPTextFieldCachedSelectStartFunction = nil;
|
||||
CPTextFieldCachedDragFunction = nil;
|
||||
|
||||
[[self window] platformWindow]._DOMBodyElement.ondrag = CPTextFieldCachedDragFunction;
|
||||
[[self window] platformWindow]._DOMBodyElement.onselectstart = CPTextFieldCachedSelectStartFunction;
|
||||
|
||||
CPTextFieldCachedSelectStartFunction = nil;
|
||||
CPTextFieldCachedDragFunction = nil;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
//post CPControlTextDidEndEditingNotification
|
||||
@@ -573,21 +605,50 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
{
|
||||
// Don't track! (ever?)
|
||||
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
|
||||
return [[self nextResponder] mouseDown:anEvent];
|
||||
}
|
||||
|
||||
- (void)mouseUp:(CPEvent)anEvent
|
||||
{
|
||||
if (![self isEditable] || ![self isEnabled])
|
||||
if (![self isSelectable] && (![self isEditable] || ![self isEnabled]))
|
||||
[[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
|
||||
{
|
||||
if (![self isEditable] || ![self isEnabled])
|
||||
if (![self isSelectable] && (![self isEditable] || ![self isEnabled]))
|
||||
[[self nextResponder] mouseDragged:anEvent];
|
||||
else if ([self isSelectable])
|
||||
return [[[anEvent window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
}
|
||||
|
||||
- (void)keyUp:(CPEvent)anEvent
|
||||
@@ -624,29 +685,16 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
[[[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
|
||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
}
|
||||
|
||||
|
||||
- (void)textDidBlur:(CPNotification)note
|
||||
{
|
||||
//this looks to prevent false propagation of notifications for other objects
|
||||
if([note object] != self)
|
||||
// this looks to prevent false propagation of notifications for other objects
|
||||
if ([note object] != self)
|
||||
return;
|
||||
|
||||
[[CPNotificationCenter defaultCenter] postNotification:note];
|
||||
@@ -654,13 +702,22 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
- (void)textDidFocus:(CPNotification)note
|
||||
{
|
||||
//this looks to prevent false propagation of notifications for other objects
|
||||
if([note object] != self)
|
||||
// this looks to prevent false propagation of notifications for other objects
|
||||
if ([note object] != self)
|
||||
return;
|
||||
|
||||
[[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.
|
||||
*/
|
||||
@@ -683,7 +740,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
- (void)setObjectValue:(id)aValue
|
||||
{
|
||||
[super setObjectValue:aValue];
|
||||
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
if (CPTextFieldInputOwner === self || [[self window] firstResponder] === self)
|
||||
@@ -707,11 +764,11 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
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
|
||||
*/
|
||||
-(void)setPlaceholderString:(CPString)aStringValue
|
||||
- (void)setPlaceholderString:(CPString)aStringValue
|
||||
{
|
||||
if (_placeholderString === aStringValue)
|
||||
return;
|
||||
|
||||
|
||||
_placeholderString = aStringValue;
|
||||
|
||||
// Only update things if we need to show the placeholder
|
||||
@@ -730,43 +787,101 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
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;
|
||||
}
|
||||
|
||||
/*!
|
||||
Size to fit has two behavior, depending on if the receiver is an editable text field or not.
|
||||
|
||||
For non-editable text fields (typically, a label), sizeToFit will change the frame of the
|
||||
receiver to perfectly fit the current text in stringValue in the current font, and respecting
|
||||
the current theme values for content-inset, min-size, and max-size.
|
||||
|
||||
For editable text fields, sizeToFit will ONLY change the HEIGHT of the text field. It will not
|
||||
change the width of the text field. You can use setFrameSize: with the current height to set the
|
||||
width, and you can get the size of a string with [CPString sizeWithFont:].
|
||||
|
||||
For non-bezeled text fields (typically a label), sizeToFit has two behaviors, depending
|
||||
on the line break mode of the receiver.
|
||||
|
||||
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, respecting
|
||||
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),
|
||||
so it will ONLY change the HEIGHT.
|
||||
|
||||
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
|
||||
in an editable text field, so you want to just choose a fixed width and leave it at that size.
|
||||
in a bezeled text field, so you want to just choose a fixed width and leave it at that size.
|
||||
However, since you don't know how tall it needs to be if you change the font, sizeToFit will still be
|
||||
useful for making the textfield an appropriate height.
|
||||
*/
|
||||
|
||||
- (void)sizeToFit
|
||||
{
|
||||
var size = [([self stringValue] || " ") sizeWithFont:[self currentValueForThemeAttribute:@"font"]],
|
||||
[self setFrameSize:[self _minimumFrameSize]];
|
||||
}
|
||||
|
||||
- (CGSize)_minimumFrameSize
|
||||
{
|
||||
var frameSize = [self frameSize],
|
||||
contentInset = [self currentValueForThemeAttribute:@"content-inset"],
|
||||
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"];
|
||||
|
||||
size.width = MAX(size.width + contentInset.left + contentInset.right, minSize.width);
|
||||
size.height = MAX(size.height + contentInset.top + contentInset.bottom, minSize.height);
|
||||
textSize.width -= contentInset.left + contentInset.right;
|
||||
textSize.height -= contentInset.top + contentInset.bottom;
|
||||
|
||||
if (maxSize.width >= 0.0)
|
||||
size.width = MIN(size.width, maxSize.width);
|
||||
if (frameSize.width !== 0 &&
|
||||
![self isBezeled] &&
|
||||
(lineBreakMode === CPLineBreakByWordWrapping || lineBreakMode === CPLineBreakByCharWrapping))
|
||||
{
|
||||
textSize = [text sizeWithFont:font inWidth:textSize.width];
|
||||
}
|
||||
else
|
||||
textSize = [text sizeWithFont:font];
|
||||
|
||||
if (maxSize.height >= 0.0)
|
||||
size.height = MIN(size.height, maxSize.height);
|
||||
frameSize.height = textSize.height + contentInset.top + contentInset.bottom;
|
||||
|
||||
if ([self isEditable])
|
||||
size.width = CGRectGetWidth([self frame]);
|
||||
if ([self isBezeled])
|
||||
{
|
||||
frameSize.height = MAX(frameSize.height, minSize.height);
|
||||
|
||||
[self setFrameSize:size];
|
||||
if (maxSize.width > 0.0)
|
||||
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;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -776,16 +891,13 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
var element = [self _inputElement];
|
||||
|
||||
|
||||
if (([self isEditable] || [self isSelectable]))
|
||||
{
|
||||
if ([[self window] firstResponder] === self)
|
||||
window.setTimeout(function() { element.select(); }, 0);
|
||||
else
|
||||
{
|
||||
[[self window] makeFirstResponder:self];
|
||||
else if ([self window] !== nil && [[self window] makeFirstResponder:self])
|
||||
window.setTimeout(function() {[self selectText:sender];}, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -834,7 +946,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:pasteString];
|
||||
|
||||
[self setStringValue:newValue];
|
||||
[self setSelectedRange:CPMakeRange(selectedRange.location+pasteString.length, 0)];
|
||||
[self setSelectedRange:CPMakeRange(selectedRange.location + pasteString.length, 0)];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -844,14 +956,14 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
return CPMakeRange(0, 0);
|
||||
|
||||
// we wrap this in try catch because firefox will throw an exception in certain instances
|
||||
try
|
||||
try
|
||||
{
|
||||
var inputElement = [self _inputElement],
|
||||
selectionStart = inputElement.selectionStart,
|
||||
selectionEnd = inputElement.selectionEnd;
|
||||
|
||||
if ([selectionStart isKindOfClass:CPNumber])
|
||||
return CPMakeRange(selectionStart, selectionEnd - selectionStart);
|
||||
return CPMakeRange(selectionStart, selectionEnd - selectionStart);
|
||||
|
||||
// browsers which don't support selectionStart/selectionEnd (aka IE).
|
||||
var theDocument = inputElement.ownerDocument || inputElement.document,
|
||||
@@ -863,8 +975,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
range.setEndPoint('EndToStart', selectionRange);
|
||||
return CPMakeRange(range.text.length, selectionRange.text.length);
|
||||
}
|
||||
}
|
||||
catch (e)
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
// fall through to the return
|
||||
}
|
||||
@@ -879,7 +991,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
var inputElement = [self _inputElement];
|
||||
|
||||
try
|
||||
try
|
||||
{
|
||||
if ([inputElement.selectionStart isKindOfClass:CPNumber])
|
||||
{
|
||||
@@ -892,7 +1004,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
var theDocument = inputElement.ownerDocument || inputElement.document,
|
||||
existingRange = theDocument.selection.createRange(),
|
||||
range = inputElement.createTextRange();
|
||||
|
||||
|
||||
if (range.inRange(existingRange))
|
||||
{
|
||||
range.collapse(true);
|
||||
@@ -927,7 +1039,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
- (void)setDelegate:(id)aDelegate
|
||||
{
|
||||
var defaultCenter = [CPNotificationCenter defaultCenter];
|
||||
|
||||
|
||||
//unsubscribe the existing delegate if it exists
|
||||
if (_delegate)
|
||||
{
|
||||
@@ -937,24 +1049,24 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
[defaultCenter removeObserver:_delegate name:CPTextFieldDidFocusNotification object:self];
|
||||
[defaultCenter removeObserver:_delegate name:CPTextFieldDidBlurNotification object:self];
|
||||
}
|
||||
|
||||
|
||||
_delegate = aDelegate;
|
||||
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(controlTextDidBeginEditing:)])
|
||||
[defaultCenter
|
||||
addObserver:_delegate
|
||||
selector:@selector(controlTextDidBeginEditing:)
|
||||
name:CPControlTextDidBeginEditingNotification
|
||||
object:self];
|
||||
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(controlTextDidChange:)])
|
||||
[defaultCenter
|
||||
addObserver:_delegate
|
||||
selector:@selector(controlTextDidChange:)
|
||||
name:CPControlTextDidChangeNotification
|
||||
object:self];
|
||||
|
||||
|
||||
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(controlTextDidEndEditing:)])
|
||||
[defaultCenter
|
||||
addObserver:_delegate
|
||||
@@ -985,30 +1097,30 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
- (CGRect)contentRectForBounds:(CGRect)bounds
|
||||
{
|
||||
var contentInset = [self currentValueForThemeAttribute:@"content-inset"];
|
||||
|
||||
|
||||
if (!contentInset)
|
||||
return bounds;
|
||||
|
||||
|
||||
bounds.origin.x += contentInset.left;
|
||||
bounds.origin.y += contentInset.top;
|
||||
bounds.size.width -= contentInset.left + contentInset.right;
|
||||
bounds.size.height -= contentInset.top + contentInset.bottom;
|
||||
|
||||
|
||||
return bounds;
|
||||
}
|
||||
|
||||
- (CGRect)bezelRectForBounds:(CFRect)bounds
|
||||
- (CGRect)bezelRectForBounds:(CGRect)bounds
|
||||
{
|
||||
var bezelInset = [self currentValueForThemeAttribute:@"bezel-inset"];
|
||||
|
||||
if (_CGInsetIsEmpty(bezelInset))
|
||||
return bounds;
|
||||
|
||||
|
||||
bounds.origin.x += bezelInset.left;
|
||||
bounds.origin.y += bezelInset.top;
|
||||
bounds.size.width -= bezelInset.left + bezelInset.right;
|
||||
bounds.size.height -= bezelInset.top + bezelInset.bottom;
|
||||
|
||||
|
||||
return bounds;
|
||||
}
|
||||
|
||||
@@ -1016,10 +1128,10 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
{
|
||||
if (aName === "bezel-view")
|
||||
return [self bezelRectForBounds:[self bounds]];
|
||||
|
||||
|
||||
else if (aName === "content-view")
|
||||
return [self contentRectForBounds:[self bounds]];
|
||||
|
||||
|
||||
return [super rectForEphemeralSubviewNamed:aName];
|
||||
}
|
||||
|
||||
@@ -1030,19 +1142,19 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
|
||||
[view setHitTests:NO];
|
||||
|
||||
|
||||
return view;
|
||||
}
|
||||
else
|
||||
{
|
||||
var view = [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
//[view setImagePosition:CPNoImage];
|
||||
|
||||
|
||||
[view setHitTests:NO];
|
||||
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
|
||||
return [super createEphemeralSubviewNamed:aName];
|
||||
}
|
||||
|
||||
@@ -1051,10 +1163,10 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
var bezelView = [self layoutEphemeralSubviewNamed:@"bezel-view"
|
||||
positioned:CPWindowBelow
|
||||
relativeToEphemeralSubviewNamed:@"content-view"];
|
||||
|
||||
|
||||
if (bezelView)
|
||||
[bezelView setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
|
||||
|
||||
|
||||
var contentView = [self layoutEphemeralSubviewNamed:@"content-view"
|
||||
positioned:CPWindowAbove
|
||||
relativeToEphemeralSubviewNamed:@"bezel-view"];
|
||||
@@ -1064,7 +1176,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
[contentView setHidden:[self hasThemeState:CPThemeStateEditing]];
|
||||
|
||||
var string = "";
|
||||
|
||||
|
||||
if ([self hasThemeState:CPTextFieldStatePlaceholder])
|
||||
string = [self placeholderString];
|
||||
else
|
||||
@@ -1087,6 +1199,22 @@ 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
|
||||
|
||||
var secureStringForString = function(aString)
|
||||
@@ -1095,7 +1223,7 @@ var secureStringForString = function(aString)
|
||||
if (!aString)
|
||||
return "";
|
||||
|
||||
return Array(aString.length+1).join(CPSecureTextFieldCharacter);
|
||||
return Array(aString.length + 1).join(CPSecureTextFieldCharacter);
|
||||
}
|
||||
|
||||
|
||||
@@ -1106,6 +1234,7 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
|
||||
CPTextFieldBezelStyleKey = "CPTextFieldBezelStyleKey",
|
||||
CPTextFieldDrawsBackgroundKey = "CPTextFieldDrawsBackgroundKey",
|
||||
CPTextFieldLineBreakModeKey = "CPTextFieldLineBreakModeKey",
|
||||
CPTextFieldAlignmentKey = "CPTextFieldAlignmentKey",
|
||||
CPTextFieldBackgroundColorKey = "CPTextFieldBackgroundColorKey",
|
||||
CPTextFieldPlaceholderStringKey = "CPTextFieldPlaceholderStringKey";
|
||||
|
||||
@@ -1119,7 +1248,7 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
[self setEditable:[aCoder decodeBoolForKey:CPTextFieldIsEditableKey]];
|
||||
@@ -1129,9 +1258,24 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
|
||||
|
||||
[self setTextFieldBackgroundColor:[aCoder decodeObjectForKey:CPTextFieldBackgroundColorKey]];
|
||||
|
||||
[self setLineBreakMode:[aCoder decodeIntForKey:CPTextFieldLineBreakModeKey]];
|
||||
[self setAlignment:[aCoder decodeIntForKey:CPTextFieldAlignmentKey]];
|
||||
|
||||
[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;
|
||||
}
|
||||
|
||||
@@ -1142,14 +1286,17 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
|
||||
[aCoder encodeBool:_isEditable forKey:CPTextFieldIsEditableKey];
|
||||
[aCoder encodeBool:_isSelectable forKey:CPTextFieldIsSelectableKey];
|
||||
|
||||
|
||||
[aCoder encodeBool:_drawsBackground forKey:CPTextFieldDrawsBackgroundKey];
|
||||
|
||||
|
||||
[aCoder encodeObject:_textFieldBackgroundColor forKey:CPTextFieldBackgroundColorKey];
|
||||
|
||||
|
||||
[aCoder encodeInt:[self lineBreakMode] forKey:CPTextFieldLineBreakModeKey];
|
||||
[aCoder encodeInt:[self alignment] forKey:CPTextFieldAlignmentKey];
|
||||
|
||||
[aCoder encodeObject:_placeholderString forKey:CPTextFieldPlaceholderStringKey];
|
||||
}
|
||||
|
||||
|
||||
+188
-20
@@ -24,8 +24,10 @@
|
||||
@import <Foundation/CPString.j>
|
||||
@import <Foundation/CPKeyedUnarchiver.j>
|
||||
|
||||
var CPThemesByName = { },
|
||||
CPThemeDefaultTheme = nil;
|
||||
|
||||
var CPThemesByName = { },
|
||||
CPThemeDefaultTheme = nil,
|
||||
CPThemeDefaultHudTheme = nil;
|
||||
|
||||
|
||||
/*!
|
||||
@@ -48,6 +50,27 @@ var CPThemesByName = { },
|
||||
return CPThemeDefaultTheme;
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the default HUD theme. If set to nil, the default described in defaultHudTheme
|
||||
will be used.
|
||||
*/
|
||||
+ (void)setDefaultHudTheme:(CPTheme)aTheme
|
||||
{
|
||||
CPThemeDefaultHudTheme = aTheme;
|
||||
}
|
||||
|
||||
/*!
|
||||
The default HUD theme is (sometimes) used for windows with the CPHUDBackgroundWindowMask
|
||||
style mask. The default is theme with the name of the default theme with -HUD appended
|
||||
at the end.
|
||||
*/
|
||||
+ (CPTheme)defaultHudTheme
|
||||
{
|
||||
if (!CPThemeDefaultHudTheme)
|
||||
CPThemeDefaultHudTheme = [CPTheme themeNamed:[[self defaultTheme] name] + "-HUD"];
|
||||
return CPThemeDefaultHudTheme;
|
||||
}
|
||||
|
||||
+ (CPTheme)themeNamed:(CPString)aName
|
||||
{
|
||||
return CPThemesByName[aName];
|
||||
@@ -73,9 +96,110 @@ var CPThemesByName = { },
|
||||
return _name;
|
||||
}
|
||||
|
||||
- (_CPThemeAttribute)_attributeWithName:(CPString)aName forClass:(CPString)aClass
|
||||
/*!
|
||||
Returns an array of names of themed classes defined in this theme, as found in its
|
||||
ThemeDescriptors.j file.
|
||||
|
||||
NOTE: The names are not class names (such as "CPButton"), but the names returned
|
||||
by the class' +defaultThemeClass method. For example, the name for CPCheckBox is "check-box",
|
||||
as defined in CPCheckBox::themeClass.
|
||||
*/
|
||||
- (CPArray)classNames
|
||||
{
|
||||
var attributes = [_attributes objectForKey:aClass];
|
||||
return [_attributes allKeys];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a dictionary of all theme attributes defined for the given class, as found in the
|
||||
theme's ThemeDescriptors.j file. The keys of the dictionary are attribute names, and the values
|
||||
are instances of _CPThemeAttribute.
|
||||
|
||||
For a description of valid values for \c aClass, see \ref attributeNamesForClass:.
|
||||
|
||||
@param aClass The themed class whose attributes you want to retrieve
|
||||
@return A dictionary of attributes or nil
|
||||
*/
|
||||
- (CPDictionary)attributesForClass:(id)aClass
|
||||
{
|
||||
if (!aClass)
|
||||
return nil;
|
||||
|
||||
var className = nil;
|
||||
|
||||
if ([aClass isKindOfClass:[CPString class]])
|
||||
{
|
||||
// See if it is a class name
|
||||
var theClass = CPClassFromString(aClass);
|
||||
|
||||
if (theClass)
|
||||
aClass = theClass;
|
||||
else
|
||||
className = aClass;
|
||||
}
|
||||
|
||||
if (!className)
|
||||
{
|
||||
if ([aClass isKindOfClass:[CPView class]])
|
||||
{
|
||||
if ([aClass respondsToSelector:@selector(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)
|
||||
return nil;
|
||||
@@ -83,12 +207,53 @@ var CPThemesByName = { },
|
||||
return [attributes objectForKey:aName];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the value for a theme attribute in its normal state, as defined for the given class
|
||||
in the theme's ThemeDescriptors.j file.
|
||||
|
||||
\c aName should be the attribute name as you would pass to the method
|
||||
CPView::valueForThemeAttribute:.
|
||||
|
||||
For a description of valid values for \c aClass, see \ref attributeNamesForClass:.
|
||||
|
||||
@param aName The name of the attribute whose value you want to retrieve
|
||||
@param aClass The themed class in which to look for the attribute
|
||||
@return A value or nil
|
||||
*/
|
||||
- (id)valueForAttributeWithName:(CPString)aName forClass:(id)aClass
|
||||
{
|
||||
return [self valueForAttributeWithName:aName inState:CPThemeStateNormal forClass:aClass];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the value for a theme attribute in a given state, as defined for the given class
|
||||
in the theme's ThemeDescriptors.j file. This is the equivalent of the method
|
||||
CPView::valueForThemeAttribute:inState:, but retrieves the value from the theme definition as
|
||||
opposed to a single view's current theme state.
|
||||
|
||||
For a description of valid values for \c aClass, see \ref attributeNamesForClass:.
|
||||
|
||||
@param aName The name of the attribute whose value you want to retrieve
|
||||
@param aState The state qualifier for the attribute
|
||||
@param aClass The themed class in which to look for the attribute
|
||||
@return A value or nil
|
||||
*/
|
||||
- (id)valueForAttributeWithName:(CPString)aName inState:(CPThemeState)aState forClass:(id)aClass
|
||||
{
|
||||
var attribute = [self attributeWithName:aName forClass:aClass];
|
||||
|
||||
if (!attribute)
|
||||
return nil;
|
||||
|
||||
return [attribute valueForState:aState];
|
||||
}
|
||||
|
||||
- (void)takeThemeFromObject:(id)anObject
|
||||
{
|
||||
var attributes = [anObject _themeAttributeDictionary],
|
||||
attributeName = nil,
|
||||
attributeNames = [attributes keyEnumerator],
|
||||
objectThemeClass = [[anObject class] themeClass];
|
||||
objectThemeClass = [anObject themeClass];
|
||||
|
||||
while (attributeName = [attributeNames nextObject])
|
||||
[self _recordAttribute:[attributes objectForKey:attributeName] forClass:objectThemeClass];
|
||||
@@ -242,6 +407,9 @@ CPThemeStateNormal = CPThemeStates["normal"] = 0;
|
||||
CPThemeStateDisabled = CPThemeState("disabled");
|
||||
CPThemeStateHighlighted = CPThemeState("highlighted");
|
||||
CPThemeStateSelected = CPThemeState("selected");
|
||||
CPThemeStateTableDataView = CPThemeState("tableDataView");
|
||||
CPThemeStateSelectedDataView = CPThemeStateSelectedTableDataView = CPThemeState("selectedTableDataView");
|
||||
CPThemeStateGroupRow = CPThemeState("CPThemeStateGroupRow");
|
||||
CPThemeStateBezeled = CPThemeState("bezeled");
|
||||
CPThemeStateBordered = CPThemeState("bordered");
|
||||
CPThemeStateEditable = CPThemeState("editable");
|
||||
@@ -254,10 +422,10 @@ CPThemeStateCircular = CPThemeState("circular");
|
||||
{
|
||||
CPString _name;
|
||||
id _defaultValue;
|
||||
CPDictionary _values;
|
||||
CPDictionary _values @accessors(readonly, getter=values);
|
||||
|
||||
JSObject _cache;
|
||||
CPThemeAttribute _parentAttribute;
|
||||
_CPThemeAttribute _parentAttribute;
|
||||
}
|
||||
|
||||
- (id)initWithName:(CPString)aName defaultValue:(id)aDefaultValue
|
||||
@@ -378,7 +546,7 @@ CPThemeStateCircular = CPThemeState("circular");
|
||||
return value;
|
||||
}
|
||||
|
||||
- (void)setParentAttribute:(CPThemeAttribute)anAttribute
|
||||
- (void)setParentAttribute:(_CPThemeAttribute)anAttribute
|
||||
{
|
||||
if (_parentAttribute === anAttribute)
|
||||
return;
|
||||
@@ -387,7 +555,7 @@ CPThemeStateCircular = CPThemeState("circular");
|
||||
_parentAttribute = anAttribute;
|
||||
}
|
||||
|
||||
- (CPThemeAttribute)attributeMergedWithAttribute:(_CPThemeAttribute)anAttribute
|
||||
- (_CPThemeAttribute)attributeMergedWithAttribute:(_CPThemeAttribute)anAttribute
|
||||
{
|
||||
var mergedAttribute = [[_CPThemeAttribute alloc] initWithName:_name defaultValue:_defaultValue];
|
||||
|
||||
@@ -472,15 +640,15 @@ CPThemeStateCircular = CPThemeState("circular");
|
||||
|
||||
@end
|
||||
|
||||
var cachedNumberOfOnes = [ 0 /*000000*/, 1 /*000001*/, 1 /*000010*/, 2 /*000011*/, 1 /*000100*/, 2 /*000101*/, 2 /*000110*/,
|
||||
3 /*000111*/, 1 /*001000*/, 2 /*001001*/, 2 /*001010*/, 3 /*001011*/, 2 /*001100*/, 3 /*001101*/,
|
||||
3 /*001110*/, 4 /*001111*/, 1 /*010000*/, 2 /*010001*/, 2 /*010010*/, 3 /*010011*/, 2 /*010100*/,
|
||||
3 /*010101*/, 3 /*010110*/, 4 /*010111*/, 2 /*011000*/, 3 /*011001*/, 3 /*011010*/, 4 /*011011*/,
|
||||
3 /*011100*/, 4 /*011101*/, 4 /*011110*/, 5 /*011111*/, 1 /*100000*/, 2 /*100001*/, 2 /*100010*/,
|
||||
3 /*100011*/, 2 /*100100*/, 3 /*100101*/, 3 /*100110*/, 4 /*100111*/, 2 /*101000*/, 3 /*101001*/,
|
||||
3 /*101010*/, 4 /*101011*/, 3 /*101100*/, 4 /*101101*/, 4 /*101110*/, 5 /*101111*/, 2 /*110000*/,
|
||||
3 /*110001*/, 3 /*110010*/, 4 /*110011*/, 3 /*110100*/, 4 /*110101*/, 4 /*110110*/, 5 /*110111*/,
|
||||
3 /*111000*/, 4 /*111001*/, 4 /*111010*/, 5 /*111011*/, 4 /*111100*/, 5 /*111101*/, 5 /*111110*/,
|
||||
var cachedNumberOfOnes = [ 0 /*000000*/, 1 /*000001*/, 1 /*000010*/, 2 /*000011*/, 1 /*000100*/, 2 /*000101*/, 2 /*000110*/,
|
||||
3 /*000111*/, 1 /*001000*/, 2 /*001001*/, 2 /*001010*/, 3 /*001011*/, 2 /*001100*/, 3 /*001101*/,
|
||||
3 /*001110*/, 4 /*001111*/, 1 /*010000*/, 2 /*010001*/, 2 /*010010*/, 3 /*010011*/, 2 /*010100*/,
|
||||
3 /*010101*/, 3 /*010110*/, 4 /*010111*/, 2 /*011000*/, 3 /*011001*/, 3 /*011010*/, 4 /*011011*/,
|
||||
3 /*011100*/, 4 /*011101*/, 4 /*011110*/, 5 /*011111*/, 1 /*100000*/, 2 /*100001*/, 2 /*100010*/,
|
||||
3 /*100011*/, 2 /*100100*/, 3 /*100101*/, 3 /*100110*/, 4 /*100111*/, 2 /*101000*/, 3 /*101001*/,
|
||||
3 /*101010*/, 4 /*101011*/, 3 /*101100*/, 4 /*101101*/, 4 /*101110*/, 5 /*101111*/, 2 /*110000*/,
|
||||
3 /*110001*/, 3 /*110010*/, 4 /*110011*/, 3 /*110100*/, 4 /*110101*/, 4 /*110110*/, 5 /*110111*/,
|
||||
3 /*111000*/, 4 /*111001*/, 4 /*111010*/, 5 /*111011*/, 4 /*111100*/, 5 /*111101*/, 5 /*111110*/,
|
||||
6 /*111111*/ ];
|
||||
|
||||
var numberOfOnes = function(aNumber)
|
||||
@@ -551,7 +719,7 @@ function CPThemeAttributeDecode(aCoder, anAttributeName, aDefaultValue, aTheme,
|
||||
}
|
||||
|
||||
if (aTheme && aClass)
|
||||
[attribute setParentAttribute:[aTheme _attributeWithName:anAttributeName forClass:aClass]];
|
||||
[attribute setParentAttribute:[aTheme attributeWithName:anAttributeName forClass:aClass]];
|
||||
|
||||
return attribute;
|
||||
}
|
||||
@@ -585,4 +753,4 @@ for (i = 0;i < Math.pow(2,6);++i)
|
||||
}
|
||||
print(str+']');
|
||||
|
||||
*/
|
||||
*/
|
||||
|
||||
+34
-10
@@ -22,9 +22,10 @@
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
@import <AppKit/CPTheme.j>
|
||||
@import <AppKit/_CPCibCustomResource.j>
|
||||
@import <AppKit/_CPCibKeyedUnarchiver.j>
|
||||
@import "CPTheme.j"
|
||||
@import "_CPCibCustomResource.j"
|
||||
@import "_CPCibKeyedUnarchiver.j"
|
||||
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@@ -33,37 +34,60 @@
|
||||
@implementation CPThemeBlend : CPObject
|
||||
{
|
||||
CPBundle _bundle;
|
||||
CPArray _themes @accessors(readonly, getter=themes);
|
||||
CPArray _themes;
|
||||
id _loadDelegate;
|
||||
}
|
||||
|
||||
- (id)initWithContentsOfURL:(CPURL)aURL
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_bundle = [[CPBundle alloc] initWithPath:aURL];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns an array of names of the keyed theme archives that make up this blend.
|
||||
Each item in the array will have the extension ".keyedtheme".
|
||||
*/
|
||||
- (CPArray)themes
|
||||
{
|
||||
return _themes;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns an array of names of the themes that make up this blend.
|
||||
*/
|
||||
- (CPArray)themeNames
|
||||
{
|
||||
var names = [];
|
||||
|
||||
for (var i = 0; i < _themes.length; ++i)
|
||||
names.push(_themes[i].substring(0, _themes[i].indexOf(".keyedtheme")));
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
- (void)loadWithDelegate:(id)aDelegate
|
||||
{
|
||||
_loadDelegate = aDelegate;
|
||||
|
||||
|
||||
[_bundle loadWithDelegate:self];
|
||||
}
|
||||
|
||||
- (void)bundleDidFinishLoading:(CPBundle)aBundle
|
||||
{
|
||||
var themes = [_bundle objectForInfoDictionaryKey:@"CPKeyedThemes"],
|
||||
count = themes.length;
|
||||
_themes = [_bundle objectForInfoDictionaryKey:@"CPKeyedThemes"];
|
||||
|
||||
var count = _themes.length;
|
||||
|
||||
while (count--)
|
||||
{
|
||||
var path = [aBundle pathForResource:themes[count]],
|
||||
var path = [aBundle pathForResource:_themes[count]],
|
||||
unarchiver = [[_CPThemeKeyedUnarchiver alloc]
|
||||
initForReadingWithData:[[CPURL URLWithString:path] staticResourceData]
|
||||
bundle:_bundle];
|
||||
|
||||
Executable
+1250
File diff suppressed because it is too large
Load Diff
+21
-10
@@ -28,8 +28,6 @@
|
||||
@import "CPPopUpButton.j"
|
||||
@import "CPToolbarItem.j"
|
||||
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
|
||||
|
||||
/*
|
||||
@global
|
||||
@@ -329,7 +327,11 @@ var CPToolbarConfigurationsByIdentifier = nil;
|
||||
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],
|
||||
count = [toolbarItems count];
|
||||
@@ -466,7 +468,14 @@ var CPToolbarIdentifierKey = @"CPToolbarIdentifierKey",
|
||||
// specified, it will be read later and the resulting call to -setDelegate:
|
||||
// will cause -_reloadToolbarItems] to run again :-(
|
||||
// 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;
|
||||
@@ -559,6 +568,7 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
||||
|
||||
[_additionalItemsButton setImagePosition:CPImageOnly];
|
||||
[[_additionalItemsButton menu] setShowsStateColumn:NO];
|
||||
[[_additionalItemsButton menu] setAutoenablesItems:NO];
|
||||
|
||||
[_additionalItemsButton setAlternateImage:_CPToolbarViewExtraItemsAlternateImage];
|
||||
}
|
||||
@@ -789,14 +799,13 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
||||
|
||||
hasNonSeparatorItem = YES;
|
||||
|
||||
[_additionalItemsButton addItemWithTitle:[item label]];
|
||||
|
||||
var menuItem = [_additionalItemsButton itemArray][index + 1];
|
||||
var menuItem = [[CPMenuItem alloc] initWithTitle:[item label] action:[item action] keyEquivalent:nil];
|
||||
|
||||
[menuItem setImage:[item image]];
|
||||
|
||||
[menuItem setTarget:[item target]];
|
||||
[menuItem setAction:[item action]];
|
||||
[menuItem setEnabled:[item isEnabled]];
|
||||
|
||||
[_additionalItemsButton addItem:menuItem];
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -970,7 +979,7 @@ var TOP_MARGIN = 5.0,
|
||||
{
|
||||
_imageView = [[CPImageView alloc] initWithFrame:[self bounds]];
|
||||
|
||||
[_imageView setImageScaling:CPScaleNone];
|
||||
[_imageView setImageScaling:CPScaleProportionally];
|
||||
|
||||
[self addSubview:_imageView];
|
||||
}
|
||||
@@ -1051,6 +1060,8 @@ var TOP_MARGIN = 5.0,
|
||||
[_imageView setAlphaValue:0.5];
|
||||
[_labelField setAlphaValue:0.5];
|
||||
}
|
||||
|
||||
[_toolbar tile];
|
||||
}
|
||||
|
||||
- (CPColor)FIXME_labelColor
|
||||
|
||||
@@ -23,8 +23,9 @@
|
||||
@import <Foundation/CPObject.j>
|
||||
@import <Foundation/CPString.j>
|
||||
|
||||
@import <AppKit/CPImage.j>
|
||||
@import <AppKit/CPView.j>
|
||||
@import "CPImage.j"
|
||||
@import "CPView.j"
|
||||
|
||||
|
||||
CPToolbarItemVisibilityPriorityStandard = 0;
|
||||
CPToolbarItemVisibilityPriorityLow = -1000;
|
||||
@@ -449,6 +450,9 @@ CPToolbarItemVisibilityPriorityUser
|
||||
|
||||
- (void)validate
|
||||
{
|
||||
var action = [self action],
|
||||
target = [self target];
|
||||
|
||||
// View items do not do any target-action analysis.
|
||||
if (_view)
|
||||
{
|
||||
@@ -458,13 +462,9 @@ CPToolbarItemVisibilityPriorityUser
|
||||
return;
|
||||
}
|
||||
|
||||
var action = [self action];
|
||||
|
||||
if (!action)
|
||||
return [self setEnabled:NO];
|
||||
|
||||
var target = [self target];
|
||||
|
||||
if (target && ![target respondsToSelector:action])
|
||||
return [self setEnabled:NO];
|
||||
|
||||
|
||||
@@ -87,6 +87,40 @@
|
||||
[_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
|
||||
|
||||
var CPTreeNodeRepresentedObjectKey = @"CPTreeNodeRepresentedObjectKey",
|
||||
@@ -117,3 +151,166 @@ var CPTreeNodeRepresentedObjectKey = @"CPTreeNodeRepresentedObjectKey",
|
||||
}
|
||||
|
||||
@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
|
||||
|
||||
+326
-215
File diff suppressed because it is too large
Load Diff
+13
-12
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* CPFlashView.j
|
||||
* CPViewAnimation.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Klaas Pieter Annema on September 3, 2009.
|
||||
@@ -20,7 +20,8 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <AppKit/CPAnimation.j>
|
||||
@import "CPAnimation.j"
|
||||
|
||||
|
||||
CPViewAnimationTargetKey = @"CPViewAnimationTarget";
|
||||
CPViewAnimationStartFrameKey = @"CPViewAnimationStartFrame";
|
||||
@@ -69,7 +70,7 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut";
|
||||
[super startAnimation];
|
||||
}
|
||||
|
||||
- (void)setCurrentProgress:(NSAnimationProgress)progress
|
||||
- (void)setCurrentProgress:(CPAnimationProgress)progress
|
||||
{
|
||||
[super setCurrentProgress:progress];
|
||||
|
||||
@@ -77,17 +78,17 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut";
|
||||
while (animationIndex--)
|
||||
{
|
||||
var dictionary = [_viewAnimations objectAtIndex:animationIndex],
|
||||
view = [self _targetView:dictionary]
|
||||
startFrame = [self _startFrame:dictionary]
|
||||
endFrame = [self _endFrame:dictionary]
|
||||
differenceFrame = CPRectMakeZero();
|
||||
view = [self _targetView:dictionary],
|
||||
startFrame = [self _startFrame:dictionary],
|
||||
endFrame = [self _endFrame:dictionary],
|
||||
differenceFrame = _CGRectMakeZero();
|
||||
|
||||
differenceFrame.origin.x = endFrame.origin.x - startFrame.origin.x;
|
||||
differenceFrame.origin.y = endFrame.origin.y - startFrame.origin.y;
|
||||
differenceFrame.size.width = endFrame.size.width - startFrame.size.width;
|
||||
differenceFrame.size.height = endFrame.size.height - startFrame.size.height;
|
||||
|
||||
var intermediateFrame = CPRectMakeZero();
|
||||
var intermediateFrame = _CGRectMakeZero();
|
||||
intermediateFrame.origin.x = startFrame.origin.x + differenceFrame.origin.x * progress;
|
||||
intermediateFrame.origin.y = startFrame.origin.y + differenceFrame.origin.y * progress;
|
||||
intermediateFrame.size.width = startFrame.size.width + differenceFrame.size.width * progress;
|
||||
@@ -103,7 +104,7 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut";
|
||||
[view setAlphaValue:1.0 + ( 0.0 - 1.0 ) * progress];
|
||||
|
||||
if (progress === 1.0)
|
||||
[view setHidden:CPRectIsNull(endFrame) || [view alphaValue] === 0.0];
|
||||
[view setHidden:_CGRectIsNull(endFrame) || [view alphaValue] === 0.0];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +125,7 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut";
|
||||
else if (effect === CPViewAnimationFadeOutEffect)
|
||||
[view setAlphaValue:0.0];
|
||||
|
||||
[view setHidden:CPRectIsNull(endFrame) || [view alphaValue] === 0.0];
|
||||
[view setHidden:_CGRectIsNull(endFrame) || [view alphaValue] === 0.0];
|
||||
}
|
||||
|
||||
[super stopAnimation];
|
||||
@@ -139,7 +140,7 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut";
|
||||
return targetView;
|
||||
}
|
||||
|
||||
- (CPRect)_startFrame:(CPDictionary)dictionary
|
||||
- (CGRect)_startFrame:(CPDictionary)dictionary
|
||||
{
|
||||
var startFrame = [dictionary valueForKey:CPViewAnimationStartFrameKey];
|
||||
if (!startFrame)
|
||||
@@ -148,7 +149,7 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut";
|
||||
return startFrame;
|
||||
}
|
||||
|
||||
- (CPRect)_endFrame:(CPDictionary)dictionary
|
||||
- (CGRect)_endFrame:(CPDictionary)dictionary
|
||||
{
|
||||
var endFrame = [dictionary valueForKey:CPViewAnimationEndFrameKey];
|
||||
if (!endFrame)
|
||||
|
||||
+27
-61
@@ -20,7 +20,12 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <AppKit/CPResponder.j>
|
||||
@import <Foundation/CPArray.j>
|
||||
|
||||
@import "CPApplication.j"
|
||||
@import "CPCib.j"
|
||||
@import "CPResponder.j"
|
||||
|
||||
|
||||
var CPViewControllerCachedCibs;
|
||||
|
||||
@@ -47,10 +52,11 @@ var CPViewControllerCachedCibs;
|
||||
*/
|
||||
@implementation CPViewController : CPResponder
|
||||
{
|
||||
CPView _view;
|
||||
CPView _view @accessors(property=view);
|
||||
BOOL _isLoading;
|
||||
|
||||
id _representedObject @accessors(property=representedObject);
|
||||
CPString _title;
|
||||
CPString _title @accessors(property=title);
|
||||
|
||||
CPString _cibName @accessors(property=cibName, readonly);
|
||||
CPBundle _cibBundle @accessors(property=cibBundle, readonly);
|
||||
@@ -78,9 +84,7 @@ var CPViewControllerCachedCibs;
|
||||
|
||||
- (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]];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -99,34 +103,15 @@ var CPViewControllerCachedCibs;
|
||||
{
|
||||
// Don't load the cib until someone actually requests the view. The user may just be intending to use setView:.
|
||||
_cibName = aCibNameOrNil;
|
||||
_cibBundle = aCibBundleOrNil;
|
||||
|
||||
if (!_cibBundle)
|
||||
{
|
||||
var owner = [anExternalNameTable objectForKey:CPCibOwner];
|
||||
|
||||
_cibBundle = owner ? [CPBundle bundleForClass:[owner class]] : [CPBundle mainBundle];
|
||||
}
|
||||
|
||||
_cibBundle = aCibBundleOrNil || [CPBundle mainBundle];
|
||||
_cibExternalNameTable = anExternalNameTable || [CPDictionary dictionaryWithObject:self forKey:CPCibOwner];
|
||||
|
||||
_isLoading = NO;
|
||||
}
|
||||
|
||||
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.
|
||||
You should never call this method directly. The view controller calls this method when the view property is requested but is nil.
|
||||
@@ -134,22 +119,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.
|
||||
The default implementation for programmatic views is to create a plain view. You can invoke super to utilize this view.
|
||||
|
||||
If you use Interface Builder to create your views and initialize the view controllerŃthat is, you initialize the view using the
|
||||
initWithCibName:bundle: methodŃthen you must not override this method. The consequences risk shattering the space-time continuum.
|
||||
If you use Interface Builder to create your views, you initialize the view using the
|
||||
initWithCibName:bundle: method then you must not override this method. The consequences risk shattering the space-time continuum.
|
||||
|
||||
Note: The cib loading system is currently asynchronous.
|
||||
Note: The cib loading system is currently synchronous.
|
||||
*/
|
||||
- (void)loadView
|
||||
{
|
||||
if (_view)
|
||||
return;
|
||||
|
||||
|
||||
// check if a cib is already cached for the current _cibName
|
||||
var cib = [CPViewControllerCachedCibs objectForKey:_cibName];
|
||||
|
||||
// If the cib isn't cached yet : fetch it and cache it
|
||||
if (!cib)
|
||||
{
|
||||
// if the cib isn't cached yet : fetch it and cache it
|
||||
cib = [[CPCib alloc] initWithContentsOfURL:[_cibBundle pathForResource:_cibName + @".cib"]];
|
||||
[CPViewControllerCachedCibs setObject:cib forKey:_cibName];
|
||||
}
|
||||
@@ -166,6 +151,8 @@ var CPViewControllerCachedCibs;
|
||||
{
|
||||
if (!_view)
|
||||
{
|
||||
_isLoading = YES;
|
||||
|
||||
var cibOwner = [_cibExternalNameTable objectForKey:CPCibOwner];
|
||||
|
||||
if ([cibOwner respondsToSelector:@selector(viewControllerWillLoadCib:)])
|
||||
@@ -186,6 +173,7 @@ var CPViewControllerCachedCibs;
|
||||
if ([cibOwner respondsToSelector:@selector(viewControllerDidLoadCib:)])
|
||||
[cibOwner viewControllerDidLoadCib:self];
|
||||
|
||||
_isLoading = NO;
|
||||
[self viewDidLoad];
|
||||
}
|
||||
|
||||
@@ -196,7 +184,7 @@ var CPViewControllerCachedCibs;
|
||||
/*!
|
||||
This method is called after the view controller has loaded its associated views into memory.
|
||||
This method is called regardless of whether the views were stored in a nib file or created programmatically in the loadView method.
|
||||
This method is most commonly used to perform additional initialization steps on views that are loaded from nib files.
|
||||
This method is most commonly used to perform additional initialization steps on views that are loaded from cib files.
|
||||
*/
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
@@ -212,35 +200,13 @@ var CPViewControllerCachedCibs;
|
||||
*/
|
||||
- (void)setView:(CPView)aView
|
||||
{
|
||||
var viewWasLoaded = !_view;
|
||||
|
||||
_view = aView;
|
||||
}
|
||||
|
||||
- (CPNavigationItem)navigationItem
|
||||
{
|
||||
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
|
||||
{
|
||||
// Make sure the viewDidLoad method is called if the view is set directly
|
||||
if (!_isLoading && viewWasLoaded)
|
||||
[self viewDidLoad];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
+100
-56
@@ -20,9 +20,8 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <AppKit/CPView.j>
|
||||
|
||||
#include "Platform/Platform.h"
|
||||
@import "CPView.j"
|
||||
@import "CPScrollView.j"
|
||||
|
||||
|
||||
// FIXME: implement these where possible:
|
||||
@@ -50,30 +49,32 @@ CPWebViewScrollNative = 2;
|
||||
{
|
||||
CPScrollView _scrollView;
|
||||
CPView _frameView;
|
||||
|
||||
|
||||
IFrame _iframe;
|
||||
CPString _mainFrameURL;
|
||||
CPArray _backwardStack;
|
||||
CPArray _forwardStack;
|
||||
|
||||
|
||||
BOOL _ignoreLoadStart;
|
||||
BOOL _ignoreLoadEnd;
|
||||
|
||||
|
||||
id _downloadDelegate;
|
||||
id _frameLoadDelegate;
|
||||
id _policyDelegate;
|
||||
id _resourceLoadDelegate;
|
||||
id _UIDelegate;
|
||||
|
||||
|
||||
CPWebScriptObject _wso;
|
||||
|
||||
|
||||
CPString _url;
|
||||
CPString _html;
|
||||
|
||||
|
||||
Function _loadCallback;
|
||||
|
||||
|
||||
int _scrollMode;
|
||||
CGSize _scrollSize;
|
||||
|
||||
int _loadHTMLStringTimer;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CPRect)frameRect frameName:(CPString)frameName groupName:(CPString)groupName
|
||||
@@ -93,10 +94,10 @@ CPWebViewScrollNative = 2;
|
||||
_backwardStack = [];
|
||||
_forwardStack = [];
|
||||
_scrollMode = CPWebViewScrollNative;
|
||||
|
||||
|
||||
[self _initDOMWithFrame:aFrame];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -104,51 +105,52 @@ CPWebViewScrollNative = 2;
|
||||
{
|
||||
_ignoreLoadStart = YES;
|
||||
_ignoreLoadEnd = YES;
|
||||
|
||||
|
||||
_iframe = document.createElement("iframe");
|
||||
_iframe.name = "iframe_" + Math.floor(Math.random()*10000);
|
||||
_iframe.style.width = "100%";
|
||||
_iframe.style.height = "100%";
|
||||
_iframe.style.borderWidth = "0px";
|
||||
|
||||
_iframe.frameBorder = "0";
|
||||
|
||||
[self setDrawsBackground:YES];
|
||||
|
||||
|
||||
_loadCallback = function() {
|
||||
// HACK: this block handles the case where we don't know about loads initiated by the user clicking a link
|
||||
if (!_ignoreLoadStart)
|
||||
{
|
||||
// post the start load notification
|
||||
[self _startedLoading];
|
||||
|
||||
|
||||
if (_mainFrameURL)
|
||||
[_backwardStack addObject:_mainFrameURL];
|
||||
|
||||
|
||||
// FIXME: this doesn't actually get the right URL for different domains. Not possible due to browser security restrictions.
|
||||
_mainFrameURL = _iframe.src;
|
||||
_mainFrameURL = _iframe.src;
|
||||
|
||||
|
||||
// clear the forward
|
||||
[_forwardStack removeAllObjects];
|
||||
}
|
||||
else
|
||||
_ignoreLoadStart = NO;
|
||||
|
||||
|
||||
if (!_ignoreLoadEnd)
|
||||
{
|
||||
[self _finishedLoading];
|
||||
}
|
||||
else
|
||||
_ignoreLoadEnd = NO;
|
||||
|
||||
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
}
|
||||
|
||||
|
||||
if (_iframe.addEventListener)
|
||||
_iframe.addEventListener("load", _loadCallback, false);
|
||||
else if (_iframe.attachEvent)
|
||||
_iframe.attachEvent("onload", _loadCallback);
|
||||
|
||||
|
||||
|
||||
|
||||
_frameView = [[CPView alloc] initWithFrame:[self bounds]];
|
||||
[_frameView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
|
||||
|
||||
@@ -156,9 +158,9 @@ CPWebViewScrollNative = 2;
|
||||
[_scrollView setAutohidesScrollers:YES];
|
||||
[_scrollView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
|
||||
[_scrollView setDocumentView:_frameView];
|
||||
|
||||
|
||||
_frameView._DOMElement.appendChild(_iframe);
|
||||
|
||||
|
||||
[self _setScrollMode:_scrollMode];
|
||||
|
||||
[self addSubview:_scrollView];
|
||||
@@ -166,12 +168,37 @@ CPWebViewScrollNative = 2;
|
||||
|
||||
|
||||
- (void)setFrameSize:(CPSize)aSize
|
||||
{
|
||||
{
|
||||
[super setFrameSize:aSize];
|
||||
[self _resizeWebFrame];
|
||||
}
|
||||
|
||||
- (BOOL)_resizeWebFrame
|
||||
- (void)_attachScrollEventIfNecessary
|
||||
{
|
||||
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)
|
||||
{
|
||||
@@ -181,13 +208,14 @@ CPWebViewScrollNative = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
[_frameView setFrameSize:[_scrollView contentSize]];
|
||||
|
||||
var visibleRect = [_frameView visibleRect];
|
||||
[_frameView setFrameSize:CGSizeMake(CGRectGetMaxX(visibleRect), CGRectGetMaxY(visibleRect))];
|
||||
|
||||
// try to get the document size so we can correctly set the frame
|
||||
var win = null;
|
||||
try { win = [self DOMWindow]; } catch (e) {}
|
||||
|
||||
if (win && win.document)
|
||||
if (win && win.document && win.document.body)
|
||||
{
|
||||
var width = win.document.body.scrollWidth,
|
||||
height = win.document.body.scrollHeight;
|
||||
@@ -200,9 +228,11 @@ CPWebViewScrollNative = 2;
|
||||
else
|
||||
{
|
||||
CPLog.warn("using default size 800*1600");
|
||||
|
||||
|
||||
[_frameView setFrameSize:CGSizeMake(800, 1600)];
|
||||
}
|
||||
|
||||
[_frameView scrollRectToVisible:visibleRect];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -211,14 +241,17 @@ CPWebViewScrollNative = 2;
|
||||
{
|
||||
if (_scrollMode == aScrollMode)
|
||||
return;
|
||||
|
||||
|
||||
[self _setScrollMode:aScrollMode];
|
||||
}
|
||||
|
||||
- (void)_setScrollMode:(int)aScrollMode
|
||||
{
|
||||
_scrollMode = aScrollMode;
|
||||
|
||||
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
|
||||
_scrollMode = CPWebViewScrollNative;
|
||||
else
|
||||
_scrollMode = aScrollMode;
|
||||
|
||||
_ignoreLoadStart = YES;
|
||||
_ignoreLoadEnd = YES;
|
||||
|
||||
@@ -229,16 +262,16 @@ CPWebViewScrollNative = 2;
|
||||
{
|
||||
[_scrollView setHasHorizontalScroller:YES];
|
||||
[_scrollView setHasVerticalScroller:YES];
|
||||
|
||||
|
||||
_iframe.setAttribute("scrolling", "no");
|
||||
}
|
||||
else
|
||||
{
|
||||
[_scrollView setHasHorizontalScroller:NO];
|
||||
[_scrollView setHasVerticalScroller:NO];
|
||||
|
||||
|
||||
_iframe.setAttribute("scrolling", "auto");
|
||||
|
||||
|
||||
[_frameView setFrameSize:[_scrollView bounds].size];
|
||||
}
|
||||
|
||||
@@ -256,14 +289,16 @@ CPWebViewScrollNative = 2;
|
||||
|
||||
[self _setScrollMode:CPWebViewScrollAppKit];
|
||||
|
||||
[_frameView setFrameSize:[_scrollView contentSize]];
|
||||
|
||||
[self _startedLoading];
|
||||
|
||||
|
||||
_ignoreLoadStart = YES;
|
||||
_ignoreLoadEnd = NO;
|
||||
|
||||
|
||||
_url = null;
|
||||
_html = aString;
|
||||
|
||||
|
||||
[self _load];
|
||||
}
|
||||
|
||||
@@ -272,13 +307,13 @@ CPWebViewScrollNative = 2;
|
||||
[self _setScrollMode:CPWebViewScrollNative];
|
||||
|
||||
[self _startedLoading];
|
||||
|
||||
|
||||
_ignoreLoadStart = YES;
|
||||
_ignoreLoadEnd = NO;
|
||||
|
||||
|
||||
_url = _mainFrameURL;
|
||||
_html = null;
|
||||
|
||||
|
||||
[self _load];
|
||||
}
|
||||
|
||||
@@ -293,11 +328,19 @@ CPWebViewScrollNative = 2;
|
||||
// clear the iframe
|
||||
_iframe.src = "";
|
||||
|
||||
// need to give the browser a chance to reset iframe, otherwise we'll be document.write()-ing the previous document
|
||||
window.setTimeout(function() {
|
||||
if (_loadHTMLStringTimer !== nil)
|
||||
{
|
||||
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];
|
||||
|
||||
win.document.write(_html);
|
||||
|
||||
if (win)
|
||||
win.document.write(_html);
|
||||
|
||||
window.setTimeout(_loadCallback, 1);
|
||||
}, 0);
|
||||
@@ -315,7 +358,8 @@ CPWebViewScrollNative = 2;
|
||||
- (void)_finishedLoading
|
||||
{
|
||||
[self _resizeWebFrame];
|
||||
|
||||
[self _attachScrollEventIfNecessary];
|
||||
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPWebViewProgressFinishedNotification object:self];
|
||||
|
||||
if ([_frameLoadDelegate respondsToSelector:@selector(webView:didFinishLoadForFrame:)])
|
||||
@@ -328,7 +372,7 @@ CPWebViewScrollNative = 2;
|
||||
}
|
||||
|
||||
- (void)setMainFrameURL:(CPString)URLString
|
||||
{
|
||||
{
|
||||
if (_mainFrameURL)
|
||||
[_backwardStack addObject:_mainFrameURL];
|
||||
_mainFrameURL = URLString;
|
||||
@@ -345,9 +389,9 @@ CPWebViewScrollNative = 2;
|
||||
[_forwardStack addObject:_mainFrameURL];
|
||||
_mainFrameURL = [_backwardStack lastObject];
|
||||
[_backwardStack removeLastObject];
|
||||
|
||||
|
||||
[self _loadMainFrameURL];
|
||||
|
||||
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
@@ -361,9 +405,9 @@ CPWebViewScrollNative = 2;
|
||||
[_backwardStack addObject:_mainFrameURL];
|
||||
_mainFrameURL = [_forwardStack lastObject];
|
||||
[_forwardStack removeLastObject];
|
||||
|
||||
|
||||
[self _loadMainFrameURL];
|
||||
|
||||
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
@@ -586,7 +630,7 @@ CPWebViewScrollNative = 2;
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
// FIXME: encode/decode these?
|
||||
@@ -594,14 +638,14 @@ CPWebViewScrollNative = 2;
|
||||
_backwardStack = [];
|
||||
_forwardStack = [];
|
||||
_scrollMode = CPWebViewScrollNative;
|
||||
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
[self _initDOMWithFrame:[self frame]];
|
||||
#endif
|
||||
|
||||
[self setBackgroundColor:[CPColor whiteColor]];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
+304
-130
@@ -26,14 +26,9 @@
|
||||
|
||||
@import "CGGeometry.j"
|
||||
@import "CPAnimation.j"
|
||||
@import "CPPlatformWindow.j"
|
||||
@import "CPResponder.j"
|
||||
@import "CPScreen.j"
|
||||
@import "CPPlatformWindow.j"
|
||||
|
||||
#include "../Platform/Platform.h"
|
||||
#include "../Platform/DOM/CPDOMDisplayServer.h"
|
||||
|
||||
#include "../CoreGraphics/CGGeometry.h"
|
||||
|
||||
|
||||
/*
|
||||
@@ -194,13 +189,15 @@ var SHADOW_MARGIN_LEFT = 20.0,
|
||||
SHADOW_MARGIN_TOP = 10.0,
|
||||
SHADOW_MARGIN_BOTTOM = 10.0,
|
||||
SHADOW_DISTANCE = 5.0,
|
||||
|
||||
|
||||
_CPWindowShadowColor = nil;
|
||||
|
||||
|
||||
var CPWindowSaveImage = nil,
|
||||
CPWindowSavingImage = nil;
|
||||
|
||||
/*!
|
||||
var CPWindowResizeTime = 0.2;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPWindow
|
||||
|
||||
@@ -213,33 +210,33 @@ var CPWindowSaveImage = nil,
|
||||
<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.
|
||||
|
||||
|
||||
@par Delegate Methods
|
||||
|
||||
|
||||
@delegate -(void)windowDidResize:(CPNotification)notification;
|
||||
Sent from the notification center when the window has been resized.
|
||||
@param notification contains information about the resize event
|
||||
|
||||
|
||||
@delegate -(CPUndoManager)windowWillReturnUndoManager:(CPWindow)window;
|
||||
Called to obtain the undo manager for a window
|
||||
@param window the window for which to return the undo manager
|
||||
@return the window's undo manager
|
||||
|
||||
|
||||
@delegate -(void)windowDidBecomeMain:(CPNotification)notification;
|
||||
Sent from the notification center when the delegate's window becomes
|
||||
the main window.
|
||||
@param notification contains information about the event
|
||||
|
||||
|
||||
@delegate -(void)windowDidResignMain:(CPNotification)notification;
|
||||
Sent from the notification center when the delegate's window has
|
||||
resigned main window status.
|
||||
@param notification contains information about the event
|
||||
|
||||
|
||||
@delegate -(void)windowDidResignKey:(CPNotification)notification;
|
||||
Sent from the notification center when the delegate's window has
|
||||
resigned key window status.
|
||||
@param notification contains information about the event
|
||||
|
||||
|
||||
@delegate -(BOOL)windowShouldClose:(id)window;
|
||||
Called when the user tries to close the window.
|
||||
@param window the window to close
|
||||
@@ -311,15 +308,17 @@ var CPWindowSaveImage = nil,
|
||||
#endif
|
||||
|
||||
unsigned _autoresizingMask;
|
||||
|
||||
|
||||
BOOL _delegateRespondsToWindowWillReturnUndoManagerSelector;
|
||||
|
||||
BOOL _isFullPlatformWindow;
|
||||
_CPWindowFullPlatformWindowSession _fullPlatformWindowSession;
|
||||
|
||||
|
||||
CPDictionary _sheetContext;
|
||||
CPWindow _parentView;
|
||||
BOOL _isSheet;
|
||||
|
||||
_CPWindowFrameAnimation _frameAnimation;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -330,9 +329,9 @@ var CPWindowSaveImage = nil,
|
||||
{
|
||||
if (self != [CPWindow class])
|
||||
return;
|
||||
|
||||
|
||||
var bundle = [CPBundle bundleForClass:[CPWindow class]];
|
||||
|
||||
|
||||
CPWindowSavingImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPProgressIndicator/CPProgressIndicatorSpinningStyleRegular.gif"] size:CGSizeMake(16.0, 16.0)]
|
||||
}
|
||||
|
||||
@@ -359,7 +358,7 @@ CPTexturedBackgroundWindowMask
|
||||
- (id)initWithContentRect:(CGRect)aContentRect styleMask:(unsigned int)aStyleMask
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
var windowViewClass = [[self class] _windowViewClassForStyleMask:aStyleMask];
|
||||
@@ -372,6 +371,15 @@ CPTexturedBackgroundWindowMask
|
||||
[self setPlatformWindow:[CPPlatformWindow primaryPlatformWindow]];
|
||||
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 platformWindow]._only = self;
|
||||
}
|
||||
@@ -384,7 +392,7 @@ CPTexturedBackgroundWindowMask
|
||||
// Set up our window number.
|
||||
_windowNumber = [CPApp._windows count];
|
||||
CPApp._windows[_windowNumber] = self;
|
||||
|
||||
|
||||
_styleMask = aStyleMask;
|
||||
|
||||
[self setLevel:CPNormalWindowLevel];
|
||||
@@ -399,15 +407,15 @@ CPTexturedBackgroundWindowMask
|
||||
[_windowView setNextResponder:self];
|
||||
|
||||
[self setMovableByWindowBackground:aStyleMask & CPHUDBackgroundWindowMask];
|
||||
|
||||
|
||||
// Create a generic content view.
|
||||
[self setContentView:[[CPView alloc] initWithFrame:CGRectMakeZero()]];
|
||||
|
||||
|
||||
_firstResponder = self;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
_DOMElement = document.createElement("div");
|
||||
|
||||
|
||||
_DOMElement.style.position = "absolute";
|
||||
_DOMElement.style.visibility = "visible";
|
||||
_DOMElement.style.zIndex = 0;
|
||||
@@ -433,7 +441,7 @@ CPTexturedBackgroundWindowMask
|
||||
|
||||
[self setShowsResizeIndicator:_styleMask & CPResizableWindowMask];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -650,9 +658,10 @@ CPTexturedBackgroundWindowMask
|
||||
|
||||
if (shouldAnimate)
|
||||
{
|
||||
var animation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame];
|
||||
|
||||
[animation startAnimation];
|
||||
[_frameAnimation stopAnimation];
|
||||
_frameAnimation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame];
|
||||
|
||||
[_frameAnimation startAnimation];
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -733,8 +742,10 @@ CPTexturedBackgroundWindowMask
|
||||
*/
|
||||
- (void)orderFront:(id)aSender
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
[_platformWindow orderFront:self];
|
||||
[_platformWindow order:CPWindowAbove window:self relativeTo:nil];
|
||||
#endif
|
||||
|
||||
if (_firstResponder === self || !_firstResponder)
|
||||
[self makeFirstResponder:[self initialFirstResponder]];
|
||||
@@ -762,13 +773,17 @@ CPTexturedBackgroundWindowMask
|
||||
*/
|
||||
- (void)orderOut:(id)aSender
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
if ([self _sharesChromeWithPlatformWindow])
|
||||
[_platformWindow orderOut:self];
|
||||
#endif
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(windowWillClose:)])
|
||||
[_delegate windowWillClose:self];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
[_platformWindow order:CPWindowOut window:self relativeTo:nil];
|
||||
#endif
|
||||
|
||||
[self _updateMainAndKeyWindows];
|
||||
}
|
||||
@@ -780,7 +795,9 @@ CPTexturedBackgroundWindowMask
|
||||
*/
|
||||
- (void)orderWindow:(CPWindowOrderingMode)aPlace relativeTo:(int)otherWindowNumber
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
[_platformWindow order:aPlace window:self relativeTo:CPApp._windows[otherWindowNumber]];
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -865,12 +882,12 @@ CPTexturedBackgroundWindowMask
|
||||
{
|
||||
if (_contentView)
|
||||
[_contentView removeFromSuperview];
|
||||
|
||||
|
||||
var bounds = CGRectMake(0.0, 0.0, CGRectGetWidth(_frame), CGRectGetHeight(_frame));
|
||||
|
||||
|
||||
_contentView = aView;
|
||||
[_contentView setFrame:[self contentRectForFrameRect:bounds]];
|
||||
|
||||
|
||||
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
[_windowView addSubview:_contentView];
|
||||
}
|
||||
@@ -883,6 +900,23 @@ CPTexturedBackgroundWindowMask
|
||||
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.
|
||||
@param aColor the new color for the background
|
||||
@@ -909,24 +943,24 @@ CPTexturedBackgroundWindowMask
|
||||
{
|
||||
if (CGSizeEqualToSize(_minSize, aSize))
|
||||
return;
|
||||
|
||||
|
||||
_minSize = CGSizeCreateCopy(aSize);
|
||||
|
||||
var size = CGSizeMakeCopy([self frame].size),
|
||||
needsFrameChange = NO;
|
||||
|
||||
|
||||
if (size.width < _minSize.width)
|
||||
{
|
||||
size.width = _minSize.width;
|
||||
needsFrameChange = YES;
|
||||
}
|
||||
|
||||
|
||||
if (size.height < _minSize.height)
|
||||
{
|
||||
size.height = _minSize.height;
|
||||
needsFrameChange = YES;
|
||||
}
|
||||
|
||||
|
||||
if (needsFrameChange)
|
||||
[self setFrameSize:size];
|
||||
}
|
||||
@@ -949,24 +983,24 @@ CPTexturedBackgroundWindowMask
|
||||
{
|
||||
if (CGSizeEqualToSize(_maxSize, aSize))
|
||||
return;
|
||||
|
||||
|
||||
_maxSize = CGSizeCreateCopy(aSize);
|
||||
|
||||
var size = CGSizeMakeCopy([self frame].size),
|
||||
needsFrameChange = NO;
|
||||
|
||||
|
||||
if (size.width > _maxSize.width)
|
||||
{
|
||||
size.width = _maxSize.width;
|
||||
needsFrameChange = YES;
|
||||
}
|
||||
|
||||
|
||||
if (size.height > _maxSize.height)
|
||||
{
|
||||
size.height = _maxSize.height;
|
||||
needsFrameChange = YES;
|
||||
}
|
||||
|
||||
|
||||
if (needsFrameChange)
|
||||
[self setFrameSize:size];
|
||||
}
|
||||
@@ -1007,10 +1041,10 @@ CPTexturedBackgroundWindowMask
|
||||
if (_hasShadow && !_shadowView)
|
||||
{
|
||||
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)];
|
||||
|
||||
|
||||
if (!_CPWindowShadowColor)
|
||||
{
|
||||
var bundle = [CPBundle bundleForClass:[CPWindow class]];
|
||||
@@ -1033,7 +1067,7 @@ CPTexturedBackgroundWindowMask
|
||||
|
||||
[_shadowView setBackgroundColor:_CPWindowShadowColor];
|
||||
[_shadowView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
CPDOMDisplayServerInsertBefore(_DOMElement, _shadowView._DOMElement, _windowView._DOMElement);
|
||||
#endif
|
||||
@@ -1099,7 +1133,7 @@ CPTexturedBackgroundWindowMask
|
||||
selector:@selector(windowDidBecomeKey:)
|
||||
name:CPWindowDidBecomeKeyNotification
|
||||
object:self];
|
||||
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(windowDidBecomeMain:)])
|
||||
[defaultCenter
|
||||
addObserver:_delegate
|
||||
@@ -1195,7 +1229,7 @@ CPTexturedBackgroundWindowMask
|
||||
if(!aResponder || ![aResponder acceptsFirstResponder] || ![aResponder becomeFirstResponder])
|
||||
{
|
||||
_firstResponder = self;
|
||||
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
@@ -1248,9 +1282,9 @@ CPTexturedBackgroundWindowMask
|
||||
- (void)setTitle:(CPString)aTitle
|
||||
{
|
||||
_title = aTitle;
|
||||
|
||||
|
||||
[_windowView setTitle:aTitle];
|
||||
|
||||
|
||||
[self _synchronizeMenuBarTitleWithWindowTitle];
|
||||
}
|
||||
|
||||
@@ -1325,10 +1359,21 @@ CPTexturedBackgroundWindowMask
|
||||
*/
|
||||
- (void)center
|
||||
{
|
||||
if (_isFullPlatformWindow)
|
||||
return;
|
||||
|
||||
var size = [self frame].size,
|
||||
containerSize = [CPPlatform isBrowser] ? [_platformWindow contentBounds].size : [[self screen] visibleFrame].size;
|
||||
|
||||
[self setFrameOrigin:CGPointMake((containerSize.width - size.width) / 2.0, (containerSize.height - size.height) / 2.0)];
|
||||
var origin = CGPointMake((containerSize.width - size.width) / 2.0, (containerSize.height - size.height) / 2.0);
|
||||
|
||||
if (origin.x < 0.0)
|
||||
origin.x = 0.0;
|
||||
|
||||
if (origin.y < 0.0)
|
||||
origin.y = 0.0;
|
||||
|
||||
[self setFrameOrigin:origin];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -1342,8 +1387,37 @@ CPTexturedBackgroundWindowMask
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case CPFlagsChanged: return [[self firstResponder] flagsChanged:anEvent];
|
||||
|
||||
case CPKeyUp: return [[self firstResponder] keyUp:anEvent];
|
||||
case CPKeyDown: return [[self firstResponder] keyDown:anEvent];
|
||||
|
||||
case CPKeyDown: 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];
|
||||
|
||||
@@ -1502,7 +1576,7 @@ CPTexturedBackgroundWindowMask
|
||||
- (void)makeKeyAndOrderFront:(id)aSender
|
||||
{
|
||||
[self orderFront:self];
|
||||
|
||||
|
||||
[self makeKeyWindow];
|
||||
[self makeMainWindow];
|
||||
}
|
||||
@@ -1566,7 +1640,7 @@ CPTexturedBackgroundWindowMask
|
||||
if (!pasteboardTypes)
|
||||
return;
|
||||
|
||||
[_inclusiveRegisteredDraggedTypes minusSet:pasteboardTypes]
|
||||
[_inclusiveRegisteredDraggedTypes minusSet:pasteboardTypes];
|
||||
|
||||
if ([_inclusiveRegisteredDraggedTypes count] === 0)
|
||||
_inclusiveRegisteredDraggedTypes = nil;
|
||||
@@ -1597,7 +1671,7 @@ CPTexturedBackgroundWindowMask
|
||||
return;
|
||||
|
||||
[self _noteUnregisteredDraggedTypes:_registeredDraggedTypes];
|
||||
[_registeredDraggedTypes addObjectsFromArray:pasteboardTypes]
|
||||
[_registeredDraggedTypes addObjectsFromArray:pasteboardTypes];
|
||||
[self _noteRegisteredDraggedTypes:_registeredDraggedTypes];
|
||||
|
||||
_registeredDraggedTypesArray = nil;
|
||||
@@ -1610,7 +1684,7 @@ CPTexturedBackgroundWindowMask
|
||||
- (CPArray)registeredDraggedTypes
|
||||
{
|
||||
if (!_registeredDraggedTypesArray)
|
||||
_registeredDraggedTypesArray = [_registeredDraggedTypes allObjects]
|
||||
_registeredDraggedTypesArray = [_registeredDraggedTypes allObjects];
|
||||
|
||||
return _registeredDraggedTypesArray;
|
||||
}
|
||||
@@ -1636,9 +1710,9 @@ CPTexturedBackgroundWindowMask
|
||||
{
|
||||
if (_isDocumentEdited == isDocumentEdited)
|
||||
return;
|
||||
|
||||
|
||||
_isDocumentEdited = isDocumentEdited;
|
||||
|
||||
|
||||
[CPMenu _setMenuBarIconImageAlphaValue:_isDocumentEdited ? 0.5 : 1.0];
|
||||
|
||||
[_windowView setDocumentEdited:isDocumentEdited];
|
||||
@@ -1656,11 +1730,11 @@ CPTexturedBackgroundWindowMask
|
||||
{
|
||||
if (_isDocumentSaving == isDocumentSaving)
|
||||
return;
|
||||
|
||||
|
||||
_isDocumentSaving = isDocumentSaving;
|
||||
|
||||
|
||||
[self _synchronizeSaveMenuWithDocumentSaving];
|
||||
|
||||
|
||||
[_windowView windowDidChangeDocumentSaving];
|
||||
}
|
||||
|
||||
@@ -1677,16 +1751,16 @@ CPTexturedBackgroundWindowMask
|
||||
|
||||
var mainMenu = [CPApp mainMenu],
|
||||
index = [mainMenu indexOfItemWithTitle:_isDocumentSaving ? @"Save" : @"Saving..."];
|
||||
|
||||
|
||||
if (index == CPNotFound)
|
||||
return;
|
||||
|
||||
|
||||
var item = [mainMenu itemAtIndex:index];
|
||||
|
||||
|
||||
if (_isDocumentSaving)
|
||||
{
|
||||
CPWindowSaveImage = [item image];
|
||||
|
||||
|
||||
[item setTitle:@"Saving..."];
|
||||
[item setImage:CPWindowSavingImage];
|
||||
[item setEnabled:NO];
|
||||
@@ -1776,7 +1850,7 @@ CPTexturedBackgroundWindowMask
|
||||
if (![_delegate windowShouldClose:self])
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// 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])
|
||||
return;
|
||||
@@ -1786,8 +1860,8 @@ CPTexturedBackgroundWindowMask
|
||||
{
|
||||
var index = [documents indexOfObject:[_windowController document]];
|
||||
|
||||
[documents[index] shouldCloseWindowController:_windowController
|
||||
delegate:self
|
||||
[documents[index] shouldCloseWindowController:_windowController
|
||||
delegate:self
|
||||
shouldCloseSelector:@selector(_windowControllerContainingDocument:shouldClose:contextInfo:)
|
||||
contextInfo:{documents:[documents copy], visited:0, index:index}];
|
||||
}
|
||||
@@ -1811,8 +1885,8 @@ CPTexturedBackgroundWindowMask
|
||||
{
|
||||
[windowController setDocument:documents[index]];
|
||||
|
||||
[documents[index] shouldCloseWindowController:_windowController
|
||||
delegate:self
|
||||
[documents[index] shouldCloseWindowController:_windowController
|
||||
delegate:self
|
||||
shouldCloseSelector:@selector(_windowControllerContainingDocument:shouldClose:contextInfo:)
|
||||
contextInfo:context];
|
||||
}
|
||||
@@ -1849,7 +1923,7 @@ CPTexturedBackgroundWindowMask
|
||||
// FIXME: Also check if we can resize and titlebar.
|
||||
if ([self isVisible])
|
||||
return YES;
|
||||
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
@@ -1907,10 +1981,17 @@ CPTexturedBackgroundWindowMask
|
||||
[keyWindow makeKeyWindow];
|
||||
else
|
||||
{
|
||||
var menuWindow = [CPApp mainMenu]._menuWindow;
|
||||
var mainMenu = [CPApp mainMenu],
|
||||
menuBarClass = objj_getClass("_CPMenuBarWindow"),
|
||||
menuWindow;
|
||||
|
||||
for (var i = 0; i < windowCount; i++)
|
||||
{
|
||||
var currentWindow = allWindows[i];
|
||||
|
||||
if ([currentWindow isKindOfClass:menuBarClass])
|
||||
menuWindow = currentWindow;
|
||||
|
||||
if (currentWindow === self || currentWindow === menuWindow)
|
||||
continue;
|
||||
|
||||
@@ -1935,10 +2016,17 @@ CPTexturedBackgroundWindowMask
|
||||
[mainWindow makeMainWindow];
|
||||
else
|
||||
{
|
||||
var menuWindow = [CPApp mainMenu]._menuWindow;
|
||||
var mainMenu = [CPApp mainMenu],
|
||||
menuBarClass = objj_getClass("_CPMenuBarWindow"),
|
||||
menuWindow;
|
||||
|
||||
for (var i = 0; i < windowCount; i++)
|
||||
{
|
||||
var currentWindow = allWindows[i];
|
||||
|
||||
if ([currentWindow isKindOfClass:menuBarClass])
|
||||
menuWindow = currentWindow;
|
||||
|
||||
if (currentWindow === self || currentWindow === menuWindow)
|
||||
continue;
|
||||
|
||||
@@ -1969,25 +2057,25 @@ CPTexturedBackgroundWindowMask
|
||||
{
|
||||
if (_toolbar === aToolbar)
|
||||
return;
|
||||
|
||||
|
||||
// If this has an owner, dump it!
|
||||
[[aToolbar _window] setToolbar:nil];
|
||||
|
||||
|
||||
// This is no longer out toolbar.
|
||||
[_toolbar _setWindow:nil];
|
||||
|
||||
|
||||
_toolbar = aToolbar;
|
||||
|
||||
|
||||
// THIS is our toolbar.
|
||||
[_toolbar _setWindow:self];
|
||||
|
||||
|
||||
[self _noteToolbarChanged];
|
||||
}
|
||||
|
||||
- (void)toggleToolbarShown:(id)aSender
|
||||
{
|
||||
var toolbar = [self toolbar];
|
||||
|
||||
|
||||
[toolbar setVisible:![toolbar isVisible]];
|
||||
}
|
||||
|
||||
@@ -2003,10 +2091,10 @@ CPTexturedBackgroundWindowMask
|
||||
else
|
||||
{
|
||||
newFrame = CGRectMakeCopy([self frame]);
|
||||
|
||||
|
||||
newFrame.origin = frame.origin;
|
||||
}
|
||||
|
||||
|
||||
[self setFrame:newFrame];
|
||||
/*
|
||||
[_windowView setAnimatingToolbar:YES];
|
||||
@@ -2018,11 +2106,17 @@ CPTexturedBackgroundWindowMask
|
||||
|
||||
- (void)_setFrame:(CGRect)aFrame delegate:(id)delegate duration:(int)duration curve:(CPAnimationCurve)curve
|
||||
{
|
||||
var animation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame];
|
||||
[animation setDelegate:delegate];
|
||||
[animation setAnimationCurve:curve];
|
||||
[animation setDuration:duration];
|
||||
[animation startAnimation];
|
||||
[_frameAnimation stopAnimation];
|
||||
_frameAnimation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame];
|
||||
[_frameAnimation setDelegate:delegate];
|
||||
[_frameAnimation setAnimationCurve:curve];
|
||||
[_frameAnimation setDuration:duration];
|
||||
[_frameAnimation startAnimation];
|
||||
}
|
||||
|
||||
- (CPTimeInterval)animationResizeTime:(CGRect)newWindowFrame
|
||||
{
|
||||
return CPWindowResizeTime;
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
@@ -2032,7 +2126,7 @@ CPTexturedBackgroundWindowMask
|
||||
var attachedSheet = [self attachedSheet];
|
||||
var contentRect = [[self contentView] frame],
|
||||
sheetFrame = CGRectMakeCopy([attachedSheet frame]);
|
||||
|
||||
|
||||
sheetFrame.origin.y = CGRectGetMinY(_frame) + CGRectGetMinY(contentRect);
|
||||
sheetFrame.origin.x = CGRectGetMinX(_frame) + FLOOR((CGRectGetWidth(_frame) - CGRectGetWidth(sheetFrame)) / 2.0);
|
||||
|
||||
@@ -2044,8 +2138,8 @@ CPTexturedBackgroundWindowMask
|
||||
{
|
||||
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];
|
||||
}
|
||||
|
||||
@@ -2055,12 +2149,12 @@ CPTexturedBackgroundWindowMask
|
||||
var sheetFrame = [aSheet frame],
|
||||
frame = [self frame],
|
||||
sheetContent = [aSheet contentView];
|
||||
|
||||
|
||||
[self _setUpMasksForView:sheetContent];
|
||||
|
||||
|
||||
aSheet._isSheet = YES;
|
||||
aSheet._parentView = self;
|
||||
|
||||
|
||||
var originx = frame.origin.x + FLOOR((frame.size.width - sheetFrame.size.width)/2),
|
||||
originy = frame.origin.y + [[self contentView] frame].origin.y,
|
||||
startFrame = CGRectMake(originx, originy, sheetFrame.size.width, 0),
|
||||
@@ -2068,15 +2162,15 @@ CPTexturedBackgroundWindowMask
|
||||
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPWindowWillBeginSheetNotification object:self];
|
||||
[CPApp runModalForWindow:aSheet];
|
||||
|
||||
|
||||
[aSheet orderFront:self];
|
||||
[aSheet setFrame:startFrame display:YES animate:NO];
|
||||
_sheetContext["opened"] = YES;
|
||||
|
||||
[aSheet _setFrame:endFrame delegate:self duration:0.2 curve:CPAnimationEaseOut];
|
||||
[aSheet _setFrame:endFrame delegate:self duration:[self animationResizeTime:endFrame] curve:CPAnimationEaseOut];
|
||||
|
||||
// Should run the main loop here until _isAnimating = FALSE
|
||||
[aSheet becomeKeyWindow];
|
||||
[aSheet becomeKeyWindow];
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
@@ -2087,14 +2181,14 @@ CPTexturedBackgroundWindowMask
|
||||
endFrame = CGRectMakeCopy(startFrame);
|
||||
|
||||
endFrame.size.height = 0;
|
||||
|
||||
|
||||
_sheetContext["frame"] = startFrame;
|
||||
|
||||
|
||||
var sheetContent = [sheet contentView];
|
||||
[self _setUpMasksForView:sheetContent];
|
||||
|
||||
_sheetContext["opened"] = NO;
|
||||
[sheet _setFrame:endFrame delegate:self duration:0.2 curve:CPAnimationEaseIn];
|
||||
[sheet _setFrame:endFrame delegate:self duration:[self animationResizeTime:endFrame] curve:CPAnimationEaseIn];
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
@@ -2105,31 +2199,33 @@ CPTexturedBackgroundWindowMask
|
||||
return;
|
||||
|
||||
var sheetContent = [sheet contentView];
|
||||
|
||||
|
||||
if (_sheetContext["opened"] === YES)
|
||||
{
|
||||
[self _restoreMasksForView:sheetContent];
|
||||
return;
|
||||
}
|
||||
|
||||
[CPApp stopModal];
|
||||
|
||||
[CPApp stopModal];
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPWindowDidEndSheetNotification object:self];
|
||||
|
||||
[sheet orderOut:self];
|
||||
|
||||
var lastFrame = _sheetContext["frame"];
|
||||
[sheet setFrame:lastFrame];
|
||||
|
||||
|
||||
[self _restoreMasksForView:sheetContent];
|
||||
|
||||
var delegate = _sheetContext["modalDelegate"],
|
||||
endSelector = _sheetContext["endSelector"];
|
||||
|
||||
if (delegate != nil && endSelector != nil)
|
||||
objj_msgSend(delegate, endSelector, sheet, _sheetContext["returnCode"], _sheetContext["contextInfo"]);
|
||||
endSelector = _sheetContext["endSelector"],
|
||||
returnCode = _sheetContext["returnCode"],
|
||||
contextInfo = _sheetContext["contextInfo"];
|
||||
|
||||
_sheetContext = nil;
|
||||
sheet._parentView = nil;
|
||||
|
||||
if (delegate != nil && endSelector != nil)
|
||||
objj_msgSend(delegate, endSelector, sheet, returnCode, contextInfo);
|
||||
}
|
||||
|
||||
- (void)_setUpMasksForView:(CPView)aView
|
||||
@@ -2137,7 +2233,7 @@ CPTexturedBackgroundWindowMask
|
||||
var views = [aView subviews];
|
||||
|
||||
[views addObject:aView];
|
||||
|
||||
|
||||
for (var i = 0, count = [views count]; i < count; i++)
|
||||
{
|
||||
var view = [views objectAtIndex:i],
|
||||
@@ -2153,7 +2249,7 @@ CPTexturedBackgroundWindowMask
|
||||
var views = [aView subviews];
|
||||
|
||||
[views addObject:aView];
|
||||
|
||||
|
||||
for (var i = 0, count = [views count]; i < count; i++)
|
||||
{
|
||||
var view = [views objectAtIndex:i],
|
||||
@@ -2171,7 +2267,7 @@ CPTexturedBackgroundWindowMask
|
||||
{
|
||||
if (_sheetContext === nil)
|
||||
return nil;
|
||||
|
||||
|
||||
return _sheetContext["sheet"];
|
||||
}
|
||||
|
||||
@@ -2202,7 +2298,7 @@ CPTexturedBackgroundWindowMask
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)performKeyEquivalent:(CPEvent)anEvent
|
||||
- (BOOL)performKeyEquivalent:(CPEvent)anEvent
|
||||
{
|
||||
// FIXME: should we be starting at the root, in other words _windowView?
|
||||
// The evidence seems to point to no...
|
||||
@@ -2213,19 +2309,92 @@ CPTexturedBackgroundWindowMask
|
||||
{
|
||||
// It's not clear why we do performKeyEquivalent again here...
|
||||
// Perhaps to allow something to happen between sendEvent: and keyDown:?
|
||||
if (![anEvent _couldBeKeyEquivalent] || ![self performKeyEquivalent:anEvent])
|
||||
[self interpretKeyEvents:[anEvent]];
|
||||
if ([anEvent _couldBeKeyEquivalent] && [self performKeyEquivalent:anEvent])
|
||||
return;
|
||||
|
||||
// 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
|
||||
{
|
||||
if (_defaultButton && _defaultButtonEnabled)
|
||||
[_defaultButton performClick:nil];
|
||||
var character = [anEvent charactersIgnoringModifiers],
|
||||
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)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
|
||||
{
|
||||
[self selectNextKeyView:nil];
|
||||
var character = [anEvent charactersIgnoringModifiers],
|
||||
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
|
||||
@@ -2252,7 +2421,7 @@ CPTexturedBackgroundWindowMask
|
||||
- (void)recalculateKeyViewLoop
|
||||
{
|
||||
var subviews = [];
|
||||
|
||||
|
||||
[self _appendSubviewsOf:_contentView toArray:subviews];
|
||||
|
||||
var keyViewOrder = [subviews sortedArrayUsingFunction:keyViewComparator context:_contentView],
|
||||
@@ -2260,7 +2429,7 @@ CPTexturedBackgroundWindowMask
|
||||
|
||||
for (var i=0; i<count; i++)
|
||||
[keyViewOrder[i] setNextKeyView:keyViewOrder[(i+1)%count]];
|
||||
|
||||
|
||||
_keyViewLoopIsDirty = NO;
|
||||
}
|
||||
|
||||
@@ -2281,7 +2450,7 @@ CPTexturedBackgroundWindowMask
|
||||
return;
|
||||
|
||||
_autorecalculatesKeyViewLoop = shouldRecalculate;
|
||||
|
||||
|
||||
if (_keyViewLoopIsDirty)
|
||||
[self recalculateKeyViewLoop];
|
||||
else if (_autorecalculatesKeyViewLoop)
|
||||
@@ -2333,11 +2502,16 @@ CPTexturedBackgroundWindowMask
|
||||
|
||||
- (void)setDefaultButton:(CPButton)aButton
|
||||
{
|
||||
[_defaultButton setDefaultButton:NO];
|
||||
if (_defaultButton === aButton)
|
||||
return;
|
||||
|
||||
if ([_defaultButton keyEquivalent] === CPCarriageReturnCharacter)
|
||||
[_defaultButton setKeyEquivalent:nil];
|
||||
|
||||
_defaultButton = aButton;
|
||||
|
||||
[_defaultButton setDefaultButton:YES];
|
||||
if ([_defaultButton keyEquivalent] !== CPCarriageReturnCharacter)
|
||||
[_defaultButton setKeyEquivalent:CPCarriageReturnCharacter];
|
||||
}
|
||||
|
||||
- (CPButton)defaultButton
|
||||
@@ -2404,7 +2578,7 @@ var keyViewComparator = function(a, b, context)
|
||||
{
|
||||
if ([self isFullPlatformWindow])
|
||||
return [self setFrame:[_platformWindow visibleFrame]];
|
||||
|
||||
|
||||
if (_autoresizingMask == CPWindowNotSizable)
|
||||
return;
|
||||
|
||||
@@ -2419,7 +2593,7 @@ var keyViewComparator = function(a, b, context)
|
||||
newFrame.origin.x += dX;
|
||||
if (_autoresizingMask & CPWindowWidthSizable)
|
||||
newFrame.size.width += dX;
|
||||
|
||||
|
||||
if (_autoresizingMask & CPWindowMinYMargin)
|
||||
newFrame.origin.y += dY;
|
||||
if (_autoresizingMask & CPWindowHeightSizable)
|
||||
@@ -2591,39 +2765,39 @@ var interpolate = function(fromValue, toValue, progress)
|
||||
@implementation _CPWindowFrameAnimation : CPAnimation
|
||||
{
|
||||
CPWindow _window;
|
||||
|
||||
|
||||
CGRect _startFrame;
|
||||
CGRect _targetFrame;
|
||||
}
|
||||
|
||||
- (id)initWithWindow:(CPWindow)aWindow targetFrame:(CGRect)aTargetFrame
|
||||
{
|
||||
self = [super initWithDuration:0.2 animationCurve:CPAnimationLinear];
|
||||
|
||||
self = [super initWithDuration:[aWindow animationResizeTime:aTargetFrame] animationCurve:CPAnimationLinear];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_window = aWindow;
|
||||
|
||||
|
||||
_targetFrame = CGRectMakeCopy(aTargetFrame);
|
||||
_startFrame = CGRectMakeCopy([_window frame]);
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)startAnimation
|
||||
{
|
||||
[super startAnimation];
|
||||
|
||||
|
||||
_window._isAnimating = YES;
|
||||
}
|
||||
|
||||
- (void)setCurrentProgress:(float)aProgress
|
||||
{
|
||||
[super setCurrentProgress:aProgress];
|
||||
|
||||
|
||||
var value = [self currentValue];
|
||||
|
||||
|
||||
if (value == 1.0)
|
||||
_window._isAnimating = NO;
|
||||
|
||||
|
||||
@@ -43,21 +43,21 @@ var HUD_TITLEBAR_HEIGHT = 26.0;
|
||||
|
||||
_CPHUDWindowViewBackgroundColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
|
||||
[
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground0.png"] size:CPSizeMake(6.0, 78.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground1.png"] size:CPSizeMake(1.0, 78.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground2.png"] size:CPSizeMake(6.0, 78.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground0.png"] size:CPSizeMake(7.0, 37.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground1.png"] size:CPSizeMake(1.0, 37.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground2.png"] size:CPSizeMake(7.0, 37.0)],
|
||||
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground3.png"] size:CPSizeMake(6.0, 1.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground4.png"] size:CPSizeMake(5.0, 5.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground5.png"] size:CPSizeMake(6.0, 1.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground3.png"] size:CPSizeMake(7.0, 1.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground4.png"] size:CPSizeMake(2.0, 2.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground5.png"] size:CPSizeMake(7.0, 1.0)],
|
||||
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground6.png"] size:CPSizeMake(6.0, 6.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground7.png"] size:CPSizeMake(6.0, 6.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground8.png"] size:CPSizeMake(6.0, 6.0)]
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground6.png"] size:CPSizeMake(7.0, 3.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground7.png"] size:CPSizeMake(1.0, 3.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground8.png"] size:CPSizeMake(7.0, 3.0)]
|
||||
]]];
|
||||
|
||||
_CPHUDWindowViewCloseImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"HUDTheme/WindowClose.png"] size:CPSizeMake(20.0, 20.0)];
|
||||
_CPHUDWindowViewCloseActiveImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"HUDTheme/WindowCloseActive.png"] size:CPSizeMake(20.0, 20.0)];
|
||||
_CPHUDWindowViewCloseImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"HUDTheme/WindowClose.png"] size:CPSizeMake(18.0, 18.0)];
|
||||
_CPHUDWindowViewCloseActiveImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"HUDTheme/WindowCloseActive.png"] size:CPSizeMake(18.0, 18.0)];
|
||||
}
|
||||
|
||||
+ (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
|
||||
@@ -148,7 +148,7 @@ var HUD_TITLEBAR_HEIGHT = 26.0;
|
||||
{
|
||||
var closeSize = [_CPHUDWindowViewCloseImage size];
|
||||
|
||||
_closeButton = [[CPButton alloc] initWithFrame:CGRectMake(4.0, 4.0, closeSize.width, closeSize.height)];
|
||||
_closeButton = [[CPButton alloc] initWithFrame:CGRectMake(8.0, 5.0, closeSize.width, closeSize.height)];
|
||||
|
||||
[_closeButton setBordered:NO];
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
@import "_CPWindowView.j"
|
||||
|
||||
|
||||
var GRADIENT_HEIGHT = 41.0;
|
||||
|
||||
var _CPTexturedWindowHeadGradientColor = nil,
|
||||
|
||||
@@ -20,10 +20,8 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CPView.j"
|
||||
@import "CPImageView.j"
|
||||
|
||||
#include "../CoreGraphics/CGGeometry.h"
|
||||
@import "CPView.j"
|
||||
|
||||
|
||||
var _CPWindowViewResizeIndicatorImage = nil;
|
||||
|
||||
@@ -27,8 +27,6 @@
|
||||
@import "CPWindow.j"
|
||||
@import "CPDocument.j"
|
||||
|
||||
#include "Platform/Platform.h"
|
||||
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@@ -133,7 +131,7 @@
|
||||
if (_window)
|
||||
return;
|
||||
|
||||
[[CPBundle bundleForClass:[_cibOwner class]] loadCibFile:[self windowCibPath] externalNameTable:[CPDictionary dictionaryWithObject:_cibOwner forKey:CPCibOwner]];
|
||||
[[CPBundle mainBundle] loadCibFile:[self windowCibPath] externalNameTable:[CPDictionary dictionaryWithObject:_cibOwner forKey:CPCibOwner]];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -424,7 +422,7 @@
|
||||
if (_windowCibPath)
|
||||
return _windowCibPath;
|
||||
|
||||
return [[CPBundle bundleForClass:[_cibOwner class]] pathForResource:_windowCibName + @".cib"];
|
||||
return [[CPBundle mainBundle] pathForResource:_windowCibName + @".cib"];
|
||||
}
|
||||
|
||||
// Setting and Getting Window Attributes
|
||||
|
||||
+1
-1
@@ -150,7 +150,7 @@ var CPCibObjectDataKey = @"CPCibObjectDataKey";
|
||||
|
||||
var topLevelObjects = [anExternalNameTable objectForKey:CPCibTopLevelObjects];
|
||||
|
||||
[objectData instantiateWithOwner:owner topLevelObjects:topLevelObjects]
|
||||
[objectData instantiateWithOwner:owner topLevelObjects:topLevelObjects];
|
||||
[objectData establishConnectionsWithOwner:owner topLevelObjects:topLevelObjects];
|
||||
[objectData awakeWithOwner:owner topLevelObjects:topLevelObjects];
|
||||
|
||||
|
||||
@@ -39,9 +39,11 @@
|
||||
|
||||
// Not having a selector is a fatal error.
|
||||
if (!selector)
|
||||
{
|
||||
[CPException
|
||||
raise:CPInvalidArgumentException
|
||||
reason:@"-[" + [self className] + ' ' + _cmd + @"] selector " + selectorName + @" does not exist."];
|
||||
}
|
||||
|
||||
// If the destination doesn't respond to this selector, warn but don't die.
|
||||
if (_destination && ![_destination respondsToSelector:selector])
|
||||
@@ -58,7 +60,7 @@
|
||||
else
|
||||
[CPException
|
||||
raise:CPInvalidArgumentException
|
||||
reason:@"-[" + [self className] + ' ' + _cmd + @"] " + [_source description] + " does not respond to setAction:"];
|
||||
reason:@"-[" + [self className] + ' ' + _cmd + @"] " + [_source description] + @" does not respond to setAction:"];
|
||||
|
||||
// Not being able to set the target is a fatal error.
|
||||
if ([_source respondsToSelector:@selector(setTarget:)])
|
||||
@@ -67,10 +69,14 @@
|
||||
else
|
||||
[CPException
|
||||
raise:CPInvalidArgumentException
|
||||
reason:@"-[" + [self className] + ' ' + _cmd + @"] " + [_source description] + " does not respond to setTarget:"];
|
||||
reason:@"-[" + [self className] + ' ' + _cmd + @"] " + [_source description] + @" does not respond to setTarget:"];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation _CPCibControlConnector : CPCibControlConnector { } @end
|
||||
@implementation _CPCibControlConnector : CPCibControlConnector
|
||||
{
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
+14
-14
@@ -37,12 +37,12 @@ var CPCibOwner = @"CPCibOwner";
|
||||
|
||||
@implementation CPBundle (CPCibLoading)
|
||||
|
||||
+ (void)loadCibFile:(CPString)anAbsolutePath externalNameTable:(CPDictionary)aNameTable
|
||||
+ (CPCib)loadCibFile:(CPString)anAbsolutePath externalNameTable:(CPDictionary)aNameTable
|
||||
{
|
||||
[[[CPCib alloc] initWithContentsOfURL:anAbsolutePath] instantiateCibWithExternalNameTable:aNameTable];
|
||||
return [[[CPCib alloc] initWithContentsOfURL:anAbsolutePath] instantiateCibWithExternalNameTable:aNameTable];
|
||||
}
|
||||
|
||||
+ (void)loadCibNamed:(CPString)aName owner:(id)anOwner
|
||||
+ (CPCib)loadCibNamed:(CPString)aName owner:(id)anOwner
|
||||
{
|
||||
if (![aName hasSuffix:@".cib"])
|
||||
aName = [aName stringByAppendingString:@".cib"];
|
||||
@@ -51,24 +51,24 @@ var CPCibOwner = @"CPCibOwner";
|
||||
var bundle = anOwner ? [CPBundle bundleForClass:[anOwner class]] : [CPBundle mainBundle],
|
||||
path = [bundle pathForResource:aName];
|
||||
|
||||
[self loadCibFile:path externalNameTable:[CPDictionary dictionaryWithObject:anOwner forKey:CPCibOwner]];
|
||||
return [self loadCibFile:path externalNameTable:[CPDictionary dictionaryWithObject:anOwner forKey:CPCibOwner]];
|
||||
}
|
||||
|
||||
- (void)loadCibFile:(CPString)aFileName externalNameTable:(CPDictionary)aNameTable
|
||||
- (CPCib)loadCibFile:(CPString)aFileName externalNameTable:(CPDictionary)aNameTable
|
||||
{
|
||||
[[[CPCib alloc] initWithContentsOfURL:aFileName] instantiateCibWithExternalNameTable:aNameTable];
|
||||
return [[[CPCib alloc] initWithContentsOfURL:aFileName] instantiateCibWithExternalNameTable:aNameTable];
|
||||
}
|
||||
|
||||
+ (void)loadCibFile:(CPString)anAbsolutePath externalNameTable:(CPDictionary)aNameTable loadDelegate:aDelegate
|
||||
+ (CPCib)loadCibFile:(CPString)anAbsolutePath externalNameTable:(CPDictionary)aNameTable loadDelegate:aDelegate
|
||||
{
|
||||
[[CPCib alloc]
|
||||
return ([[CPCib alloc]
|
||||
initWithContentsOfURL:anAbsolutePath
|
||||
loadDelegate:[[_CPCibLoadDelegate alloc]
|
||||
initWithLoadDelegate:aDelegate
|
||||
externalNameTable:aNameTable]];
|
||||
externalNameTable:aNameTable]]);
|
||||
}
|
||||
|
||||
+ (void)loadCibNamed:(CPString)aName owner:(id)anOwner loadDelegate:(id)aDelegate
|
||||
+ (CPCib)loadCibNamed:(CPString)aName owner:(id)anOwner loadDelegate:(id)aDelegate
|
||||
{
|
||||
if (![aName hasSuffix:@".cib"])
|
||||
aName = [aName stringByAppendingString:@".cib"];
|
||||
@@ -77,17 +77,17 @@ var CPCibOwner = @"CPCibOwner";
|
||||
var bundle = anOwner ? [CPBundle bundleForClass:[anOwner class]] : [CPBundle mainBundle],
|
||||
path = [bundle pathForResource:aName];
|
||||
|
||||
[self loadCibFile:path externalNameTable:[CPDictionary dictionaryWithObject:anOwner forKey:CPCibOwner] loadDelegate:aDelegate];
|
||||
return [self loadCibFile:path externalNameTable:[CPDictionary dictionaryWithObject:anOwner forKey:CPCibOwner] loadDelegate:aDelegate];
|
||||
}
|
||||
|
||||
- (void)loadCibFile:(CPString)aFileName externalNameTable:(CPDictionary)aNameTable loadDelegate:(id)aDelegate
|
||||
- (CPCib)loadCibFile:(CPString)aFileName externalNameTable:(CPDictionary)aNameTable loadDelegate:(id)aDelegate
|
||||
{
|
||||
[[CPCib alloc]
|
||||
return ([[CPCib alloc]
|
||||
initWithCibNamed:aFileName
|
||||
bundle:self
|
||||
loadDelegate:[[_CPCibLoadDelegate alloc]
|
||||
initWithLoadDelegate:aDelegate
|
||||
externalNameTable:aNameTable]];
|
||||
externalNameTable:aNameTable]]);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -46,28 +46,28 @@ var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey",
|
||||
- (id)initWithClassName:(CPString)aClassName resourceName:(CPString)aResourceName properties:(CPDictionary)properties
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_className = aClassName;
|
||||
_resourceName = aResourceName;
|
||||
_properties = properties;
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_className = [aCoder decodeObjectForKey:_CPCibCustomResourceClassNameKey];
|
||||
_resourceName = [aCoder decodeObjectForKey:_CPCibCustomResourceResourceNameKey];
|
||||
_properties = [aCoder decodeObjectForKey:_CPCibCustomResourcePropertiesKey];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey",
|
||||
|
||||
- (id)awakeAfterUsingCoder:(CPCoder)aCoder
|
||||
{
|
||||
if ([aCoder respondsToSelector:@selector(bundle)] &&
|
||||
if ([aCoder respondsToSelector:@selector(bundle)] &&
|
||||
(![aCoder respondsToSelector:@selector(awakenCustomResources)] || [aCoder awakenCustomResources]))
|
||||
if (_className === @"CPImage")
|
||||
return [[CPImage alloc] initWithContentsOfFile:[[aCoder bundle] pathForResource:_resourceName] size:_properties.valueForKey(@"size")];
|
||||
@@ -112,4 +112,14 @@ var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey",
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (unsigned)loadStatus
|
||||
{
|
||||
return CPImageLoadStatusCompleted;
|
||||
}
|
||||
|
||||
- (id)delegate
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
@import "CGGeometry.j"
|
||||
@import "CPWindow.j"
|
||||
|
||||
|
||||
var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinSizeKey",
|
||||
_CPCibWindowTemplateMaxSizeKey = @"_CPCibWindowTemplateMaxSizeKey",
|
||||
|
||||
@@ -22,13 +22,10 @@
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
@import <AppKit/CABackingStore.j>
|
||||
@import "CABackingStore.j"
|
||||
|
||||
@import <AppKit/CGContext.j>
|
||||
@import <AppKit/CGGeometry.j>
|
||||
|
||||
#include "../CoreGraphics/CGGeometry.h"
|
||||
#include "../CoreGraphics/CGAffineTransform.j"
|
||||
@import "CGContext.j"
|
||||
@import "CGGeometry.j"
|
||||
|
||||
|
||||
#define DOM(aLayer) aLayer._DOMElement
|
||||
|
||||
@@ -20,14 +20,11 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "CGGeometry.h"
|
||||
#include "CGAffineTransform.h"
|
||||
|
||||
#define _function(inline) function inline { return _##inline; }
|
||||
|
||||
@import "CGGeometry.j"
|
||||
|
||||
|
||||
#define _function(inline) function inline { return _##inline; }
|
||||
|
||||
_function(CGAffineTransformMake(a, b, c, d, tx, ty))
|
||||
_function(CGAffineTransformMakeIdentity())
|
||||
_function(CGAffineTransformMakeCopy(anAffineTransform))
|
||||
|
||||
@@ -20,13 +20,12 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "CGGeometry.h"
|
||||
#include "CGAffineTransform.h"
|
||||
|
||||
@import "CGGeometry.j"
|
||||
@import "CGAffineTransform.j"
|
||||
@import "CPCompatibility.j"
|
||||
@import "CGGeometry.j"
|
||||
@import "CGPath.j"
|
||||
|
||||
|
||||
kCGLineCapButt = 0;
|
||||
kCGLineCapRound = 1;
|
||||
kCGLineCapSquare = 2;
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
#define _CGInsetMakeCopy(anInset) _CGInsetMake(anInset.top, anInset.right, anInset.bottom, anInset.left)
|
||||
#define _CGInsetMakeZero() _CGInsetMake(0, 0, 0, 0)
|
||||
#define _CGInsetIsEmpty(anInset) ((anInset).top === 0 && (anInset).right === 0 && (anInset).bottom === 0 && (anInset).left === 0)
|
||||
#define _CGInsetEqualToInset(lhsInset, rhsInset) ((lhsInset).top === (rhsInset).top && (lhsInset).right === (rhsInset).right && (lhsInset).bottom === (rhsInset).bottom && (lhsInset).left === (rhsInset).left)
|
||||
|
||||
// DEPRECATED
|
||||
#define _CGPointCreateCopy(aPoint) _CGPointMake(aPoint.x, aPoint.y)
|
||||
|
||||
@@ -20,8 +20,6 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "CGGeometry.h"
|
||||
|
||||
#define _function(inline) function inline { return _##inline; }
|
||||
|
||||
_function(CGPointMake(x, y))
|
||||
@@ -69,6 +67,12 @@ _function(CGInsetMake(top, right, bottom, left))
|
||||
_function(CGInsetMakeZero())
|
||||
_function(CGInsetMakeCopy(anInset))
|
||||
_function(CGInsetIsEmpty(anInset))
|
||||
_function(CGInsetEqualToInset(lhsInset, rhsInset))
|
||||
|
||||
CGMinXEdge = 0;
|
||||
CGMinYEdge = 1;
|
||||
CGMaxXEdge = 2;
|
||||
CGMaxYEdge = 3;
|
||||
|
||||
CGRectNull = _CGRectMake(Infinity, Infinity, 0.0, 0.0);
|
||||
|
||||
@@ -77,6 +81,50 @@ CGRectNull = _CGRectMake(Infinity, Infinity, 0.0, 0.0);
|
||||
@{
|
||||
*/
|
||||
|
||||
/*!
|
||||
Creates two rectangles -- slice and rem -- from inRect, by dividing inRect
|
||||
with a line that's parallel to the side of inRect specified by edge.
|
||||
The size of slice is determined by amount, which specifies the distance from edge.
|
||||
|
||||
slice and rem must not be NULL, must not be the same object, and must not be the
|
||||
same object as inRect.
|
||||
|
||||
@group CGRect
|
||||
*/
|
||||
function CGRectDivide(inRect, slice, rem, amount, edge)
|
||||
{
|
||||
slice.origin = _CGPointMakeCopy(inRect.origin);
|
||||
slice.size = _CGSizeMakeCopy(inRect.size);
|
||||
rem.origin = _CGPointMakeCopy(inRect.origin);
|
||||
rem.size = _CGSizeMakeCopy(inRect.size);
|
||||
|
||||
switch (edge)
|
||||
{
|
||||
case CGMinXEdge:
|
||||
slice.size.width = amount;
|
||||
rem.origin.x += amount;
|
||||
rem.size.width -= amount;
|
||||
break;
|
||||
|
||||
case CGMaxXEdge:
|
||||
slice.origin.x = _CGRectGetMaxX(slice) - amount;
|
||||
slice.size.width = amount;
|
||||
rem.size.width -= amount;
|
||||
break;
|
||||
|
||||
case CGMinYEdge:
|
||||
slice.size.height = amount;
|
||||
rem.origin.y += amount;
|
||||
rem.size.height -= amount;
|
||||
break;
|
||||
|
||||
case CGMaxYEdge:
|
||||
slice.origin.y = _CGRectGetMaxY(slice) - amount;
|
||||
slice.size.height = amount;
|
||||
rem.size.height -= amount;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a \c BOOL indicating whether CGRect \c lhsRect
|
||||
contains CGRect \c rhsRect.
|
||||
@@ -88,7 +136,7 @@ CGRectNull = _CGRectMake(Infinity, Infinity, 0.0, 0.0);
|
||||
function CGRectContainsRect(lhsRect, rhsRect)
|
||||
{
|
||||
var union = CGRectUnion(lhsRect, rhsRect);
|
||||
|
||||
|
||||
return _CGRectEqualToRect(union, lhsRect);
|
||||
}
|
||||
|
||||
@@ -102,12 +150,12 @@ function CGRectContainsRect(lhsRect, rhsRect)
|
||||
function CGRectIntersectsRect(lhsRect, rhsRect)
|
||||
{
|
||||
var intersection = CGRectIntersection(lhsRect, rhsRect);
|
||||
|
||||
|
||||
return !_CGRectIsEmpty(intersection);
|
||||
}
|
||||
|
||||
/*!
|
||||
Makes the origin and size of a CGRect all integers. Specifically, by making
|
||||
Makes the origin and size of a CGRect all integers. Specifically, by making
|
||||
the southwest corner the origin (rounded down), and the northeast corner a CGSize (rounded up).
|
||||
@param aRect the rectangle to operate on
|
||||
@return CGRect the modified rectangle (same as the input)
|
||||
@@ -120,7 +168,7 @@ function CGRectIntegral(aRect)
|
||||
// Store these out separately, if not the GetMaxes will return incorrect values.
|
||||
var x = FLOOR(_CGRectGetMinX(aRect)),
|
||||
y = FLOOR(_CGRectGetMinY(aRect));
|
||||
|
||||
|
||||
aRect.size.width = CEIL(_CGRectGetMaxX(aRect)) - x;
|
||||
aRect.size.height = CEIL(_CGRectGetMaxY(aRect)) - y;
|
||||
|
||||
@@ -140,18 +188,18 @@ function CGRectIntegral(aRect)
|
||||
function CGRectIntersection(lhsRect, rhsRect)
|
||||
{
|
||||
var intersection = _CGRectMake(
|
||||
MAX(_CGRectGetMinX(lhsRect), _CGRectGetMinX(rhsRect)),
|
||||
MAX(_CGRectGetMinY(lhsRect), _CGRectGetMinY(rhsRect)),
|
||||
MAX(_CGRectGetMinX(lhsRect), _CGRectGetMinX(rhsRect)),
|
||||
MAX(_CGRectGetMinY(lhsRect), _CGRectGetMinY(rhsRect)),
|
||||
0, 0);
|
||||
|
||||
|
||||
intersection.size.width = MIN(_CGRectGetMaxX(lhsRect), _CGRectGetMaxX(rhsRect)) - _CGRectGetMinX(intersection);
|
||||
intersection.size.height = MIN(_CGRectGetMaxY(lhsRect), _CGRectGetMaxY(rhsRect)) - _CGRectGetMinY(intersection);
|
||||
|
||||
|
||||
return _CGRectIsEmpty(intersection) ? _CGRectMakeZero() : intersection;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
|
||||
*/
|
||||
function CGRectStandardize(aRect)
|
||||
{
|
||||
@@ -189,28 +237,28 @@ function CGRectUnion(lhsRect, rhsRect)
|
||||
minY = MIN(_CGRectGetMinY(lhsRect), _CGRectGetMinY(rhsRect)),
|
||||
maxX = MAX(_CGRectGetMaxX(lhsRect), _CGRectGetMaxX(rhsRect)),
|
||||
maxY = MAX(_CGRectGetMaxY(lhsRect), _CGRectGetMaxY(rhsRect));
|
||||
|
||||
|
||||
return _CGRectMake(minX, minY, maxX - minX, maxY - minY);
|
||||
}
|
||||
|
||||
function CGPointFromString(aString)
|
||||
{
|
||||
var comma = aString.indexOf(',');
|
||||
|
||||
|
||||
return { x:parseInt(aString.substr(1, comma - 1)), y:parseInt(aString.substring(comma + 1, aString.length)) };
|
||||
}
|
||||
|
||||
function CGSizeFromString(aString)
|
||||
{
|
||||
var comma = aString.indexOf(',');
|
||||
|
||||
|
||||
return { width:parseInt(aString.substr(1, comma - 1)), height:parseInt(aString.substring(comma + 1, aString.length)) };
|
||||
}
|
||||
|
||||
function CGRectFromString(aString)
|
||||
{
|
||||
var comma = aString.indexOf(',', aString.indexOf(',') + 1);
|
||||
|
||||
|
||||
return { origin:CGPointFromString(aString.substr(1, comma - 1)), size:CGSizeFromString(aString.substring(comma + 2, aString.length)) };
|
||||
}
|
||||
|
||||
@@ -233,6 +281,6 @@ function CPStringFromCGInset(anInset)
|
||||
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
Reference in New Issue
Block a user