Merge branch 'master' into @each
Conflicts: Foundation/CPArray.j
@@ -36,8 +36,8 @@
|
||||
@import "CPCibLoading.j"
|
||||
@import "CPCibOutletConnector.j"
|
||||
@import "CPClipView.j"
|
||||
@import "CPCollectionViewItem.j"
|
||||
@import "CPCollectionView.j"
|
||||
@import "CPCollectionViewItem.j"
|
||||
@import "CPColor.j"
|
||||
@import "CPColorPanel.j"
|
||||
@import "CPColorWell.j"
|
||||
@@ -53,8 +53,10 @@
|
||||
@import "CPFont.j"
|
||||
@import "CPFontManager.j"
|
||||
@import "CPGeometry.j"
|
||||
@import "CPGraphics.j"
|
||||
@import "CPImage.j"
|
||||
@import "CPImageView.j"
|
||||
@import "CPKeyBinding.j"
|
||||
@import "CPMenu.j"
|
||||
@import "CPMenuItem.j"
|
||||
@import "CPOpenPanel.j"
|
||||
@@ -65,17 +67,17 @@
|
||||
@import "CPProgressIndicator.j"
|
||||
@import "CPRadio.j"
|
||||
@import "CPResponder.j"
|
||||
@import "CPSearchField.j"
|
||||
@import "CPScrollView.j"
|
||||
@import "CPScroller.j"
|
||||
@import "CPScrollView.j"
|
||||
@import "CPSearchField.j"
|
||||
@import "CPSecureTextField.j"
|
||||
@import "CPSegmentedControl.j"
|
||||
@import "CPShadow.j"
|
||||
@import "CPSlider.j"
|
||||
@import "CPSplitView.j"
|
||||
@import "CPTabView.j"
|
||||
@import "CPTableColumn.j"
|
||||
@import "CPTableView.j"
|
||||
@import "CPTabView.j"
|
||||
@import "CPText.j"
|
||||
@import "CPTextField.j"
|
||||
@import "CPToolbar.j"
|
||||
@@ -87,3 +89,4 @@
|
||||
@import "CPWebView.j"
|
||||
@import "CPWindow.j"
|
||||
@import "CPWindowController.j"
|
||||
@import "CPArrayController.j"
|
||||
|
||||
@@ -39,26 +39,21 @@
|
||||
@global
|
||||
@group CPAlertStyle
|
||||
*/
|
||||
CPWarningAlertStyle = 0;
|
||||
CPWarningAlertStyle = 0;
|
||||
/*
|
||||
@global
|
||||
@group CPAlertStyle
|
||||
*/
|
||||
CPInformationalAlertStyle = 1;
|
||||
CPInformationalAlertStyle = 1;
|
||||
/*
|
||||
@global
|
||||
@group CPAlertStyle
|
||||
*/
|
||||
CPCriticalAlertStyle = 2;
|
||||
|
||||
|
||||
var CPAlertWarningImage,
|
||||
CPAlertInformationImage,
|
||||
CPAlertErrorImage;
|
||||
CPCriticalAlertStyle = 2;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
|
||||
|
||||
CPAlert is an alert panel that can be displayed modally to present the
|
||||
user with a message and one or more options.
|
||||
|
||||
@@ -74,41 +69,51 @@ var CPAlertWarningImage,
|
||||
@delegate -(void)alertDidEnd:(CPAlert)theAlert returnCode:(int)returnCode;
|
||||
Called when the user dismisses the alert by clicking one of the buttons.
|
||||
@param theAlert the alert panel that the user dismissed
|
||||
@param returnCode the index of the button that the user clicked (starting from 0,
|
||||
@param returnCode the index of the button that the user clicked (starting from 0,
|
||||
representing the first button added to the alert which appears on the
|
||||
right, 1 representing the next button to the left and so on)
|
||||
*/
|
||||
@implementation CPAlert : CPObject
|
||||
@implementation CPAlert : CPView
|
||||
{
|
||||
CPPanel _alertPanel;
|
||||
|
||||
CPTextField _messageLabel;
|
||||
CPTextField _informativeLabel;
|
||||
CPImageView _alertImageView;
|
||||
|
||||
CPAlertStyle _alertStyle;
|
||||
CPString _windowTitle;
|
||||
int _windowStyle;
|
||||
int _buttonCount;
|
||||
CPArray _buttons;
|
||||
|
||||
id _delegate;
|
||||
SEL _didEndSelector;
|
||||
id _modalDelegate;
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
+ (CPString)themeClass
|
||||
{
|
||||
if (self != CPAlert)
|
||||
return;
|
||||
return @"alert";
|
||||
}
|
||||
|
||||
var bundle = [CPBundle bundleForClass:[self class]];
|
||||
|
||||
CPAlertWarningImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPAlert/dialog-warning.png"]
|
||||
size:CGSizeMake(32.0, 32.0)];
|
||||
|
||||
CPAlertInformationImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPAlert/dialog-information.png"]
|
||||
size:CGSizeMake(32.0, 32.0)];
|
||||
|
||||
CPAlertErrorImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPAlert/dialog-error.png"]
|
||||
size:CGSizeMake(32.0, 32.0)];
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[CGSizeMake(400.0, 110.0), CGInsetMake(15, 15, 15, 50), 6, 10,
|
||||
CPJustifiedTextAlignment, [CPColor blackColor], [CPFont boldSystemFontOfSize:13.0], [CPNull null], CGSizeMakeZero(),
|
||||
CPJustifiedTextAlignment, [CPColor blackColor], [CPFont systemFontOfSize:12.0], [CPNull null], CGSizeMakeZero(),
|
||||
CGPointMake(15, 12),
|
||||
[CPNull null],
|
||||
[CPNull null],
|
||||
[CPNull null]
|
||||
]
|
||||
forKeys:[@"size", @"content-inset", @"informative-offset", @"button-offset",
|
||||
@"message-text-alignment", @"message-text-color", @"message-text-font", @"message-text-shadow-color", @"message-text-shadow-offset",
|
||||
@"informative-text-alignment", @"informative-text-color", @"informative-text-font", @"informative-text-shadow-color", @"informative-text-shadow-offset",
|
||||
@"image-offset",
|
||||
@"information-image",
|
||||
@"warning-image",
|
||||
@"error-image"
|
||||
]];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -118,57 +123,56 @@ var CPAlertWarningImage,
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
_buttonCount = 0;
|
||||
_buttons = [CPArray array];
|
||||
_alertStyle = CPWarningAlertStyle;
|
||||
_alertPanel = nil;
|
||||
_windowStyle = nil;
|
||||
_didEndSelector = nil;
|
||||
|
||||
[self setWindowStyle:nil];
|
||||
_messageLabel = [CPTextField labelWithTitle:@"Alert"];
|
||||
_alertImageView = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
|
||||
_informativeLabel = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the window appearance.
|
||||
Sets the window appearance. If CPHUDBackgroundWindowMask is set, the default HUD theme
|
||||
will be activated.
|
||||
|
||||
@param styleMask - Either CPHUDBackgroundWindowMask or nil for standard.
|
||||
*/
|
||||
- (void)setWindowStyle:(int)styleMask
|
||||
{
|
||||
_windowStyle = styleMask;
|
||||
|
||||
_alertPanel = [[CPPanel alloc] initWithContentRect:CGRectMake(0.0, 0.0, 400.0, 110.0) styleMask:styleMask ? styleMask | CPTitledWindowMask : CPTitledWindowMask];
|
||||
[_alertPanel setFloatingPanel:YES];
|
||||
[_alertPanel center];
|
||||
|
||||
[_messageLabel setTextColor:(styleMask & CPHUDBackgroundWindowMask) ? [CPColor whiteColor] : [CPColor blackColor]];
|
||||
[self setTheme:(_windowStyle & CPHUDBackgroundWindowMask) ? [CPTheme defaultHudTheme] : [CPTheme defaultTheme]];
|
||||
|
||||
var count = [_buttons count];
|
||||
for(var i=0; i < count; i++)
|
||||
// We'll need to recreate the panel to get the new window style.
|
||||
_alertPanel = nil;
|
||||
}
|
||||
|
||||
- (void)_createPanel
|
||||
{
|
||||
var frame = CGRectMakeZero();
|
||||
frame.size = [self currentValueForThemeAttribute:@"size"];
|
||||
_alertPanel = [[CPPanel alloc] initWithContentRect:frame styleMask:_windowStyle ? _windowStyle | CPTitledWindowMask : CPTitledWindowMask];
|
||||
|
||||
var contentView = [_alertPanel contentView],
|
||||
count = [_buttons count];
|
||||
|
||||
if (count)
|
||||
{
|
||||
var button = _buttons[i];
|
||||
|
||||
[button setFrameSize:CGSizeMake([button frame].size.width, (styleMask == CPHUDBackgroundWindowMask) ? 20.0 : 24.0)];
|
||||
|
||||
[button setTheme:(_windowStyle === CPHUDBackgroundWindowMask) ? [CPTheme themeNamed:"Aristo-HUD"] : [CPTheme defaultTheme]];
|
||||
|
||||
[[_alertPanel contentView] addSubview:button];
|
||||
while (count--)
|
||||
[contentView addSubview:_buttons[count]];
|
||||
}
|
||||
|
||||
if (!_messageLabel)
|
||||
{
|
||||
var bounds = [[_alertPanel contentView] bounds];
|
||||
else
|
||||
[self addButtonWithTitle:@"OK"];
|
||||
|
||||
_messageLabel = [[CPTextField alloc] initWithFrame:CGRectMake(57.0, 10.0, CGRectGetWidth(bounds) - 73.0, 62.0)];
|
||||
[_messageLabel setFont:[CPFont boldSystemFontOfSize:13.0]];
|
||||
[_messageLabel setLineBreakMode:CPLineBreakByWordWrapping];
|
||||
[_messageLabel setAlignment:CPJustifiedTextAlignment];
|
||||
[_messageLabel setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
|
||||
|
||||
_alertImageView = [[CPImageView alloc] initWithFrame:CGRectMake(15.0, 12.0, 32.0, 32.0)];
|
||||
}
|
||||
|
||||
[[_alertPanel contentView] addSubview:_messageLabel];
|
||||
[[_alertPanel contentView] addSubview:_alertImageView];
|
||||
[contentView addSubview:_messageLabel];
|
||||
[contentView addSubview:_alertImageView];
|
||||
[contentView addSubview:_informativeLabel];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -231,7 +235,7 @@ var CPAlertWarningImage,
|
||||
}
|
||||
|
||||
/*!
|
||||
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,14 +243,31 @@ var CPAlertWarningImage,
|
||||
[_messageLabel setStringValue:messageText];
|
||||
}
|
||||
|
||||
/*!
|
||||
Return's the receiver's message text body.
|
||||
/*!
|
||||
Returns the receiver's message text body.
|
||||
*/
|
||||
- (CPString)messageText
|
||||
{
|
||||
return [_messageLabel stringValue];
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the receiver's informative text, shown below the message text.
|
||||
@param informativeText - The informative text.
|
||||
*/
|
||||
- (void)setInformativeText:(CPString)informativeText
|
||||
{
|
||||
[_informativeLabel setStringValue:informativeText];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the receiver's informative text.
|
||||
*/
|
||||
- (CPString)informativeText
|
||||
{
|
||||
return [_informativeLabel stringValue];
|
||||
}
|
||||
|
||||
/*!
|
||||
Adds a button with a given title to the receiver.
|
||||
Buttons will be added starting from the right hand side of the \c CPAlert panel.
|
||||
@@ -260,25 +281,119 @@ var CPAlertWarningImage,
|
||||
- (void)addButtonWithTitle:(CPString)title
|
||||
{
|
||||
var bounds = [[_alertPanel contentView] bounds],
|
||||
button = [[CPButton alloc] initWithFrame:CGRectMake(CGRectGetWidth(bounds) - ((_buttonCount + 1) * 90.0), CGRectGetHeight(bounds) - 34.0, 80.0, (_windowStyle == CPHUDBackgroundWindowMask) ? 20.0 : 24.0)];
|
||||
|
||||
button = [[CPButton alloc] initWithFrame:CGRectMakeZero()],
|
||||
_buttonCount = [_buttons count];
|
||||
|
||||
[button setTitle:title];
|
||||
[button setTarget:self];
|
||||
[button setTag:_buttonCount];
|
||||
[button setAction:@selector(_notifyDelegate:)];
|
||||
|
||||
[button setTheme:(_windowStyle === CPHUDBackgroundWindowMask) ? [CPTheme themeNamed:"Aristo-HUD"] : [CPTheme defaultTheme]];
|
||||
[button setAutoresizingMask:CPViewMinXMargin | CPViewMinYMargin];
|
||||
[button setAction:@selector(_dismissAlert:)];
|
||||
|
||||
[[_alertPanel contentView] addSubview:button];
|
||||
|
||||
|
||||
if (_buttonCount == 0)
|
||||
[_alertPanel setDefaultButton:button];
|
||||
[button setKeyEquivalent:CPCarriageReturnCharacter];
|
||||
else if ([title lowercaseString] === "cancel")
|
||||
[button setKeyEquivalent:CPEscapeFunctionKey];
|
||||
else
|
||||
[button setKeyEquivalent:nil];
|
||||
|
||||
_buttonCount++;
|
||||
[_buttons addObject:button];
|
||||
[_buttons insertObject:button atIndex:0];
|
||||
}
|
||||
|
||||
- (void)layoutPanel
|
||||
{
|
||||
if (!_alertPanel)
|
||||
[self _createPanel];
|
||||
|
||||
var inset = [self currentValueForThemeAttribute:@"content-inset"],
|
||||
iconOffset = [self currentValueForThemeAttribute:@"image-offset"],
|
||||
theTitle,
|
||||
theImage;
|
||||
|
||||
switch (_alertStyle)
|
||||
{
|
||||
case CPWarningAlertStyle: theImage = [self currentValueForThemeAttribute:@"warning-image"];
|
||||
theTitle = @"Warning";
|
||||
break;
|
||||
case CPInformationalAlertStyle: theImage = [self currentValueForThemeAttribute:@"information-image"];
|
||||
theTitle = @"Information";
|
||||
break;
|
||||
case CPCriticalAlertStyle: theImage = [self currentValueForThemeAttribute:@"error-image"];
|
||||
theTitle = @"Error";
|
||||
break;
|
||||
}
|
||||
|
||||
[_alertImageView setImage:theImage];
|
||||
|
||||
var imageSize = theImage ? [theImage size] : CGSizeMakeZero();
|
||||
[_alertImageView setFrame:CGRectMake(iconOffset.x, iconOffset.y, imageSize.width, imageSize.height)];
|
||||
|
||||
[_alertPanel setTitle:_windowTitle ? _windowTitle : theTitle];
|
||||
[_alertPanel setFloatingPanel:YES];
|
||||
[_alertPanel center];
|
||||
|
||||
[_messageLabel setTextColor:[self currentValueForThemeAttribute:@"message-text-color"]];
|
||||
[_messageLabel setFont:[self currentValueForThemeAttribute:@"message-text-font"]];
|
||||
[_messageLabel setTextShadowColor:[self currentValueForThemeAttribute:@"message-text-shadow-color"]];
|
||||
[_messageLabel setTextShadowOffset:[self currentValueForThemeAttribute:@"message-text-shadow-offset"]];
|
||||
[_messageLabel setAlignment:[self currentValueForThemeAttribute:@"message-text-alignment"]];
|
||||
[_messageLabel setLineBreakMode:CPLineBreakByWordWrapping];
|
||||
|
||||
[_informativeLabel setTextColor:[self currentValueForThemeAttribute:@"informative-text-color"]];
|
||||
[_informativeLabel setFont:[self currentValueForThemeAttribute:@"informative-text-font"]];
|
||||
[_informativeLabel setTextShadowColor:[self currentValueForThemeAttribute:@"informative-text-shadow-color"]];
|
||||
[_informativeLabel setTextShadowOffset:[self currentValueForThemeAttribute:@"informative-text-shadow-offset"]];
|
||||
[_informativeLabel setLineBreakMode:CPLineBreakByWordWrapping];
|
||||
|
||||
// FIXME sizeWithFontCorrection shouldn't be needed.
|
||||
var bounds = [[_alertPanel contentView] bounds],
|
||||
offsetX = CGRectGetWidth(bounds) - inset.right,
|
||||
informativeOffset = [self currentValueForThemeAttribute:@"informative-offset"],
|
||||
buttonOffset = [self currentValueForThemeAttribute:@"button-offset"],
|
||||
|
||||
textWidth = offsetX - inset.left,
|
||||
messageSize = [([_messageLabel stringValue] || " ") sizeWithFont:[_messageLabel font] inWidth:textWidth],
|
||||
informationString = [_informativeLabel stringValue],
|
||||
informativeSize = [(informationString || " ") sizeWithFont:[_informativeLabel font] inWidth:textWidth],
|
||||
sizeWithFontCorrection = 6.0;
|
||||
|
||||
[_messageLabel setFrame:CGRectMake(inset.left, inset.top, textWidth, messageSize.height + sizeWithFontCorrection)];
|
||||
[_informativeLabel setFrame:CGRectMake(inset.left, CGRectGetMaxY([_messageLabel frame]) + informativeOffset, textWidth, informativeSize.height + sizeWithFontCorrection)];
|
||||
// Don't let an empty informative label partially cover the buttons.
|
||||
[_informativeLabel setHidden:!informationString];
|
||||
|
||||
var aRepresentativeButton = _buttons[0],
|
||||
buttonY = MAX(CGRectGetMaxY([_alertImageView frame]), CGRectGetMaxY(informationString ? [_informativeLabel frame] : [_messageLabel frame])) + buttonOffset; // the lower of the bottom of the text and the bottom of the icon.
|
||||
|
||||
[aRepresentativeButton setTheme:[self theme]];
|
||||
[aRepresentativeButton sizeToFit];
|
||||
|
||||
// Make the window just tall enough to fit everything. Bit of a hack really.
|
||||
var minimumSize = [self currentValueForThemeAttribute:@"size"],
|
||||
desiredHeight = MAX(minimumSize.height, buttonY + CGRectGetHeight([aRepresentativeButton bounds]) + inset.bottom),
|
||||
deltaY = desiredHeight - CGRectGetHeight(bounds),
|
||||
frameSize = CGSizeMakeCopy([_alertPanel frame].size);
|
||||
|
||||
frameSize.height += deltaY;
|
||||
[_alertPanel setFrameSize:frameSize];
|
||||
|
||||
var count = [_buttons count];
|
||||
|
||||
while (count--)
|
||||
{
|
||||
var button = _buttons[count];
|
||||
[button setTheme:[self theme]];
|
||||
[button sizeToFit];
|
||||
|
||||
var buttonBounds = [button bounds],
|
||||
width = MAX(80.0, CGRectGetWidth(buttonBounds)),
|
||||
height = CGRectGetHeight(buttonBounds);
|
||||
|
||||
offsetX -= width;
|
||||
[button setFrame:CGRectMake(offsetX, buttonY, width, height)];
|
||||
offsetX -= 10;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -288,34 +403,68 @@ var CPAlertWarningImage,
|
||||
*/
|
||||
- (void)runModal
|
||||
{
|
||||
var theTitle;
|
||||
|
||||
switch (_alertStyle)
|
||||
{
|
||||
case CPWarningAlertStyle: [_alertImageView setImage:CPAlertWarningImage];
|
||||
theTitle = @"Warning";
|
||||
break;
|
||||
case CPInformationalAlertStyle: [_alertImageView setImage:CPAlertInformationImage];
|
||||
theTitle = @"Information";
|
||||
break;
|
||||
case CPCriticalAlertStyle: [_alertImageView setImage:CPAlertErrorImage];
|
||||
theTitle = @"Error";
|
||||
break;
|
||||
}
|
||||
|
||||
[_alertPanel setTitle:_windowTitle ? _windowTitle : theTitle];
|
||||
|
||||
[self layoutPanel];
|
||||
[CPApp runModalForWindow:_alertPanel];
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (void)_notifyDelegate:(id)button
|
||||
{
|
||||
[CPApp abortModal];
|
||||
[_alertPanel close];
|
||||
/*!
|
||||
Runs the receiver modally as an alert sheet attached to a specified window.
|
||||
|
||||
if (_delegate && [_delegate respondsToSelector:@selector(alertDidEnd:returnCode:)])
|
||||
[_delegate alertDidEnd:self returnCode:[button tag]];
|
||||
@param window The parent window for the sheet.
|
||||
@param modalDelegate The delegate for the modal-dialog session.
|
||||
@param alertDidEndSelector Message the alert sends to modalDelegate after the sheet is dismissed.
|
||||
@param contextInfo Contextual data passed to modalDelegate in didEndSelector message.
|
||||
*/
|
||||
- (void)beginSheetModalForWindow:(CPWindow)window modalDelegate:(id)modalDelegate didEndSelector:(SEL)alertDidEndSelector contextInfo:(void)contextInfo
|
||||
{
|
||||
if (!(_windowStyle & CPDocModalWindowMask))
|
||||
[self setWindowStyle:CPDocModalWindowMask];
|
||||
[self layoutPanel];
|
||||
|
||||
_didEndSelector = alertDidEndSelector;
|
||||
_modalDelegate = modalDelegate;
|
||||
|
||||
[CPApp beginSheet:_alertPanel modalForWindow:window modalDelegate:self didEndSelector:@selector(_alertDidEnd:returnCode:contextInfo:) contextInfo:contextInfo];
|
||||
}
|
||||
|
||||
/*!
|
||||
Runs the receiver modally as an alert sheet attached to a specified window.
|
||||
|
||||
@param window The parent window for the sheet.
|
||||
*/
|
||||
- (void)beginSheetModalForWindow:(CPWindow)window
|
||||
{
|
||||
if (!(_windowStyle & CPDocModalWindowMask))
|
||||
[self setWindowStyle:CPDocModalWindowMask];
|
||||
[self layoutPanel];
|
||||
|
||||
[CPApp beginSheet:_alertPanel modalForWindow:window modalDelegate:self didEndSelector:@selector(_alertDidEnd:returnCode:contextInfo:) contextInfo:nil];
|
||||
}
|
||||
|
||||
- (void)_alertDidEnd:(CPWindow)aSheet returnCode:(CPInteger)returnCode contextInfo:(id)contextInfo
|
||||
{
|
||||
if ([_delegate respondsToSelector:@selector(alertDidEnd:returnCode:)])
|
||||
[_delegate alertDidEnd:self returnCode:returnCode];
|
||||
|
||||
if (_didEndSelector)
|
||||
objj_msgSend(_modalDelegate, _didEndSelector, self, returnCode, contextInfo);
|
||||
|
||||
_didEndSelector = nil;
|
||||
_modalDelegate = nil;
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (void)_dismissAlert:(CPButton)button
|
||||
{
|
||||
if ([_alertPanel isSheet])
|
||||
[CPApp endSheet:_alertPanel returnCode:[button tag]];
|
||||
else
|
||||
{
|
||||
[CPApp abortModal];
|
||||
[_alertPanel close];
|
||||
|
||||
[self _alertDidEnd:nil returnCode:[button tag] contextInfo:nil];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -108,6 +108,8 @@ CPRunContinuesResponse = -1002;
|
||||
CPImage _applicationIconImage;
|
||||
|
||||
CPPanel _aboutPanel;
|
||||
|
||||
CPThemeBlend _themeBlend @accessors(property=themeBlend);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -325,7 +327,9 @@ CPRunContinuesResponse = -1002;
|
||||
applicationVersion = [options objectForKey:@"ApplicationVersion"] || [mainInfo objectForKey:@"CPBundleShortVersionString"],
|
||||
copyright = [options objectForKey:@"Copyright"] || [mainInfo objectForKey:@"CPHumanReadableCopyright"];
|
||||
|
||||
var aboutPanelController = [[CPWindowController alloc] initWithWindowCibName:@"AboutPanel"],
|
||||
var aboutPanelPath = [[CPBundle bundleForClass:[CPWindowController class]] pathForResource:@"AboutPanel.cib"],
|
||||
aboutPanelController = [CPWindowController alloc],
|
||||
aboutPanelController = [aboutPanelController initWithWindowCibPath:aboutPanelPath owner:aboutPanelController],
|
||||
aboutPanel = [aboutPanelController window],
|
||||
contentView = [aboutPanel contentView],
|
||||
imageView = [contentView viewWithTag:1],
|
||||
@@ -859,6 +863,7 @@ CPRunContinuesResponse = -1002;
|
||||
}
|
||||
|
||||
[aWindow orderFront:self];
|
||||
[aSheet setPlatformWindow:[aWindow platformWindow]];
|
||||
[aWindow _attachSheet:aSheet modalDelegate:aModalDelegate didEndSelector:aDidEndSelector contextInfo:aContextInfo];
|
||||
}
|
||||
|
||||
@@ -1016,7 +1021,6 @@ CPRunContinuesResponse = -1002;
|
||||
|
||||
+ (CPString)defaultThemeName
|
||||
{
|
||||
// FIXME: don't hardcode
|
||||
return ([[CPBundle mainBundle] objectForInfoDictionaryKey:"CPDefaultTheme"] || @"Aristo");
|
||||
}
|
||||
|
||||
@@ -1032,7 +1036,8 @@ var _CPEventListenerMake = function(anEventMask, aCallback)
|
||||
return { _mask:anEventMask, _callback:aCallback };
|
||||
}
|
||||
|
||||
var _CPRunModalLoop = function(anEvent)
|
||||
// Make this a global for use in CPPlatformWindow+DOM.j.
|
||||
_CPRunModalLoop = function(anEvent)
|
||||
{
|
||||
[CPApp setCallback:_CPRunModalLoop forNextEventMatchingMask:CPAnyEventMask untilDate:nil inMode:0 dequeue:NO];
|
||||
|
||||
@@ -1110,8 +1115,15 @@ var _CPAppBootstrapperActions = nil;
|
||||
|
||||
+ (BOOL)loadDefaultTheme
|
||||
{
|
||||
var blend = [[CPThemeBlend alloc] initWithContentsOfURL:[[CPBundle bundleForClass:[CPApplication class]] pathForResource:[CPApplication defaultThemeName] + ".blend"]];
|
||||
var defaultThemeName = [CPApplication defaultThemeName],
|
||||
themeURL = nil;
|
||||
|
||||
if (defaultThemeName === @"Aristo")
|
||||
themeURL = [[CPBundle bundleForClass:[CPApplication class]] pathForResource:defaultThemeName + @".blend"];
|
||||
else
|
||||
themeURL = [[CPBundle mainBundle] pathForResource:defaultThemeName + @".blend"];
|
||||
|
||||
var blend = [[CPThemeBlend alloc] initWithContentsOfURL:themeURL];
|
||||
[blend loadWithDelegate:self];
|
||||
|
||||
return YES;
|
||||
@@ -1119,6 +1131,7 @@ var _CPAppBootstrapperActions = nil;
|
||||
|
||||
+ (void)blendDidFinishLoading:(CPThemeBlend)aThemeBlend
|
||||
{
|
||||
[[CPApplication sharedApplication] setThemeBlend:aThemeBlend];
|
||||
[CPTheme setDefaultTheme:[CPTheme themeNamed:[CPApplication defaultThemeName]]];
|
||||
|
||||
[self performActions];
|
||||
@@ -1216,7 +1229,7 @@ var _CPAppBootstrapperActions = nil;
|
||||
|
||||
+ (void)reset
|
||||
{
|
||||
_CPAppBootstrapperActions = nil;
|
||||
_CPAppBootstrapperActions = nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -58,22 +58,30 @@
|
||||
|
||||
+ (CPSet)keyPathsForValuesAffectingArrangedObjects
|
||||
{
|
||||
return [CPSet setWithObjects:"content", "contentArray", "contentSet", "filterPredicate", "sortDescriptors"];
|
||||
return [CPSet setWithObjects:"content", "filterPredicate", "sortDescriptors"];
|
||||
}
|
||||
|
||||
+ (CPSet)keyPathsForValuesAffectingSelection
|
||||
{
|
||||
return [CPSet setWithObjects:"content", "contentArray", "contentSet", "selectionIndexes"];
|
||||
return [CPSet setWithObjects:"selectionIndexes"];
|
||||
}
|
||||
|
||||
+ (CPSet)keyPathsForValuesAffectingSelectionIndex
|
||||
{
|
||||
return [CPSet setWithObjects:"content", "contentArray", "contentSet", "selectionIndexes", "selection"];
|
||||
return [CPSet setWithObjects:"selectionIndexes"];
|
||||
}
|
||||
|
||||
+ (CPSet)keyPathsForValuesAffectingSelectionIndexes
|
||||
{
|
||||
// When the arranged objects change, selection preservation may cause the indexes
|
||||
// to change.
|
||||
return [CPSet setWithObjects:"arrangedObjects"];
|
||||
}
|
||||
|
||||
+ (CPSet)keyPathsForValuesAffectingSelectedObjects
|
||||
{
|
||||
return [CPSet setWithObjects:"content", "contentArray", "contentSet", "selectionIndexes", "selection"];
|
||||
// Don't need to depend on arrangedObjects here because selectionIndexes already does.
|
||||
return [CPSet setWithObjects:"selectionIndexes"];
|
||||
}
|
||||
|
||||
+ (CPSet)keyPathsForValuesAffectingCanRemove
|
||||
@@ -91,16 +99,6 @@
|
||||
return [CPSet setWithObjects:"selectionIndexes"];
|
||||
}
|
||||
|
||||
+ (BOOL)automaticallyNotifiesObserversForKey:(CPString)aKey
|
||||
{
|
||||
if (![super automaticallyNotifiesObserversForKey:aKey])
|
||||
return NO;
|
||||
if (aKey === @"selectionIndexes")
|
||||
return NO;
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
@@ -153,31 +151,50 @@
|
||||
if(![value isKindOfClass:[CPArray class]])
|
||||
value = [value];
|
||||
|
||||
var oldSelection = nil,
|
||||
oldSelectionIndexes = [[self selectionIndexes] copy];
|
||||
var oldSelectedObjects = nil,
|
||||
oldSelectionIndexes = nil;
|
||||
|
||||
if ([self preservesSelection])
|
||||
oldSelection = [self selectedObjects];
|
||||
oldSelectedObjects = [self selectedObjects];
|
||||
else
|
||||
oldSelectionIndexes = [self selectionIndexes];
|
||||
|
||||
// Avoid out of bounds selections.
|
||||
_selectionIndexes = [CPIndexSet indexSet];
|
||||
//FIXME: copy?
|
||||
[super setContent:value];
|
||||
/*
|
||||
When the contents are changed, the selected indexes may no longer refer to the
|
||||
same items. This would cause problems when setSelectedObjects is called below.
|
||||
Any KVO observation would try to retrieve the 'before' value which could be
|
||||
wrong or even throw an exception for no longer existing indexes.
|
||||
|
||||
To avoid that, use the internal __setSelectedObjects which fires no notifications.
|
||||
The selectionIndexes notifications will fire later since they depend on the
|
||||
content key. This pattern is also applied for many other methods throughout this
|
||||
class.
|
||||
*/
|
||||
|
||||
if (_clearsFilterPredicateOnInsertion)
|
||||
[self willChangeValueForKey:@"filterPredicate"];
|
||||
|
||||
// Don't use [super setContent:] as that would fire the contentObject change.
|
||||
// We need to be in control of when notifications fire.
|
||||
_contentObject = value;
|
||||
|
||||
if(_clearsFilterPredicateOnInsertion)
|
||||
[self setFilterPredicate:nil];
|
||||
|
||||
[self rearrangeObjects];
|
||||
|
||||
if (oldSelection)
|
||||
[self setSelectedObjects:oldSelection];
|
||||
[self __setFilterPredicate:nil]; // Causes a _rearrangeObjects.
|
||||
else
|
||||
[self setSelectionIndexes:oldSelectionIndexes];
|
||||
[self _rearrangeObjects];
|
||||
|
||||
if ([self preservesSelection])
|
||||
[self __setSelectedObjects:oldSelectedObjects];
|
||||
else
|
||||
[self __setSelectionIndexes:oldSelectionIndexes];
|
||||
|
||||
if (_clearsFilterPredicateOnInsertion)
|
||||
[self didChangeValueForKey:@"filterPredicate"];
|
||||
}
|
||||
|
||||
- (void)_setContentArray:(id)anArray
|
||||
{
|
||||
[self setContent:anArray];
|
||||
[self setContent:anArray];
|
||||
}
|
||||
|
||||
- (void)_setContentSet:(id)aSet
|
||||
@@ -197,42 +214,57 @@
|
||||
|
||||
- (CPArray)arrangeObjects:(CPArray)objects
|
||||
{
|
||||
var sortedObjects = objects;
|
||||
var filterPredicate = [self filterPredicate],
|
||||
sortDescriptors = [self sortDescriptors];
|
||||
|
||||
if ([self filterPredicate])
|
||||
sortedObjects = [sortedObjects filteredArrayUsingPredicate:[self filterPredicate]];
|
||||
if ([self sortDescriptors])
|
||||
sortedObjects = [sortedObjects sortedArrayUsingDescriptors:[self sortDescriptors]];
|
||||
if (filterPredicate && sortDescriptors)
|
||||
{
|
||||
var sortedObjects = [objects filteredArrayUsingPredicate:filterPredicate];
|
||||
[sortedObjects sortUsingDescriptors:sortDescriptors];
|
||||
return sortedObjects;
|
||||
}
|
||||
else if (filterPredicate)
|
||||
return [objects filteredArrayUsingPredicate:filterPredicate];
|
||||
else if (sortDescriptors)
|
||||
return [objects sortedArrayUsingDescriptors:sortDescriptors];
|
||||
|
||||
return sortedObjects;
|
||||
return [objects copy];
|
||||
}
|
||||
|
||||
- (void)rearrangeObjects
|
||||
{
|
||||
// Rearranging reapplies the selection criteria and may cause objects to disappear,
|
||||
// so take care of the selection.
|
||||
//
|
||||
// Sometimes rearrangeObjects is called by setContent which may cause two rounds of
|
||||
// selection preservation. This is okay because setContent temporarily clears the
|
||||
// selection and so this code below ends up preserving nothing in that case.
|
||||
var oldSelection = nil,
|
||||
oldSelectionIndexes = [[self selectionIndexes] copy];
|
||||
|
||||
if ([self preservesSelection])
|
||||
oldSelection = [self selectedObjects];
|
||||
|
||||
// Avoid out of bounds selections.
|
||||
_selectionIndexes = [CPIndexSet indexSet];
|
||||
|
||||
[self _setArrangedObjects:[self arrangeObjects:[self contentArray]]];
|
||||
|
||||
if (oldSelection)
|
||||
[self setSelectedObjects:oldSelection];
|
||||
else
|
||||
[self setSelectionIndexes:oldSelectionIndexes];
|
||||
[self willChangeValueForKey:@"arrangedObjects"];
|
||||
[self _rearrangeObjects];
|
||||
[self didChangeValueForKey:@"arrangedObjects"];
|
||||
}
|
||||
|
||||
- (void)_setArrangedObjects:(id)value
|
||||
/*
|
||||
Like rearrangeObjects but don't fire any change notifications.
|
||||
@ignore
|
||||
*/
|
||||
- (void)_rearrangeObjects
|
||||
{
|
||||
/*
|
||||
Rearranging reapplies the selection criteria and may cause objects to disappear,
|
||||
so take care of the selection.
|
||||
*/
|
||||
var oldSelectedObjects = nil,
|
||||
oldSelectionIndexes = nil;
|
||||
|
||||
if ([self preservesSelection])
|
||||
oldSelectedObjects = [self selectedObjects];
|
||||
else
|
||||
oldSelectionIndexes = [self selectionIndexes];
|
||||
|
||||
[self __setArrangedObjects:[self arrangeObjects:[self contentArray]]];
|
||||
|
||||
if ([self preservesSelection])
|
||||
[self __setSelectedObjects:oldSelectedObjects];
|
||||
else
|
||||
[self __setSelectionIndexes:oldSelectionIndexes];
|
||||
}
|
||||
|
||||
- (void)__setArrangedObjects:(id)value
|
||||
{
|
||||
if (_arrangedObjects === value)
|
||||
return;
|
||||
@@ -245,7 +277,6 @@
|
||||
return _arrangedObjects;
|
||||
}
|
||||
|
||||
|
||||
- (CPArray)sortDescriptors
|
||||
{
|
||||
return _sortDescriptors;
|
||||
@@ -257,7 +288,9 @@
|
||||
return;
|
||||
|
||||
_sortDescriptors = [value copy];
|
||||
[self rearrangeObjects];
|
||||
// Use the non-notification version since arrangedObjects already depends
|
||||
// on sortDescriptors.
|
||||
[self _rearrangeObjects];
|
||||
}
|
||||
|
||||
- (CPPredicate)filterPredicate
|
||||
@@ -266,12 +299,23 @@
|
||||
}
|
||||
|
||||
- (void)setFilterPredicate:(CPPredicate)value
|
||||
{
|
||||
[self __setFilterPredicate:value];
|
||||
}
|
||||
|
||||
/*
|
||||
Like setFilterPredicate but don't fire any change notifications.
|
||||
@ignore
|
||||
*/
|
||||
- (void)__setFilterPredicate:(CPPredicate)value
|
||||
{
|
||||
if (_filterPredicate === value)
|
||||
return;
|
||||
|
||||
_filterPredicate = value;
|
||||
[self rearrangeObjects];
|
||||
// Use the non-notification version since arrangedObjects already depends
|
||||
// on filterPredicate.
|
||||
[self _rearrangeObjects];
|
||||
}
|
||||
|
||||
- (BOOL)alwaysUsesMultipleValuesMarker
|
||||
@@ -298,8 +342,26 @@
|
||||
|
||||
- (BOOL)setSelectionIndexes:(CPIndexSet)indexes
|
||||
{
|
||||
if ([_selectionIndexes isEqualToIndexSet:indexes])
|
||||
return NO;
|
||||
[self __setSelectionIndexes:indexes];
|
||||
}
|
||||
|
||||
/*
|
||||
Like setSelectionIndex but don't fire any change notifications.
|
||||
@ignore
|
||||
*/
|
||||
- (BOOL)__setSelectionIndex:(int)theIndex
|
||||
{
|
||||
[self __setSelectionIndexes:[CPIndexSet indexSetWithIndex:theIndex]];
|
||||
}
|
||||
|
||||
/*
|
||||
Like setSelectionIndexes but don't fire any change notifications.
|
||||
@ignore
|
||||
*/
|
||||
- (BOOL)__setSelectionIndexes:(CPIndexSet)indexes
|
||||
{
|
||||
if (!indexes)
|
||||
indexes = [CPIndexSet indexSet];
|
||||
|
||||
if (![indexes count])
|
||||
{
|
||||
@@ -316,14 +378,11 @@
|
||||
indexes = [CPIndexSet indexSetWithIndex:objectsCount-1];
|
||||
}
|
||||
|
||||
[self willChangeValueForKey:@"selectionIndexes"];
|
||||
[self _selectionWillChange];
|
||||
if ([_selectionIndexes isEqualToIndexSet:indexes])
|
||||
return NO;
|
||||
|
||||
_selectionIndexes = [indexes copy];
|
||||
|
||||
[self _selectionDidChange];
|
||||
[self didChangeValueForKey:@"selectionIndexes"];
|
||||
|
||||
// Push back the new selection to the model for selectionIndexes if we have one.
|
||||
// There won't be an infinite loop because of the equality check above.
|
||||
[[CPKeyValueBinding getBinding:@"selectionIndexes" forObject:self] reverseSetValueFor:@"selectionIndexes"];
|
||||
@@ -335,10 +394,25 @@
|
||||
{
|
||||
var objects = [[self arrangedObjects] objectsAtIndexes:[self selectionIndexes]];
|
||||
|
||||
return objects || [_CPObservableArray array];
|
||||
return [_CPObservableArray arrayWithArray:(objects || [])];
|
||||
}
|
||||
|
||||
- (BOOL)setSelectedObjects:(CPArray)objects
|
||||
{
|
||||
[self willChangeValueForKey:@"selectionIndexes"];
|
||||
[self _selectionWillChange];
|
||||
|
||||
[self __setSelectedObjects:objects];
|
||||
|
||||
[self didChangeValueForKey:@"selectionIndexes"];
|
||||
[self _selectionDidChange];
|
||||
}
|
||||
|
||||
/*
|
||||
Like setSelectedObjects but don't fire any change notifications.
|
||||
@ignore
|
||||
*/
|
||||
- (BOOL)__setSelectedObjects:(CPArray)objects
|
||||
{
|
||||
var set = [CPIndexSet indexSet],
|
||||
count = [objects count],
|
||||
@@ -352,35 +426,35 @@
|
||||
[set addIndex:index];
|
||||
}
|
||||
|
||||
[self setSelectionIndexes:set];
|
||||
[self __setSelectionIndexes:set];
|
||||
return YES;
|
||||
}
|
||||
|
||||
//Moving selection
|
||||
|
||||
-(BOOL)canSelectPrevious
|
||||
- (BOOL)canSelectPrevious
|
||||
{
|
||||
return [[self selectionIndexes] firstIndex] > 0
|
||||
}
|
||||
|
||||
-(BOOL)canSelectNext
|
||||
-(void)selectPrevious:(id)sender
|
||||
{
|
||||
return [[self selectionIndexes] firstIndex] < [[self arrangedObjects] count] -1;
|
||||
}
|
||||
var index = [[self selectionIndexes] firstIndex] - 1;
|
||||
|
||||
-(void)selectNext:(id)sender
|
||||
{
|
||||
var index = [[self selectionIndexes] firstIndex] + 1 || 0;
|
||||
|
||||
if (index < [[self arrangedObjects] count])
|
||||
if (index >= 0)
|
||||
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
|
||||
}
|
||||
|
||||
-(void)selectPrevious:(id)sender
|
||||
- (BOOL)canSelectNext
|
||||
{
|
||||
var index = [[self selectionIndexes] firstIndex] - 1 || [[self arrangedObjects] count] - 1;
|
||||
return [[self selectionIndexes] firstIndex] < [[self arrangedObjects] count] - 1;
|
||||
}
|
||||
|
||||
if (index >= 0)
|
||||
- (void)selectNext:(id)sender
|
||||
{
|
||||
var index = [[self selectionIndexes] firstIndex] + 1;
|
||||
|
||||
if (index < [[self arrangedObjects] count])
|
||||
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
|
||||
}
|
||||
|
||||
@@ -391,30 +465,63 @@
|
||||
if (![self canAdd])
|
||||
return;
|
||||
|
||||
if (_clearsFilterPredicateOnInsertion)
|
||||
[self willChangeValueForKey:@"filterPredicate"];
|
||||
|
||||
[self willChangeValueForKey:@"content"];
|
||||
[_contentObject addObject:object];
|
||||
[self didChangeValueForKey:@"content"];
|
||||
|
||||
if (_clearsFilterPredicateOnInsertion)
|
||||
[self setFilterPredicate:nil];
|
||||
[self __setFilterPredicate:nil];
|
||||
|
||||
if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:object])
|
||||
{
|
||||
var pos = [_arrangedObjects insertObject:object inArraySortedByDescriptors:_sortDescriptors];
|
||||
|
||||
// selectionIndexes change notification will be fired as a result of the
|
||||
// content change. Don't fire manually.
|
||||
if (_selectsInsertedObjects)
|
||||
{
|
||||
[self setSelectionIndex:pos];
|
||||
}
|
||||
[self __setSelectionIndex:pos];
|
||||
else
|
||||
{
|
||||
[self willChangeValueForKey:@"selectionIndexes"];
|
||||
[_selectionIndexes shiftIndexesStartingAtIndex:pos by:1];
|
||||
[self didChangeValueForKey:@"selectionIndexes"];
|
||||
}
|
||||
}
|
||||
else
|
||||
[self rearrangeObjects];
|
||||
[self _rearrangeObjects];
|
||||
|
||||
[self didChangeValueForKey:@"content"];
|
||||
if (_clearsFilterPredicateOnInsertion)
|
||||
[self didChangeValueForKey:@"filterPredicate"];
|
||||
}
|
||||
|
||||
- (void)insertObject:(id)anObject atArrangedObjectIndex:(int)anIndex
|
||||
{
|
||||
if (![self canAdd])
|
||||
return;
|
||||
|
||||
if (_clearsFilterPredicateOnInsertion)
|
||||
[self willChangeValueForKey:@"filterPredicate"];
|
||||
|
||||
[self willChangeValueForKey:@"content"];
|
||||
[_contentObject insertObject:anObject atIndex:anIndex];
|
||||
|
||||
if (_clearsFilterPredicateOnInsertion)
|
||||
[self __setFilterPredicate:nil];
|
||||
|
||||
[[self arrangedObjects] insertObject:anObject atIndex:anIndex];
|
||||
|
||||
// selectionIndexes change notification will be fired as a result of the
|
||||
// content change. Don't fire manually.
|
||||
if ([self selectsInsertedObjects])
|
||||
[self __setSelectionIndex:anIndex];
|
||||
else
|
||||
[[self selectionIndexes] shiftIndexesStartingAtIndex:anIndex by:1];
|
||||
|
||||
if ([self avoidsEmptySelection] && [[self selectionIndexes] count] <= 0 && [_contentObject count] > 0)
|
||||
[self __setSelectionIndexes:[CPIndexSet indexSetWithIndex:0]];
|
||||
|
||||
[self didChangeValueForKey:@"content"];
|
||||
if (_clearsFilterPredicateOnInsertion)
|
||||
[self didChangeValueForKey:@"filterPredicate"];
|
||||
}
|
||||
|
||||
- (void)removeObject:(id)object
|
||||
@@ -424,16 +531,18 @@
|
||||
|
||||
[self willChangeValueForKey:@"content"];
|
||||
[_contentObject removeObject:object];
|
||||
[self didChangeValueForKey:@"content"];
|
||||
|
||||
if ([_filterPredicate evaluateWithObject:object])
|
||||
if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:object])
|
||||
{
|
||||
[self willChangeValueForKey:@"selectionIndexes"];
|
||||
// selectionIndexes change notification will be fired as a result of the
|
||||
// content change. Don't fire manually.
|
||||
var pos = [_arrangedObjects indexOfObject:object];
|
||||
|
||||
[_arrangedObjects removeObjectAtIndex:pos];
|
||||
[_selectionIndexes shiftIndexesStartingAtIndex:pos by:-1];
|
||||
[self didChangeValueForKey:@"selectionIndexes"];
|
||||
}
|
||||
|
||||
[self didChangeValueForKey:@"content"];
|
||||
}
|
||||
|
||||
-(void)add:(id)sender
|
||||
@@ -489,13 +598,33 @@
|
||||
|
||||
- (void)_removeObjects:(CPArray)objects
|
||||
{
|
||||
var contentArray = [self contentArray],
|
||||
count = [objects count];
|
||||
[self willChangeValueForKey:@"content"];
|
||||
[_contentObject removeObjectsInArray:objects];
|
||||
|
||||
for (var i=0; i<count; i++)
|
||||
[contentArray removeObject:[objects objectAtIndex:i]];
|
||||
var arrangedObjects = [self arrangedObjects],
|
||||
position = [arrangedObjects indexOfObject:[objects objectAtIndex:0]];
|
||||
|
||||
[self setContent:contentArray];
|
||||
[arrangedObjects removeObjectsInArray:objects];
|
||||
|
||||
var objectsCount = [arrangedObjects count],
|
||||
selectionIndexes = [CPIndexSet indexSet];
|
||||
|
||||
if ([self preservesSelection] || [self avoidsEmptySelection])
|
||||
{
|
||||
selectionIndexes = [CPIndexSet indexSetWithIndex:position];
|
||||
|
||||
// Remove the selection if there are no objects
|
||||
if (objectsCount <= 0)
|
||||
selectionIndexes = [CPIndexSet indexSet];
|
||||
|
||||
// Shift selection to last object if position is out of bounds
|
||||
else if (position >= objectsCount)
|
||||
selectionIndexes = [CPIndexSet indexSetWithIndex:objectsCount - 1];
|
||||
}
|
||||
|
||||
_selectionIndexes = selectionIndexes;
|
||||
|
||||
[self didChangeValueForKey:@"content"];
|
||||
}
|
||||
|
||||
- (BOOL)canInsert
|
||||
|
||||
@@ -19,25 +19,25 @@
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
@import "CPView.j"
|
||||
|
||||
// CPBorderType
|
||||
CPNoBorder = 0;
|
||||
CPLineBorder = 1;
|
||||
CPLineBorder = 1;
|
||||
CPBezelBorder = 2;
|
||||
CPGrooveBorder = 3;
|
||||
|
||||
@implementation CPBox : CPView
|
||||
{
|
||||
CPBorderType _borderType;
|
||||
|
||||
|
||||
CPColor _borderColor;
|
||||
CPColor _fillColor;
|
||||
|
||||
|
||||
float _cornerRadius;
|
||||
float _borderWidth;
|
||||
|
||||
|
||||
CPSize _contentMargin;
|
||||
CPView _contentView;
|
||||
}
|
||||
@@ -50,18 +50,19 @@ CPGrooveBorder = 3;
|
||||
[box setFrameFromContentFrame:[aView frame]];
|
||||
|
||||
[enclosingView replaceSubview:aView with:box];
|
||||
|
||||
|
||||
[box setContentView:aView];
|
||||
|
||||
|
||||
return box;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CPRect)frameRect
|
||||
{
|
||||
self = [super initWithFrame:frameRect];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_borderType = CPBezelBorder;
|
||||
_fillColor = [CPColor clearColor];
|
||||
_borderColor = [CPColor blackColor];
|
||||
|
||||
@@ -69,7 +70,9 @@ CPGrooveBorder = 3;
|
||||
_contentMargin = CGSizeMake(0.0, 0.0);
|
||||
|
||||
_contentView = [[CPView alloc] initWithFrame:[self bounds]];
|
||||
[_contentView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
|
||||
|
||||
[self setAutoresizesSubviews:YES];
|
||||
[self addSubview:_contentView];
|
||||
}
|
||||
|
||||
@@ -161,9 +164,10 @@ CPGrooveBorder = 3;
|
||||
return;
|
||||
|
||||
[aView setFrame:CGRectInset([self bounds], _contentMargin.width + _borderWidth, _contentMargin.height + _borderWidth)];
|
||||
[aView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
|
||||
[self replaceSubview:_contentView with:aView];
|
||||
|
||||
_contentView = aView;
|
||||
|
||||
_contentView = aView;
|
||||
}
|
||||
|
||||
- (CPSize)contentViewMargins
|
||||
@@ -175,7 +179,7 @@ CPGrooveBorder = 3;
|
||||
{
|
||||
if(size.width < 0 || size.height < 0)
|
||||
[CPException raise:CPGenericException reason:@"Margins must be positive"];
|
||||
|
||||
|
||||
_contentMargin = CGSizeMakeCopy(size);
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
@@ -189,56 +193,97 @@ CPGrooveBorder = 3;
|
||||
- (void)sizeToFit
|
||||
{
|
||||
var contentFrame = [_contentView frame];
|
||||
|
||||
[self setFrameSize:CGSizeMake(contentFrame.size.width + _contentMargin.width * 2,
|
||||
|
||||
[self setFrameSize:CGSizeMake(contentFrame.size.width + _contentMargin.width * 2,
|
||||
contentFrame.size.height + _contentMargin.height * 2)];
|
||||
|
||||
|
||||
[_contentView setFrameOrigin:CGPointMake(_contentMargin.width, _contentMargin.height)];
|
||||
}
|
||||
|
||||
- (void)drawRect:(CPRect)rect
|
||||
{
|
||||
if (_borderType === CPNoBorder)
|
||||
return;
|
||||
|
||||
var bounds = [self bounds],
|
||||
aContext = [[CPGraphicsContext currentContext] graphicsPort],
|
||||
border2 = _borderWidth/2,
|
||||
context = [[CPGraphicsContext currentContext] graphicsPort];
|
||||
|
||||
strokeRect = CGRectMake(bounds.origin.x + border2,
|
||||
bounds.origin.y + border2,
|
||||
bounds.size.width - _borderWidth,
|
||||
bounds.size.height - _borderWidth),
|
||||
|
||||
fillRect = CGRectMake(bounds.origin.x + border2,
|
||||
bounds.origin.y + border2,
|
||||
bounds.size.width - _borderWidth,
|
||||
bounds.size.height - _borderWidth);
|
||||
CGContextSetFillColor(context, [self fillColor]);
|
||||
|
||||
CGContextSetFillColor(aContext, [self fillColor]);
|
||||
CGContextSetStrokeColor(aContext, [self borderColor]);
|
||||
CGContextSetLineWidth(aContext, _borderWidth);
|
||||
|
||||
switch(_borderType)
|
||||
switch (_borderType)
|
||||
{
|
||||
case CPLineBorder: CGContextFillRoundedRectangleInRect(aContext, fillRect, _cornerRadius, YES, YES, YES, YES);
|
||||
CGContextStrokeRoundedRectangleInRect(aContext, strokeRect, _cornerRadius, YES, YES, YES, YES);
|
||||
break;
|
||||
case CPBezelBorder:
|
||||
var sides = [CPMinYEdge, CPMaxXEdge, CPMaxYEdge, CPMinXEdge],
|
||||
sideGray = 190.0 / 255.0,
|
||||
grays = [142.0 / 255.0, sideGray, sideGray, sideGray],
|
||||
borderWidth = _borderWidth;
|
||||
|
||||
case CPBezelBorder: CGContextFillRoundedRectangleInRect(aContext, fillRect, _cornerRadius, YES, YES, YES, YES);
|
||||
CGContextSetStrokeColor(aContext, [CPColor colorWithWhite:190.0/255.0 alpha:1.0]);
|
||||
CGContextBeginPath(aContext);
|
||||
CGContextMoveToPoint(aContext, strokeRect.origin.x, strokeRect.origin.y);
|
||||
CGContextAddLineToPoint(aContext, CGRectGetMinX(strokeRect), CGRectGetMaxY(strokeRect)),
|
||||
CGContextAddLineToPoint(aContext, CGRectGetMaxX(strokeRect), CGRectGetMaxY(strokeRect)),
|
||||
CGContextAddLineToPoint(aContext, CGRectGetMaxX(strokeRect), CGRectGetMinY(strokeRect)),
|
||||
CGContextStrokePath(aContext);
|
||||
CGContextSetStrokeColor(aContext, [CPColor colorWithWhite:142.0/255.0 alpha:1.0]);
|
||||
CGContextBeginPath(aContext);
|
||||
CGContextMoveToPoint(aContext, bounds.origin.x, strokeRect.origin.y);
|
||||
CGContextAddLineToPoint(aContext, CGRectGetMaxX(bounds), CGRectGetMinY(strokeRect));
|
||||
CGContextStrokePath(aContext);
|
||||
break;
|
||||
while (borderWidth--)
|
||||
bounds = CPDrawTiledRects(bounds, bounds, sides, grays);
|
||||
|
||||
default: break;
|
||||
CGContextFillRect(context, bounds);
|
||||
break;
|
||||
|
||||
default:
|
||||
bounds = CGRectInset(bounds, _borderWidth / 2.0, _borderWidth / 2.0);
|
||||
|
||||
CGContextSetStrokeColor(context, [self borderColor]);
|
||||
CGContextSetLineWidth(context, _borderWidth);
|
||||
CGContextFillRoundedRectangleInRect(context, bounds, _cornerRadius, YES, YES, YES, YES);
|
||||
CGContextStrokeRoundedRectangleInRect(context, bounds, _cornerRadius, YES, YES, YES, YES);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPBoxBorderTypeKey = @"CPBoxBorderTypeKey",
|
||||
CPBoxBorderColorKey = @"CPBoxBorderColorKey",
|
||||
CPBoxFillColorKey = @"CPBoxFillColorKey",
|
||||
CPBoxCornerRadiusKey = @"CPBoxCornerRadiusKey",
|
||||
CPBoxBorderWidthKey = @"CPBoxBorderWidthKey",
|
||||
CPBoxContentMarginKey = @"CPBoxContentMarginKey";
|
||||
|
||||
@implementation CPBox (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_borderType = [aCoder decodeIntForKey:CPBoxBorderTypeKey];
|
||||
|
||||
_borderColor = [aCoder decodeObjectForKey:CPBoxBorderColorKey];
|
||||
_fillColor = [aCoder decodeObjectForKey:CPBoxFillColorKey];
|
||||
|
||||
_cornerRadius = [aCoder decodeFloatForKey:CPBoxCornerRadiusKey];
|
||||
_borderWidth = [aCoder decodeFloatForKey:CPBoxBorderWidthKey];
|
||||
|
||||
_contentMargin = [aCoder decodeSizeForKey:CPBoxContentMarginKey];
|
||||
|
||||
_contentView = [self subviews][0];
|
||||
|
||||
[self setAutoresizesSubviews:YES];
|
||||
[_contentView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[aCoder encodeInt:_borderType forKey:CPBoxBorderTypeKey];
|
||||
|
||||
[aCoder encodeObject:_borderColor forKey:CPBoxBorderColorKey];
|
||||
[aCoder encodeObject:_fillColor forKey:CPBoxFillColorKey];
|
||||
|
||||
[aCoder encodeFloat:_cornerRadius forKey:CPBoxCornerRadiusKey];
|
||||
[aCoder encodeFloat:_borderWidth forKey:CPBoxBorderWidthKey];
|
||||
|
||||
[aCoder encodeSize:_contentMargin forKey:CPBoxContentMarginKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -74,6 +74,9 @@ CPChangeBackgroundCellMask = CPBackgroundButtonMask;
|
||||
|
||||
CPButtonStateMixed = CPThemeState("mixed");
|
||||
|
||||
CPButtonDefaultHeight = 24.0;
|
||||
CPButtonImageOffset = 3.0;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPButton
|
||||
@@ -89,9 +92,6 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
CPString _title;
|
||||
CPString _alternateTitle;
|
||||
|
||||
CPImage _image;
|
||||
CPImage _alternateImage;
|
||||
|
||||
CPInteger _showsStateBy;
|
||||
CPInteger _highlightsBy;
|
||||
BOOL _imageDimsWhenDisabled;
|
||||
@@ -127,8 +127,8 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[_CGInsetMakeZero(), _CGInsetMakeZero(), [CPNull null]]
|
||||
forKeys:[@"bezel-inset", @"content-inset", @"bezel-color"]];
|
||||
return [CPDictionary dictionaryWithObjects:[[CPNull null], 0.0, _CGInsetMakeZero(), _CGInsetMakeZero(), [CPNull null]]
|
||||
forKeys:[@"image", @"image-offset", @"bezel-inset", @"content-inset", @"bezel-color"]];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
@@ -145,7 +145,7 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
|
||||
_controlSize = CPRegularControlSize;
|
||||
|
||||
_keyEquivalent = "";
|
||||
_keyEquivalent = @"";
|
||||
_keyEquivalentModifierMask = 0;
|
||||
|
||||
// [self setBezelStyle:CPRoundRectBezelStyle];
|
||||
@@ -284,18 +284,12 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
|
||||
- (void)setImage:(CPImage)anImage
|
||||
{
|
||||
if (_image === anImage)
|
||||
return;
|
||||
|
||||
_image = anImage;
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
[self setValue:anImage forThemeAttribute:@"image"];
|
||||
}
|
||||
|
||||
- (CPImage)image
|
||||
{
|
||||
return _image;
|
||||
return [self valueForThemeAttribute:@"image" inState:CPThemeStateNormal];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -304,13 +298,7 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
*/
|
||||
- (void)setAlternateImage:(CPImage)anImage
|
||||
{
|
||||
if (_alternateImage === anImage)
|
||||
return;
|
||||
|
||||
_alternateImage = anImage;
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
[self setValue:anImage forThemeAttribute:@"image" inState:CPThemeStateHighlighted];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -318,7 +306,17 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
*/
|
||||
- (CPImage)alternateImage
|
||||
{
|
||||
return _alternateImage;
|
||||
return [self valueForThemeAttribute:@"image" inState:CPThemeStateHighlighted];
|
||||
}
|
||||
|
||||
- (void)setImageOffset:(float)theImageOffset
|
||||
{
|
||||
[self setValue:theImageOffset forThemeAttribute:@"image-offset"];
|
||||
}
|
||||
|
||||
- (float)imageOffset
|
||||
{
|
||||
return [self valueForThemeAttribute:@"image-offset"];
|
||||
}
|
||||
|
||||
- (void)setShowsStateBy:(CPInteger)aMask
|
||||
@@ -468,8 +466,20 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
*/
|
||||
- (void)sizeToFit
|
||||
{
|
||||
var size = [([self title] || " ") sizeWithFont:[self currentValueForThemeAttribute:@"font"]],
|
||||
contentInset = [self currentValueForThemeAttribute:@"content-inset"],
|
||||
[self layoutSubviews];
|
||||
|
||||
var size,
|
||||
contentView = [self ephemeralSubviewNamed:@"content-view"];
|
||||
|
||||
if (contentView)
|
||||
{
|
||||
[contentView sizeToFit];
|
||||
size = [contentView frameSize];
|
||||
}
|
||||
else
|
||||
size = [([self title] || " ") sizeWithFont:[self currentValueForThemeAttribute:@"font"]];
|
||||
|
||||
var contentInset = [self currentValueForThemeAttribute:@"content-inset"],
|
||||
minSize = [self currentValueForThemeAttribute:@"min-size"],
|
||||
maxSize = [self currentValueForThemeAttribute:@"max-size"];
|
||||
|
||||
@@ -525,7 +535,8 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
if (contentView)
|
||||
{
|
||||
[contentView setText:([self hasThemeState:CPThemeStateHighlighted] && _alternateTitle) ? _alternateTitle : _title];
|
||||
[contentView setImage:([self hasThemeState:CPThemeStateHighlighted] && _alternateImage) ? _alternateImage : _image];
|
||||
[contentView setImage:[self currentValueForThemeAttribute:@"image"]];
|
||||
[contentView setImageOffset:[self currentValueForThemeAttribute:@"image-offset"]];
|
||||
|
||||
[contentView setFont:[self currentValueForThemeAttribute:@"font"]];
|
||||
[contentView setTextColor:[self currentValueForThemeAttribute:@"text-color"]];
|
||||
@@ -540,14 +551,6 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setDefaultButton:(BOOL)shouldBeDefaultButton
|
||||
{
|
||||
if (shouldBeDefaultButton)
|
||||
[self setThemeState:CPThemeStateDefault];
|
||||
else
|
||||
[self unsetThemeState:CPThemeStateDefault];
|
||||
}
|
||||
|
||||
- (void)setBordered:(BOOL)shouldBeBordered
|
||||
{
|
||||
if (shouldBeBordered)
|
||||
@@ -570,6 +573,27 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
- (void)setKeyEquivalent:(CPString)aString
|
||||
{
|
||||
_keyEquivalent = aString || @"";
|
||||
|
||||
// Check if the key equivalent is the enter key
|
||||
// Treat \r and \n as the same key equivalent. See issue #710.
|
||||
if (aString === CPNewlineCharacter || aString === CPCarriageReturnCharacter)
|
||||
[self setThemeState:CPThemeStateDefault];
|
||||
else
|
||||
[self unsetThemeState:CPThemeStateDefault];
|
||||
}
|
||||
|
||||
- (void)viewWillMoveToWindow:(CPWindow)aWindow
|
||||
{
|
||||
var selfWindow = [self window];
|
||||
|
||||
if (selfWindow === aWindow || aWindow === nil)
|
||||
return;
|
||||
|
||||
if ([selfWindow defaultButton] === self)
|
||||
[selfWindow setDefaultButton:nil];
|
||||
|
||||
if ([self keyEquivalent] === CPNewlineCharacter || [self keyEquivalent] === CPCarriageReturnCharacter)
|
||||
[aWindow setDefaultButton:self];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -602,6 +626,10 @@ CPButtonStateMixed = CPThemeState("mixed");
|
||||
*/
|
||||
- (BOOL)performKeyEquivalent:(CPEvent)anEvent
|
||||
{
|
||||
// Don't handle the key equivalent for the default window because the window will handle it for us
|
||||
if ([[self window] defaultButton] === self)
|
||||
return NO;
|
||||
|
||||
if (![anEvent _triggersKeyEquivalent:[self keyEquivalent] withModifierMask:[self keyEquivalentModifierMask]])
|
||||
return NO;
|
||||
|
||||
@@ -629,7 +657,11 @@ var CPButtonImageKey = @"CPButtonImageKey",
|
||||
CPButtonTitleKey = @"CPButtonTitleKey",
|
||||
CPButtonAlternateTitleKey = @"CPButtonAlternateTitleKey",
|
||||
CPButtonIsBorderedKey = @"CPButtonIsBorderedKey",
|
||||
CPButtonImageDimsWhenDisabledKey = @"CPButtonImageDimsWhenDisabledKey";
|
||||
CPButtonAllowsMixedStateKey = @"CPButtonAllowsMixedStateKey",
|
||||
CPButtonImageDimsWhenDisabledKey = @"CPButtonImageDimsWhenDisabledKey",
|
||||
CPButtonImagePositionKey = @"CPButtonImagePositionKey",
|
||||
CPButtonKeyEquivalentKey = @"CPButtonKeyEquivalentKey",
|
||||
CPButtonKeyEquivalentMaskKey = @"CPButtonKeyEquivalentMaskKey";
|
||||
|
||||
@implementation CPButton (CPCoding)
|
||||
|
||||
@@ -645,14 +677,22 @@ var CPButtonImageKey = @"CPButtonImageKey",
|
||||
{
|
||||
_controlSize = CPRegularControlSize;
|
||||
|
||||
[self setImage:[aCoder decodeObjectForKey:CPButtonImageKey]];
|
||||
[self setAlternateImage:[aCoder decodeObjectForKey:CPButtonAlternateImageKey]];
|
||||
_title = [aCoder decodeObjectForKey:CPButtonTitleKey];
|
||||
_alternateTitle = [aCoder decodeObjectForKey:CPButtonAlternateTitleKey];
|
||||
|
||||
[self setTitle:[aCoder decodeObjectForKey:CPButtonTitleKey]];
|
||||
[self setAlternateTitle:[aCoder decodeObjectForKey:CPButtonAlternateTitleKey]];
|
||||
if ([aCoder containsValueForKey:CPButtonAllowsMixedStateKey])
|
||||
_allowsMixedState = [aCoder decodeBoolForKey:CPButtonAllowsMixedStateKey];
|
||||
|
||||
[self setImageDimsWhenDisabled:[aCoder decodeObjectForKey:CPButtonImageDimsWhenDisabledKey]];
|
||||
|
||||
if ([aCoder containsValueForKey:CPButtonImagePositionKey])
|
||||
[self setImagePosition:[aCoder decodeIntForKey:CPButtonImagePositionKey]];
|
||||
|
||||
if ([aCoder containsValueForKey:CPButtonKeyEquivalentKey])
|
||||
[self setKeyEquivalent:CFData.decodeBase64ToUtf16String([aCoder decodeObjectForKey:CPButtonKeyEquivalentKey])];
|
||||
|
||||
_keyEquivalentModifierMask = [aCoder decodeIntForKey:CPButtonKeyEquivalentMaskKey];
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
@@ -668,13 +708,18 @@ var CPButtonImageKey = @"CPButtonImageKey",
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[aCoder encodeObject:_image forKey:CPButtonImageKey];
|
||||
[aCoder encodeObject:_alternateImage forKey:CPButtonAlternateImageKey];
|
||||
|
||||
[aCoder encodeObject:_title forKey:CPButtonTitleKey];
|
||||
[aCoder encodeObject:_alternateTitle forKey:CPButtonAlternateTitleKey];
|
||||
|
||||
[aCoder encodeObject:[self imageDimsWhenDisabled] forKey:CPButtonImageDimsWhenDisabledKey];
|
||||
[aCoder encodeBool:_allowsMixedState forKey:CPButtonAllowsMixedStateKey];
|
||||
|
||||
[aCoder encodeBool:[self imageDimsWhenDisabled] forKey:CPButtonImageDimsWhenDisabledKey];
|
||||
[aCoder encodeInt:[self imagePosition] forKey:CPButtonImagePositionKey];
|
||||
|
||||
if (_keyEquivalent)
|
||||
[aCoder encodeObject:CFData.encodeBase64Utf16String(_keyEquivalent) forKey:CPButtonKeyEquivalentKey];
|
||||
|
||||
[aCoder encodeInt:_keyEquivalentModifierMask forKey:CPButtonKeyEquivalentMaskKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
@import "CPButton.j"
|
||||
|
||||
CPCheckBoxImageOffset = 4.0;
|
||||
|
||||
@implementation CPCheckBox : CPButton
|
||||
{
|
||||
@@ -55,7 +56,7 @@
|
||||
[self setImagePosition:CPImageLeft];
|
||||
[self setAlignment:CPLeftTextAlignment];
|
||||
|
||||
[self setBordered:YES];
|
||||
[self setBordered:NO];
|
||||
}
|
||||
|
||||
return self;
|
||||
|
||||
@@ -297,7 +297,7 @@
|
||||
*/
|
||||
- (void)setSelectionIndexes:(CPIndexSet)anIndexSet
|
||||
{
|
||||
if (_selectionIndexes == anIndexSet || !_isSelectable)
|
||||
if ([_selectionIndexes isEqual:anIndexSet] || !_isSelectable)
|
||||
return;
|
||||
|
||||
var index = CPNotFound;
|
||||
@@ -312,8 +312,10 @@
|
||||
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound)
|
||||
[_items[index] setSelected:YES];
|
||||
|
||||
[[CPKeyValueBinding getBinding:@"selectionIndexes" forObject:self] reverseSetValueFor:@"selectionIndexes"];
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(collectionViewDidChangeSelection:)])
|
||||
[_delegate collectionViewDidChangeSelection:self]
|
||||
[_delegate collectionViewDidChangeSelection:self];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -737,9 +739,12 @@
|
||||
@end
|
||||
|
||||
@implementation CPCollectionView (KeyboardInteraction)
|
||||
- (CPIndexSet)_selectionForEvent:(CPEvent)anEvent withNewIndex:(int)anIndex direction:(int)aDirection
|
||||
|
||||
- (void)_modifySelectionWithNewIndex:(int)anIndex direction:(int)aDirection expand:(BOOL)shouldExpand
|
||||
{
|
||||
if (_allowsMultipleSelection && [anEvent modifierFlags] & CPShiftKeyMask)
|
||||
anIndex = MIN(MAX(anIndex, 0), [[self items] count]-1);
|
||||
|
||||
if (_allowsMultipleSelection && shouldExpand)
|
||||
{
|
||||
var indexes = [_selectionIndexes copy],
|
||||
bottomAnchor = [indexes firstIndex],
|
||||
@@ -754,7 +759,8 @@
|
||||
else
|
||||
indexes = [CPIndexSet indexSetWithIndex:anIndex];
|
||||
|
||||
return indexes;
|
||||
[self setSelectionIndexes:indexes];
|
||||
[self _scrollToSelection];
|
||||
}
|
||||
|
||||
- (void)_scrollToSelection
|
||||
@@ -771,26 +777,36 @@
|
||||
if (index === CPNotFound)
|
||||
index = [[self items] count];
|
||||
|
||||
index = MAX(index - 1, 0);
|
||||
[self _modifySelectionWithNewIndex:index - 1 direction:-1 expand:NO];
|
||||
}
|
||||
|
||||
[self setSelectionIndexes:[self _selectionForEvent:[CPApp currentEvent] withNewIndex:index direction:-1]];
|
||||
[self _scrollToSelection];
|
||||
- (void)moveLeftAndModifySelection:(id)sender
|
||||
{
|
||||
var index = [[self selectionIndexes] firstIndex];
|
||||
if (index === CPNotFound)
|
||||
index = [[self items] count];
|
||||
|
||||
[self _modifySelectionWithNewIndex:index - 1 direction:-1 expand:YES];
|
||||
}
|
||||
|
||||
- (void)moveRight:(id)sender
|
||||
{
|
||||
var index = MIN([[self selectionIndexes] lastIndex] + 1, [[self items] count]-1);
|
||||
[self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + 1 direction:1 expand:NO];
|
||||
}
|
||||
|
||||
[self setSelectionIndexes:[self _selectionForEvent:[CPApp currentEvent] withNewIndex:index direction:1]];
|
||||
[self _scrollToSelection];
|
||||
- (void)moveRightAndModifySelection:(id)sender
|
||||
{
|
||||
[self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + 1 direction:1 expand:YES];
|
||||
}
|
||||
|
||||
- (void)moveDown:(id)sender
|
||||
{
|
||||
var index = MIN([[self selectionIndexes] lastIndex] + [self numberOfColumns], [[self items] count]-1);
|
||||
[self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + [self numberOfColumns] direction:1 expand:NO];
|
||||
}
|
||||
|
||||
[self setSelectionIndexes:[self _selectionForEvent:[CPApp currentEvent] withNewIndex:index direction:1]];
|
||||
[self _scrollToSelection];
|
||||
- (void)moveDownAndModifySelection:(id)sender
|
||||
{
|
||||
[self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + [self numberOfColumns] direction:1 expand:YES];
|
||||
}
|
||||
|
||||
- (void)moveUp:(id)sender
|
||||
@@ -799,10 +815,16 @@
|
||||
if (index == CPNotFound)
|
||||
index = [[self items] count];
|
||||
|
||||
index = MAX(0, index - [self numberOfColumns]);
|
||||
[self _modifySelectionWithNewIndex:index - [self numberOfColumns] direction:-1 expand:NO];
|
||||
}
|
||||
|
||||
[self setSelectionIndexes:[self _selectionForEvent:[CPApp currentEvent] withNewIndex:index direction:-1]];
|
||||
[self _scrollToSelection];
|
||||
- (void)moveUpAndModifySelection:(id)sender
|
||||
{
|
||||
var index = [[self selectionIndexes] firstIndex];
|
||||
if (index == CPNotFound)
|
||||
index = [[self items] count];
|
||||
|
||||
[self _modifySelectionWithNewIndex:index - [self numberOfColumns] direction:-1 expand:YES];
|
||||
}
|
||||
|
||||
- (void)deleteBackward:(id)sender
|
||||
@@ -847,11 +869,13 @@
|
||||
|
||||
@end
|
||||
|
||||
var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
|
||||
CPCollectionViewMaxItemSizeKey = @"CPCollectionViewMaxItemSizeKey",
|
||||
CPCollectionViewVerticalMarginKey = @"CPCollectionViewVerticalMarginKey",
|
||||
CPCollectionViewSelectableKey = @"CPCollectionViewSelectableKey",
|
||||
CPCollectionViewBackgroundColorsKey = @"CPCollectionViewBackgroundColorsKey";
|
||||
var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
|
||||
CPCollectionViewMaxItemSizeKey = @"CPCollectionViewMaxItemSizeKey",
|
||||
CPCollectionViewVerticalMarginKey = @"CPCollectionViewVerticalMarginKey",
|
||||
CPCollectionViewMaxNumberOfRowsKey = @"CPCollectionViewMaxNumberOfRowsKey",
|
||||
CPCollectionViewMaxNumberOfColumnsKey = @"CPCollectionViewMaxNumberOfColumnsKey",
|
||||
CPCollectionViewSelectableKey = @"CPCollectionViewSelectableKey",
|
||||
CPCollectionViewBackgroundColorsKey = @"CPCollectionViewBackgroundColorsKey";
|
||||
|
||||
|
||||
@implementation CPCollectionView (CPCoding)
|
||||
@@ -872,6 +896,9 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
|
||||
_minItemSize = [aCoder decodeSizeForKey:CPCollectionViewMinItemSizeKey] || CGSizeMakeZero();
|
||||
_maxItemSize = [aCoder decodeSizeForKey:CPCollectionViewMaxItemSizeKey] || CGSizeMakeZero();
|
||||
|
||||
_maxNumberOfRows = [aCoder decodeIntForKey:CPCollectionViewMaxNumberOfRowsKey] || 0;
|
||||
_maxNumberOfColumns = [aCoder decodeIntForKey:CPCollectionViewMaxNumberOfColumnsKey] || 0;
|
||||
|
||||
_verticalMargin = [aCoder decodeFloatForKey:CPCollectionViewVerticalMarginKey];
|
||||
|
||||
_isSelectable = [aCoder decodeBoolForKey:CPCollectionViewSelectableKey];
|
||||
@@ -898,6 +925,9 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
|
||||
if (!CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero()))
|
||||
[aCoder encodeSize:_maxItemSize forKey:CPCollectionViewMaxItemSizeKey];
|
||||
|
||||
[aCoder encodeInt:_maxNumberOfRows forKey:CPCollectionViewMaxNumberOfRowsKey];
|
||||
[aCoder encodeInt:_maxNumberOfColumns forKey:CPCollectionViewMaxNumberOfColumnsKey];
|
||||
|
||||
[aCoder encodeBool:_isSelectable forKey:CPCollectionViewSelectableKey];
|
||||
|
||||
[aCoder encodeFloat:_verticalMargin forKey:CPCollectionViewVerticalMarginKey];
|
||||
|
||||
@@ -56,18 +56,12 @@ var cachedBlackColor,
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@code CPColor
|
||||
|
||||
\c CPColor can be used to represent color
|
||||
in an RGB or HSB model with an optional transparency value.</p>
|
||||
|
||||
<p>It also provides some class helper methods that
|
||||
returns instances of commonly used colors.</p>
|
||||
|
||||
<p>The class does not have a \c -set: method
|
||||
like NextStep based frameworks to change the color of
|
||||
the current context. To change the color of the current
|
||||
context, use CGContextSetFillColor().
|
||||
*/
|
||||
@implementation CPColor : CPObject
|
||||
{
|
||||
@@ -82,12 +76,12 @@ var cachedBlackColor,
|
||||
Each component should be between the range of 0.0 to 1.0. For
|
||||
the alpha component, a value of 1.0 is opaque, and 0.0 means
|
||||
completely transparent.
|
||||
|
||||
|
||||
@param red the red component of the color
|
||||
@param green the green component of the color
|
||||
@param blue the blue component of the color
|
||||
@param alpha the alpha component
|
||||
|
||||
|
||||
@return a color initialized to the values specified
|
||||
*/
|
||||
+ (CPColor)colorWithRed:(float)red green:(float)green blue:(float)blue alpha:(float)alpha
|
||||
@@ -97,17 +91,17 @@ var cachedBlackColor,
|
||||
|
||||
/*!
|
||||
@deprecated in favor of colorWithRed:green:blue:alpha:
|
||||
|
||||
|
||||
Creates a color in the RGB color space, with an alpha value.
|
||||
Each component should be between the range of 0.0 to 1.0. For
|
||||
the alpha component, a value of 1.0 is opaque, and 0.0 means
|
||||
completely transparent.
|
||||
|
||||
|
||||
@param red the red component of the color
|
||||
@param green the green component of the color
|
||||
@param blue the blue component of the color
|
||||
@param alpha the alpha component
|
||||
|
||||
|
||||
@return a color initialized to the values specified
|
||||
*/
|
||||
+ (CPColor)colorWithCalibratedRed:(float)red green:(float)green blue:(float)blue alpha:(float)alpha
|
||||
@@ -119,10 +113,10 @@ var cachedBlackColor,
|
||||
/*!
|
||||
Creates a new color object with \c white for the RGB components.
|
||||
For the alpha component, a value of 1.0 is opaque, and 0.0 means completely transparent.
|
||||
|
||||
|
||||
@param white a float between 0.0 and 1.0
|
||||
@param alpha the alpha component between 0.0 and 1.0
|
||||
|
||||
|
||||
@return a color initialized to the values specified
|
||||
*/
|
||||
+ (CPColor)colorWithWhite:(float)white alpha:(float)alpha
|
||||
@@ -132,13 +126,13 @@ var cachedBlackColor,
|
||||
|
||||
/*!
|
||||
@deprecated in favor of colorWithWhite:apha:
|
||||
|
||||
|
||||
Creates a new color object with \c white for the RGB components.
|
||||
For the alpha component, a value of 1.0 is opaque, and 0.0 means completely transparent.
|
||||
|
||||
|
||||
@param white a float between 0.0 and 1.0
|
||||
@param alpha the alpha component between 0.0 and 1.0
|
||||
|
||||
|
||||
@return a color initialized to the values specified
|
||||
*/
|
||||
+ (CPColor)colorWithCalibratedWhite:(float)white alpha:(float)alpha
|
||||
@@ -148,11 +142,11 @@ var cachedBlackColor,
|
||||
|
||||
/*!
|
||||
Creates a new color in HSB space.
|
||||
|
||||
|
||||
@param hue the hue value
|
||||
@param saturation the saturation value
|
||||
@param brightness the brightness value
|
||||
|
||||
|
||||
@return the initialized color
|
||||
*/
|
||||
+ (CPColor)colorWithHue:(float)hue saturation:(float)saturation brightness:(float)brightness
|
||||
@@ -162,16 +156,16 @@ var cachedBlackColor,
|
||||
|
||||
+ (CPColor)colorWithHue:(float)hue saturation:(float)saturation brightness:(float)brightness alpha:(float)alpha
|
||||
{
|
||||
if(saturation === 0.0)
|
||||
if (saturation === 0.0)
|
||||
return [CPColor colorWithCalibratedWhite:brightness / 100.0 alpha:alpha];
|
||||
|
||||
|
||||
var f = hue % 60,
|
||||
p = (brightness * (100 - saturation)) / 10000,
|
||||
q = (brightness * (6000 - saturation * f)) / 600000,
|
||||
t = (brightness * (6000 - saturation * (60 -f))) / 600000,
|
||||
b = brightness / 100.0;
|
||||
|
||||
switch(FLOOR(hue / 60))
|
||||
|
||||
switch (FLOOR(hue / 60))
|
||||
{
|
||||
case 0: return [CPColor colorWithCalibratedRed: b green: t blue: p alpha: alpha];
|
||||
case 1: return [CPColor colorWithCalibratedRed: q green: b blue: p alpha: alpha];
|
||||
@@ -194,7 +188,8 @@ var cachedBlackColor,
|
||||
*/
|
||||
+ (CPColor)colorWithHexString:(string)hex
|
||||
{
|
||||
return [[CPColor alloc] _initWithRGBA: hexToRGB(hex)];
|
||||
var rgba = hexToRGB(hex);
|
||||
return rgba ? [[CPColor alloc] _initWithRGBA: rgba] : null;
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -397,7 +392,7 @@ var cachedBlackColor,
|
||||
|
||||
/*!
|
||||
Creates a CPColor from a valid CSS RGB string. Example, "rgb(32,64,129)".
|
||||
|
||||
|
||||
@param aString a CSS color string
|
||||
@return a color initialized to the value in the css string
|
||||
*/
|
||||
@@ -409,23 +404,23 @@ var cachedBlackColor,
|
||||
/* @ignore */
|
||||
- (id)_initWithCSSString:(CPString)aString
|
||||
{
|
||||
if(aString.indexOf("rgb") == CPNotFound)
|
||||
if (aString.indexOf("rgb") == CPNotFound)
|
||||
return nil;
|
||||
|
||||
|
||||
self = [super init];
|
||||
|
||||
|
||||
var startingIndex = aString.indexOf("(");
|
||||
var parts = aString.substring(startingIndex+1).split(',');
|
||||
|
||||
|
||||
_components = [
|
||||
parseInt(parts[0], 10) / 255.0,
|
||||
parseInt(parts[1], 10) / 255.0,
|
||||
parseInt(parts[2], 10) / 255.0,
|
||||
parts[3] ? parseInt(parts[3], 10) / 255.0 : 1.0
|
||||
]
|
||||
|
||||
];
|
||||
|
||||
_cssString = aString;
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -433,7 +428,7 @@ var cachedBlackColor,
|
||||
- (id)_initWithRGBA:(CPArray)components
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_components = components;
|
||||
@@ -454,14 +449,14 @@ var cachedBlackColor,
|
||||
- (id)_initWithPatternImage:(CPImage)anImage
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_patternImage = anImage;
|
||||
_cssString = "url(\"" + [_patternImage filename] + "\")";
|
||||
_components = [0.0, 0.0, 0.0, 1.0];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -523,17 +518,17 @@ var cachedBlackColor,
|
||||
|
||||
/*!
|
||||
Returns a new color with the same RGB as the receiver but a new alpha component.
|
||||
|
||||
|
||||
@param anAlphaComponent the alpha component for the new color
|
||||
|
||||
|
||||
@return a new color object
|
||||
*/
|
||||
- (CPColor)colorWithAlphaComponent:(float)anAlphaComponent
|
||||
{
|
||||
var components = _components.slice();
|
||||
|
||||
|
||||
components[components.length - 1] = anAlphaComponent;
|
||||
|
||||
|
||||
return [[[self class] alloc] _initWithRGBA:components];
|
||||
}
|
||||
|
||||
@@ -552,35 +547,38 @@ var cachedBlackColor,
|
||||
var red = ROUND(_components[_redComponent] * 255.0),
|
||||
green = ROUND(_components[_greenComponent] * 255.0),
|
||||
blue = ROUND(_components[_blueComponent] * 255.0);
|
||||
|
||||
|
||||
var max = MAX(red, green, blue),
|
||||
min = MIN(red, green, blue),
|
||||
delta = max - min;
|
||||
|
||||
|
||||
var brightness = max / 255.0,
|
||||
saturation = (max != 0) ? delta / max : 0;
|
||||
|
||||
|
||||
var hue;
|
||||
if(saturation == 0)
|
||||
|
||||
if (saturation == 0)
|
||||
{
|
||||
hue = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
var rr = (max - red) / delta;
|
||||
var gr = (max - green) / delta;
|
||||
var br = (max - blue) / delta;
|
||||
|
||||
|
||||
if (red == max)
|
||||
hue = br - gr;
|
||||
else if (green == max)
|
||||
hue = 2 + rr - br;
|
||||
else
|
||||
hue = 4 + gr - rr;
|
||||
|
||||
|
||||
hue /= 6;
|
||||
if (hue < 0)
|
||||
hue++;
|
||||
}
|
||||
|
||||
|
||||
return [
|
||||
ROUND(hue * 360.0),
|
||||
ROUND(saturation * 100.0),
|
||||
@@ -699,10 +697,8 @@ var CPColorComponentsKey = @"CPColorComponentsKey",
|
||||
|
||||
@end
|
||||
|
||||
var hexCharacters = "0123456789ABCDEF";
|
||||
|
||||
// HACK: prevent these from becoming globals. workaround for obj-j "function foo(){}" behavior
|
||||
var hexToRGB, rgbToHex, byteToHex;
|
||||
var hexCharacters = "0123456789ABCDEF";
|
||||
|
||||
/*!
|
||||
Used for the CPColor \c +colorWithHexString: implementation
|
||||
@@ -710,39 +706,39 @@ var hexToRGB, rgbToHex, byteToHex;
|
||||
@class CPColor
|
||||
@return an array of rgb components
|
||||
*/
|
||||
function hexToRGB(hex)
|
||||
var hexToRGB = function(hex)
|
||||
{
|
||||
if ( hex.length == 3 )
|
||||
if (hex.length == 3)
|
||||
hex = hex.charAt(0) + hex.charAt(0) + hex.charAt(1) + hex.charAt(1) + hex.charAt(2) + hex.charAt(2);
|
||||
if(hex.length != 6)
|
||||
|
||||
if (hex.length != 6)
|
||||
return null;
|
||||
|
||||
hex = hex.toUpperCase();
|
||||
|
||||
for(var i=0; i<hex.length; i++)
|
||||
if(hexCharacters.indexOf(hex.charAt(i)) == -1)
|
||||
for (var i = 0; i < hex.length; i++)
|
||||
if (hexCharacters.indexOf(hex.charAt(i)) == -1)
|
||||
return null;
|
||||
|
||||
|
||||
var red = (hexCharacters.indexOf(hex.charAt(0)) * 16 + hexCharacters.indexOf(hex.charAt(1))) / 255.0;
|
||||
var green = (hexCharacters.indexOf(hex.charAt(2)) * 16 + hexCharacters.indexOf(hex.charAt(3))) / 255.0;
|
||||
var blue = (hexCharacters.indexOf(hex.charAt(4)) * 16 + hexCharacters.indexOf(hex.charAt(5))) / 255.0;
|
||||
|
||||
|
||||
return [red, green, blue, 1.0];
|
||||
}
|
||||
};
|
||||
|
||||
function rgbToHex(r,g,b) {
|
||||
var rgbToHex = function(r,g,b)
|
||||
{
|
||||
return byteToHex(r) + byteToHex(g) + byteToHex(b);
|
||||
}
|
||||
};
|
||||
|
||||
function byteToHex(n) {
|
||||
if (!n || isNaN(n)) return "00";
|
||||
n = ROUND(MIN(255,MAX(0,256*n)));
|
||||
return hexCharacters.charAt((n - n % 16) / 16) +
|
||||
hexCharacters.charAt(n % 16);
|
||||
}
|
||||
var byteToHex = function(n)
|
||||
{
|
||||
if (!n || isNaN(n))
|
||||
return "00";
|
||||
|
||||
// Toll-Free bridge CPColor to CGColor.
|
||||
//CGColor.prototype.isa = CPColor;
|
||||
//[CPColor initialize];
|
||||
n = FLOOR(MIN(255, MAX(0, 256 * n)));
|
||||
|
||||
//http://dev.mootools.net/browser/trunk/Source/Utilities/Color.js?rev=1184
|
||||
return hexCharacters.charAt((n - n % 16) / 16) +
|
||||
hexCharacters.charAt(n % 16);
|
||||
};
|
||||
|
||||
@@ -35,7 +35,7 @@ var PREVIEW_HEIGHT = 20.0,
|
||||
|
||||
var SharedColorPanel = nil,
|
||||
ColorPickerClasses = [];
|
||||
|
||||
|
||||
/*
|
||||
A color wheel
|
||||
@global
|
||||
@@ -52,7 +52,7 @@ CPSliderColorPickerMode = 2;
|
||||
CPColorPickerViewWidth = 265,
|
||||
CPColorPickerViewHeight = 370;
|
||||
|
||||
/*!
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPColorPanel
|
||||
|
||||
@@ -61,7 +61,7 @@ CPColorPickerViewHeight = 370;
|
||||
obtain the panel, call the \c +sharedColorPanel method.
|
||||
*/
|
||||
@implementation CPColorPanel : CPPanel
|
||||
{
|
||||
{
|
||||
_CPColorPanelToolbar _toolbar;
|
||||
_CPColorPanelSwatches _swatchView;
|
||||
_CPColorPanelPreview _previewView;
|
||||
@@ -80,8 +80,8 @@ CPColorPickerViewHeight = 370;
|
||||
int _mode;
|
||||
}
|
||||
|
||||
/*!
|
||||
A list of color pickers is collected here, and any color panel created will contain
|
||||
/*!
|
||||
A list of color pickers is collected here, and any color panel created will contain
|
||||
any picker in this list up to this point. In other words, call before creating a color panel.
|
||||
*/
|
||||
+ (void)provideColorPickerClass:(Class)aColorPickerSubclass
|
||||
@@ -96,7 +96,7 @@ CPColorPickerViewHeight = 370;
|
||||
{
|
||||
if (!SharedColorPanel)
|
||||
SharedColorPanel = [[CPColorPanel alloc] init];
|
||||
|
||||
|
||||
return SharedColorPanel;
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ CPColorPickerViewHeight = 370;
|
||||
+ (void)setPickerMode:(CPColorPanelMode)mode
|
||||
{
|
||||
var panel = [CPColorPanel sharedColorPanel];
|
||||
[panel setMode: mode];
|
||||
[panel setMode:mode];
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -116,7 +116,7 @@ CPColorPickerViewHeight = 370;
|
||||
*/
|
||||
- (id)init
|
||||
{
|
||||
self = [super initWithContentRect:CGRectMake(500.0, 50.0, 219.0, 370.0)
|
||||
self = [super initWithContentRect:CGRectMake(500.0, 50.0, 219.0, 370.0)
|
||||
styleMask:(CPTitledWindowMask | CPClosableWindowMask | CPResizableWindowMask)];
|
||||
|
||||
if (self)
|
||||
@@ -125,14 +125,14 @@ CPColorPickerViewHeight = 370;
|
||||
|
||||
[self setTitle:@"Color Panel"];
|
||||
[self setLevel:CPFloatingWindowLevel];
|
||||
|
||||
|
||||
[self setFloatingPanel:YES];
|
||||
[self setBecomesKeyOnlyIfNeeded:YES];
|
||||
|
||||
|
||||
[self setMinSize:CGSizeMake(219.0, 342.0)];
|
||||
[self setMaxSize:CGSizeMake(323.0, 537.0)];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -143,12 +143,12 @@ CPColorPickerViewHeight = 370;
|
||||
{
|
||||
_color = aColor;
|
||||
[_previewView setBackgroundColor: _color];
|
||||
|
||||
|
||||
[CPApp sendAction:@selector(changeColor:) to:nil from:self];
|
||||
|
||||
if (_target && _action)
|
||||
[CPApp sendAction:_action to:_target from:self];
|
||||
|
||||
|
||||
[[CPNotificationCenter defaultCenter]
|
||||
postNotificationName:CPColorPanelColorDidChangeNotification
|
||||
object:self];
|
||||
@@ -165,7 +165,7 @@ CPColorPickerViewHeight = 370;
|
||||
- (void)setColor:(CPColor)aColor updatePicker:(BOOL)bool
|
||||
{
|
||||
[self setColor:aColor];
|
||||
|
||||
|
||||
if (bool)
|
||||
[_activePicker setColor:_color];
|
||||
}
|
||||
@@ -232,30 +232,30 @@ CPColorPickerViewHeight = 370;
|
||||
{
|
||||
var picker = _colorPickers[[sender tag]],
|
||||
view = [picker provideNewView:NO];
|
||||
|
||||
|
||||
if (!view)
|
||||
view = [picker provideNewView:YES];
|
||||
|
||||
|
||||
if (view == _currentView)
|
||||
return;
|
||||
|
||||
|
||||
if (_currentView)
|
||||
[view setFrame:[_currentView frame]];
|
||||
else
|
||||
{
|
||||
var height = (TOOLBAR_HEIGHT+10+PREVIEW_HEIGHT+5+SWATCH_HEIGHT+32),
|
||||
var height = (TOOLBAR_HEIGHT + 10 + PREVIEW_HEIGHT + 5 + SWATCH_HEIGHT + 32),
|
||||
bounds = [[self contentView] bounds];
|
||||
|
||||
[view setFrameSize: CPSizeMake(bounds.size.width - 10, bounds.size.height - height)];
|
||||
[view setFrameOrigin: CPPointMake(5, height)];
|
||||
[view setFrameSize:CPSizeMake(bounds.size.width - 10, bounds.size.height - height)];
|
||||
[view setFrameOrigin:CPPointMake(5, height)];
|
||||
}
|
||||
|
||||
|
||||
[_currentView removeFromSuperview];
|
||||
[[self contentView] addSubview:view];
|
||||
|
||||
|
||||
_currentView = view;
|
||||
_activePicker = picker;
|
||||
|
||||
|
||||
[picker setColor:[self color]];
|
||||
}
|
||||
|
||||
@@ -285,7 +285,7 @@ CPColorPickerViewHeight = 370;
|
||||
_colorPickers = [];
|
||||
|
||||
var count = [ColorPickerClasses count];
|
||||
for (var i=0; i<count; i++)
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var currentPickerClass = ColorPickerClasses[i],
|
||||
currentPicker = [[currentPickerClass alloc] initWithPickerMask:0 colorPanel:self];
|
||||
@@ -297,29 +297,29 @@ CPColorPickerViewHeight = 370;
|
||||
bounds = [contentView bounds];
|
||||
|
||||
_toolbar = [[CPView alloc] initWithFrame:CGRectMake(0, 6, CGRectGetWidth(bounds), TOOLBAR_HEIGHT)];
|
||||
[_toolbar setAutoresizingMask: CPViewWidthSizable];
|
||||
[_toolbar setAutoresizingMask: CPViewWidthSizable];
|
||||
|
||||
var totalToolbarWidth = count * ICON_WIDTH + (count - 1) * ICON_PADDING,
|
||||
leftOffset = (CGRectGetWidth(bounds) - totalToolbarWidth) / 2.0,
|
||||
buttonForLater = nil;
|
||||
|
||||
for (var i=0; i<count; i++)
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var image = [_colorPickers[i] provideNewButtonImage],
|
||||
highlightImage = [_colorPickers[i] provideNewAlternateButtonImage],
|
||||
button = [[CPButton alloc] initWithFrame:CGRectMake(leftOffset + i*(ICON_WIDTH+ICON_PADDING), 0, ICON_WIDTH, ICON_WIDTH)];
|
||||
|
||||
button = [[CPButton alloc] initWithFrame:CGRectMake(leftOffset + i * (ICON_WIDTH + ICON_PADDING), 0, ICON_WIDTH, ICON_WIDTH)];
|
||||
|
||||
[button setTag:i];
|
||||
[button setTarget:self];
|
||||
[button setAction:@selector(_setPicker:)];
|
||||
[button setBordered:NO];
|
||||
[button setAutoresizingMask:CPViewMinXMargin|CPViewMaxXMargin];
|
||||
|
||||
|
||||
[button setImage:image];
|
||||
[button setAlternateImage:highlightImage];
|
||||
|
||||
|
||||
[_toolbar addSubview:button];
|
||||
|
||||
|
||||
if (!buttonForLater)
|
||||
buttonForLater = button;
|
||||
}
|
||||
@@ -330,7 +330,7 @@ CPColorPickerViewHeight = 370;
|
||||
_previewView = [[_CPColorPanelPreview alloc] initWithFrame:CGRectInset([previewBox bounds], 2.0, 2.0)];
|
||||
|
||||
[_previewView setColorPanel:self];
|
||||
[_previewView setAutoresizingMask:CPViewWidthSizable];
|
||||
[_previewView setAutoresizingMask:CPViewWidthSizable];
|
||||
|
||||
[previewBox setBackgroundColor:[CPColor colorWithWhite:0.8 alpha:1.0]];
|
||||
[previewBox setAutoresizingMask:CPViewWidthSizable];
|
||||
@@ -338,7 +338,7 @@ CPColorPickerViewHeight = 370;
|
||||
[previewBox addSubview:_previewView];
|
||||
|
||||
var _previewLabel = [[CPTextField alloc] initWithFrame: CPRectMake(10, TOOLBAR_HEIGHT + 10, 60, 15)];
|
||||
[_previewLabel setStringValue: "Preview:"];
|
||||
[_previewLabel setStringValue:"Preview:"];
|
||||
[_previewLabel setTextColor:[CPColor blackColor]];
|
||||
[_previewLabel setAlignment:CPRightTextAlignment];
|
||||
|
||||
@@ -350,8 +350,8 @@ CPColorPickerViewHeight = 370;
|
||||
|
||||
_swatchView = [[_CPColorPanelSwatches alloc] initWithFrame:CGRectInset([swatchBox bounds], 1.0, 1.0)];
|
||||
|
||||
[_swatchView setColorPanel: self];
|
||||
[_swatchView setAutoresizingMask: CPViewWidthSizable];
|
||||
[_swatchView setColorPanel:self];
|
||||
[_swatchView setAutoresizingMask:CPViewWidthSizable];
|
||||
|
||||
[swatchBox addSubview:_swatchView];
|
||||
|
||||
@@ -367,7 +367,7 @@ CPColorPickerViewHeight = 370;
|
||||
[opacityLabel setAlignment:CPRightTextAlignment];
|
||||
|
||||
_opacitySlider = [[CPSlider alloc] initWithFrame:CGRectMake(76, TOOLBAR_HEIGHT + PREVIEW_HEIGHT + 34, CGRectGetWidth(bounds) - 86, 20.0)];
|
||||
|
||||
|
||||
[_opacitySlider setMinValue:0.0];
|
||||
[_opacitySlider setMaxValue:1.0];
|
||||
|
||||
@@ -418,34 +418,34 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
-(id)initWithFrame:(CPRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
|
||||
[self setBackgroundColor: [CPColor grayColor]];
|
||||
|
||||
|
||||
[self registerForDraggedTypes:[CPArray arrayWithObjects:CPColorDragType]];
|
||||
|
||||
var whiteColor = [CPColor whiteColor];
|
||||
|
||||
_swatchCookie = [[CPCookie alloc] initWithName: CPColorPanelSwatchesCookie];
|
||||
var colorList = [self startingColorList];
|
||||
|
||||
|
||||
_swatches = [];
|
||||
|
||||
|
||||
for(var i=0; i < 50; i++)
|
||||
{
|
||||
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
|
||||
var view = [[CPView alloc] initWithFrame: CPRectMake(13*i+1, 1, 12, 12)],
|
||||
fillView = [[CPView alloc] initWithFrame:CGRectInset([view bounds], 1.0, 1.0)];
|
||||
|
||||
|
||||
[view setBackgroundColor:whiteColor];
|
||||
[fillView setBackgroundColor: (i < colorList.length) ? colorList[i] : whiteColor];
|
||||
|
||||
[view addSubview:fillView];
|
||||
|
||||
[self addSubview: view];
|
||||
|
||||
|
||||
_swatches.push(view);
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -471,10 +471,10 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
[CPColor yellowColor]
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
var cookieValue = eval(cookieValue);
|
||||
var result = [];
|
||||
|
||||
|
||||
for(var i=0; i<cookieValue.length; i++)
|
||||
result.push([CPColor colorWithHexString: cookieValue[i]]);
|
||||
|
||||
@@ -487,10 +487,10 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
|
||||
for(var i=0; i<_swatches.length; i++)
|
||||
result.push([[[_swatches[i] subviews][0] backgroundColor] hexString]);
|
||||
|
||||
|
||||
var future = new Date();
|
||||
future.setYear(2019);
|
||||
|
||||
|
||||
[_swatchCookie setValue: JSON.stringify(result) expires:future domain: nil];
|
||||
}
|
||||
|
||||
@@ -520,7 +520,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
{
|
||||
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil],
|
||||
bounds = [self bounds];
|
||||
|
||||
|
||||
if(!CGRectContainsPoint(bounds, point) || point.x > [self bounds].size.width - 1 || point.x < 1)
|
||||
return NO;
|
||||
|
||||
@@ -535,21 +535,21 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
return NO;
|
||||
|
||||
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:[CPArray arrayWithObject:CPColorDragType] owner:self];
|
||||
|
||||
|
||||
var swatch = _swatches[FLOOR(point.x / 13)];
|
||||
|
||||
|
||||
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
|
||||
_dragColor = [[swatch subviews][0] backgroundColor];
|
||||
|
||||
|
||||
var bounds = CPRectCreateCopy([swatch bounds]);
|
||||
|
||||
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
|
||||
var dragView = [[CPView alloc] initWithFrame: bounds];
|
||||
var dragView = [[CPView alloc] initWithFrame: bounds],
|
||||
dragFillView = [[CPView alloc] initWithFrame:CGRectInset(bounds, 1.0, 1.0)];
|
||||
|
||||
|
||||
[dragView setBackgroundColor:[CPColor blackColor]];
|
||||
[dragFillView setBackgroundColor:_dragColor];
|
||||
|
||||
|
||||
[dragView addSubview:dragFillView];
|
||||
|
||||
[self dragView: dragView
|
||||
@@ -568,14 +568,14 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
}
|
||||
|
||||
- (void)performDragOperation:(id <CPDraggingInfo>)aSender
|
||||
{
|
||||
{
|
||||
var location = [self convertPoint:[aSender draggingLocation] fromView:nil],
|
||||
pasteboard = [aSender draggingPasteboard],
|
||||
swatch = nil;
|
||||
|
||||
if(![pasteboard availableTypeFromArray:[CPColorDragType]] || location.x > [self bounds].size.width - 1 || location.x < 1)
|
||||
return NO;
|
||||
|
||||
|
||||
[self setColor:[CPKeyedUnarchiver unarchiveObjectWithData:[pasteboard dataForType:CPColorDragType]] atIndex: FLOOR(location.x / 13)];
|
||||
}
|
||||
|
||||
@@ -590,9 +590,9 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
- (id)initWithFrame:(CPRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
|
||||
[self registerForDraggedTypes:[CPArray arrayWithObjects:CPColorDragType]];
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -610,9 +610,9 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
{
|
||||
var pasteboard = [aSender draggingPasteboard];
|
||||
|
||||
if(![pasteboard availableTypeFromArray:[CPColorDragType]])
|
||||
if (![pasteboard availableTypeFromArray:[CPColorDragType]])
|
||||
return NO;
|
||||
|
||||
|
||||
var color = [CPKeyedUnarchiver unarchiveObjectWithData:[pasteboard dataForType:CPColorDragType]];
|
||||
[_colorPanel setColor:color updatePicker:YES];
|
||||
}
|
||||
@@ -626,19 +626,19 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
{
|
||||
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||
|
||||
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:[CPColorDragType] owner:self];
|
||||
|
||||
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:[CPColorDragType] owner:self];
|
||||
|
||||
var bounds = CPRectMake(0, 0, 15, 15);
|
||||
|
||||
|
||||
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
|
||||
var dragView = [[CPView alloc] initWithFrame: bounds];
|
||||
var dragView = [[CPView alloc] initWithFrame: bounds],
|
||||
dragFillView = [[CPView alloc] initWithFrame:CGRectInset(bounds, 1.0, 1.0)];
|
||||
|
||||
|
||||
[dragView setBackgroundColor:[CPColor blackColor]];
|
||||
[dragFillView setBackgroundColor:[self backgroundColor]];
|
||||
|
||||
|
||||
[dragView addSubview:dragFillView];
|
||||
|
||||
|
||||
[self dragView: dragView
|
||||
at: CPPointMake(point.x - bounds.size.width / 2.0, point.y - bounds.size.height / 2.0)
|
||||
offset: CPPointMake(0.0, 0.0)
|
||||
@@ -650,7 +650,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
|
||||
|
||||
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
|
||||
{
|
||||
if(aType == CPColorDragType)
|
||||
if (aType == CPColorDragType)
|
||||
[aPasteboard setData:[CPKeyedArchiver archivedDataWithRootObject:[self backgroundColor]] forType:aType];
|
||||
}
|
||||
|
||||
|
||||
@@ -278,7 +278,7 @@ var CPColorWellColorKey = "CPColorWellColorKey",
|
||||
if (self)
|
||||
{
|
||||
_active = NO;
|
||||
_bordered = [aCoder decodeObjectForKey:CPColorWellBorderedKey];
|
||||
_bordered = [aCoder decodeBoolForKey:CPColorWellBorderedKey];
|
||||
_color = [aCoder decodeObjectForKey:CPColorWellColorKey];
|
||||
|
||||
[self drawBezelWithHighlight:NO];
|
||||
|
||||
@@ -280,7 +280,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
- (void)trackMouse:(CPEvent)anEvent
|
||||
{
|
||||
var type = [anEvent type],
|
||||
currentLocation = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||
currentLocation = [self convertPoint:[anEvent locationInWindow] fromView:nil],
|
||||
isWithinFrame = [self tracksMouseOutsideOfFrame] || CGRectContainsPoint([self bounds], currentLocation);
|
||||
|
||||
if (type === CPLeftMouseUp)
|
||||
@@ -289,7 +289,6 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
|
||||
_trackingMouseDownFlags = 0;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (type === CPLeftMouseDown)
|
||||
@@ -337,9 +336,19 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
|
||||
[self highlight:YES];
|
||||
[self setState:[self nextState]];
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
|
||||
[CPTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(unhighlightButtonTimerDidFinish:) userInfo:nil repeats:NO];
|
||||
try
|
||||
{
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
[CPTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(unhighlightButtonTimerDidFinish:) userInfo:nil repeats:NO];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)unhighlightButtonTimerDidFinish:(id)sender
|
||||
@@ -545,6 +554,7 @@ var CPControlBlackColor = [CPColor blackColor];
|
||||
return;
|
||||
|
||||
[self _reverseSetBinding];
|
||||
|
||||
[[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidEndEditingNotification object:self userInfo:[CPDictionary dictionaryWithObject:[note object] forKey:"CPFieldEditor"]];
|
||||
}
|
||||
|
||||
|
||||
@@ -92,21 +92,28 @@
|
||||
domain = "; domain="+domain;
|
||||
else
|
||||
domain = "";
|
||||
|
||||
document.cookie = _cookieName+"="+value+expires+"; path=/"+domain;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
document.cookie = _cookieName+"="+value+expires+"; path=/"+domain;
|
||||
#else
|
||||
_cookieValue = value;
|
||||
_expires = expires;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (CPString)_readCookieValue
|
||||
{
|
||||
var nameEQ = _cookieName + "=";
|
||||
var ca = document.cookie.split(';');
|
||||
for(var i=0;i < ca.length;i++) {
|
||||
var c = ca[i];
|
||||
while (c.charAt(0)==' ') c = c.substring(1,c.length);
|
||||
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
|
||||
}
|
||||
return "";
|
||||
#if PLATFORM(DOM)
|
||||
var nameEQ = _cookieName + "=";
|
||||
var ca = document.cookie.split(';');
|
||||
for(var i=0;i < ca.length;i++) {
|
||||
var c = ca[i];
|
||||
while (c.charAt(0)==' ') c = c.substring(1,c.length);
|
||||
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
|
||||
}
|
||||
#endif
|
||||
return "";
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -197,7 +197,7 @@ var currentCursor = nil,
|
||||
|
||||
+ (void)unhide
|
||||
{
|
||||
[self _setCursorCSS:[currentCursor _cssString]]
|
||||
[self _setCursorCSS:[currentCursor _cssString]];
|
||||
}
|
||||
|
||||
+ (void)setHiddenUntilMouseMoves:(BOOL)flag
|
||||
|
||||
@@ -262,7 +262,7 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
||||
{
|
||||
var contentView = [scrollView contentView],
|
||||
bounds = [contentView bounds],
|
||||
insetBounds = CGRectInset(bounds, 10, 10)
|
||||
insetBounds = CGRectInset(bounds, 10, 10),
|
||||
eventLocation = [contentView convertPoint:_draggingLocation fromView:nil],
|
||||
deltaX = 0,
|
||||
deltaY = 0;
|
||||
@@ -304,7 +304,7 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
||||
- (void)_sendPeriodicDraggingUpdate:(CPTimer)aTimer
|
||||
{
|
||||
var userInfo = [aTimer userInfo];
|
||||
_dragOperation = [self draggingUpdatedInPlatformWindow:[userInfo objectForKey:@"platformWindow"]
|
||||
_dragOperation = [self draggingUpdatedInPlatformWindow:[userInfo objectForKey:@"platformWindow"]
|
||||
location:[userInfo objectForKey:@"location"]];
|
||||
}
|
||||
|
||||
@@ -328,8 +328,8 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
|
||||
|
||||
- (void)performDragOperationInPlatformWindow:(CPPlatformWindow)aPlatformWindow
|
||||
{
|
||||
if (_draggingDestination &&
|
||||
(![_draggingDestination respondsToSelector:@selector(prepareForDragOperation:)] || [_draggingDestination prepareForDragOperation:CPDragServerDraggingInfo]) &&
|
||||
if (_draggingDestination &&
|
||||
(![_draggingDestination respondsToSelector:@selector(prepareForDragOperation:)] || [_draggingDestination prepareForDragOperation:CPDragServerDraggingInfo]) &&
|
||||
(![_draggingDestination respondsToSelector:@selector(performDragOperation:)] || [_draggingDestination performDragOperation:CPDragServerDraggingInfo]) &&
|
||||
[_draggingDestination respondsToSelector:@selector(concludeDragOperation:)])
|
||||
[_draggingDestination concludeDragOperation:CPDragServerDraggingInfo];
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
*/
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
@import "CPText.j"
|
||||
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
|
||||
@@ -178,7 +179,8 @@ CPDOMEventTouchEnd = "touchend";
|
||||
CPDOMEventTouchCancel = "touchcancel";
|
||||
|
||||
var _CPEventPeriodicEventPeriod = 0,
|
||||
_CPEventPeriodicEventTimer = nil;
|
||||
_CPEventPeriodicEventTimer = nil,
|
||||
_CPEventUpperCaseRegex = new RegExp("[A-Z]");
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@@ -521,10 +523,10 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
|
||||
- (BOOL)_triggersKeyEquivalent:(CPString)aKeyEquivalent withModifierMask:aKeyEquivalentModifierMask
|
||||
{
|
||||
var characters = [self charactersIgnoringModifiers],
|
||||
modifierFlags = [self modifierFlags];
|
||||
if (!aKeyEquivalent)
|
||||
return NO;
|
||||
|
||||
if (new RegExp("[A-Z]").test(aKeyEquivalent))
|
||||
if (_CPEventUpperCaseRegex.test(aKeyEquivalent))
|
||||
aKeyEquivalentModifierMask |= CPShiftKeyMask;
|
||||
|
||||
if (CPBrowserIsOperatingSystem(CPWindowsOperatingSystem) && (aKeyEquivalentModifierMask & CPCommandKeyMask))
|
||||
@@ -533,35 +535,39 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
aKeyEquivalentModifierMask &= ~CPCommandKeyMask;
|
||||
}
|
||||
|
||||
if ((modifierFlags & (CPShiftKeyMask | CPAlternateKeyMask | CPCommandKeyMask | CPControlKeyMask)) !== aKeyEquivalentModifierMask)
|
||||
if ((_modifierFlags & (CPShiftKeyMask | CPAlternateKeyMask | CPCommandKeyMask | CPControlKeyMask)) !== aKeyEquivalentModifierMask)
|
||||
return NO;
|
||||
|
||||
return [characters caseInsensitiveCompare:aKeyEquivalent] === CPOrderedSame;
|
||||
// Treat \r and \n as the same key equivalent. See issue #710.
|
||||
if (_characters === CPNewlineCharacter || _characters === CPCarriageReturnCharacter)
|
||||
return CPNewlineCharacter === aKeyEquivalent || CPCarriageReturnCharacter === aKeyEquivalent;
|
||||
|
||||
return [_characters caseInsensitiveCompare:aKeyEquivalent] === CPOrderedSame;
|
||||
}
|
||||
|
||||
- (BOOL)_couldBeKeyEquivalent
|
||||
{
|
||||
// FIXME: More cases? Space?
|
||||
return _type === CPKeyDown &&
|
||||
((_modifierFlags & (CPCommandKeyMask | CPControlKeyMask) &&
|
||||
[_characters length] > 0) ||
|
||||
[self _hasActionCharacter]);
|
||||
}
|
||||
if (_type !== CPKeyDown)
|
||||
return NO;
|
||||
|
||||
- (BOOL)_hasActionCharacter
|
||||
{
|
||||
var characters = [self characters],
|
||||
characterCount = [characters length];
|
||||
var characterCount = _characters.length;
|
||||
|
||||
if (!characterCount)
|
||||
return NO;
|
||||
|
||||
if (_modifierFlags & (CPCommandKeyMask | CPControlKeyMask))
|
||||
return YES;
|
||||
|
||||
for(var i=0; i<characterCount; i++)
|
||||
{
|
||||
var c = [characters characterAtIndex:i];
|
||||
switch(c)
|
||||
switch(_characters.charAt(i))
|
||||
{
|
||||
case CPBackspaceCharacter:
|
||||
case CPDeleteCharacter:
|
||||
case CPDeleteFunctionKey:
|
||||
case CPTabCharacter:
|
||||
case CPCarriageReturnCharacter:
|
||||
case CPNewlineCharacter:
|
||||
case CPEscapeFunctionKey:
|
||||
case CPPageUpFunctionKey:
|
||||
case CPPageDownFunctionKey:
|
||||
@@ -570,10 +576,10 @@ var _CPEventPeriodicEventPeriod = 0,
|
||||
case CPRightArrowFunctionKey:
|
||||
case CPDownArrowFunctionKey:
|
||||
return YES;
|
||||
default:
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
// FIXME: More cases? Space?
|
||||
return NO;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
||||
@@ -28,7 +28,7 @@ var _CPFonts = {},
|
||||
#define _CPCreateCSSString(aName, aSize, isBold) (isBold ? @"bold " : @"") + ROUND(aSize) + @"px " + ((aName === _CPFontSystemFontFace) ? aName : (@"\"" + aName.replace(_CPWrapRegExp, '", "') + @"\", " + _CPFontSystemFontFace))
|
||||
#define _CPCachedFont(aName, aSize, isBold) _CPFonts[_CPCreateCSSString(aName, aSize, isBold)]
|
||||
|
||||
/*!
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPFont
|
||||
|
||||
@@ -38,11 +38,22 @@ var _CPFonts = {},
|
||||
{
|
||||
CPString _name;
|
||||
float _size;
|
||||
float _ascender;
|
||||
float _descender;
|
||||
float _lineHeight;
|
||||
BOOL _isBold;
|
||||
|
||||
|
||||
CPString _cssString;
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
var systemFont = [[CPBundle bundleForClass:[CPView class]] objectForInfoDictionaryKey:"CPSystemFontFace"];
|
||||
|
||||
if (systemFont)
|
||||
_CPFontSystemFontFace = systemFont;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a font with the specified name and size.
|
||||
@param aName the name of the font
|
||||
@@ -89,25 +100,64 @@ var _CPFonts = {},
|
||||
@ignore
|
||||
*/
|
||||
- (id)_initWithName:(CPString)aName size:(float)aSize bold:(BOOL)isBold
|
||||
{
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_name = aName;
|
||||
_size = aSize;
|
||||
_ascender = 0;
|
||||
_descender = 0;
|
||||
_lineHeight = 0;
|
||||
_isBold = isBold;
|
||||
|
||||
|
||||
_cssString = _CPCreateCSSString(_name, _size, _isBold);
|
||||
|
||||
|
||||
_CPFonts[_cssString] = self;
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the font size (in points)
|
||||
Returns the distance of the longest ascender's top y-coordinate from the baseline (in CSS px)
|
||||
*/
|
||||
- (float)ascender
|
||||
{
|
||||
if (!_ascender)
|
||||
[self _getMetrics];
|
||||
|
||||
return _ascender;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the bottom y coordinate (in CSS px), offset from the baseline, of the receiver's longest descender.
|
||||
Thus, if the longest descender extends 2 points below the baseline, descender will return –2.
|
||||
*/
|
||||
- (float)descender
|
||||
{
|
||||
if (!_descender)
|
||||
[self _getMetrics];
|
||||
|
||||
return _descender;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the default line height.
|
||||
|
||||
NOTE: This was moved from NSFont to NSLayoutManager in Cocoa, but since there is no CPLayoutManager, it has been kept here.
|
||||
*/
|
||||
- (float)defaultLineHeightForFont
|
||||
{
|
||||
if (!_lineHeight)
|
||||
[self _getMetrics];
|
||||
|
||||
return _lineHeight;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the font size (in CSS px)
|
||||
*/
|
||||
- (float)size
|
||||
{
|
||||
@@ -140,6 +190,15 @@ var _CPFonts = {},
|
||||
return [CPString stringWithFormat:@"%@ %@ %f pt.", [super description], [self familyName], [self size]];
|
||||
}
|
||||
|
||||
- (void)_getMetrics
|
||||
{
|
||||
var metrics = [CPString metricsOfFont:self];
|
||||
|
||||
_ascender = [metrics objectForKey:@"ascender"];
|
||||
_descender = [metrics objectForKey:@"descender"];
|
||||
_lineHeight = [metrics objectForKey:@"lineHeight"];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPFontNameKey = @"CPFontNameKey",
|
||||
|
||||
@@ -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,110 @@
|
||||
/*
|
||||
* CPGraphics.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Francisco Tolmasky.
|
||||
* Copyright 2010, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "CPColor.j"
|
||||
@import "CPGraphicsContext.j"
|
||||
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
|
||||
|
||||
function CPDrawTiledRects(
|
||||
/* CGRect */ boundsRect,
|
||||
/* CGRect */ clipRect,
|
||||
/* CPRectEdge[] */ sides,
|
||||
/* float[] */ grays)
|
||||
{
|
||||
if (sides.length != grays.length)
|
||||
[CPException raise:CPInvalidArgumentException reason:@"sides (length: " + sides.length + ") and grays (length: " + grays.length + ") must have the same length."];
|
||||
|
||||
var colors = [];
|
||||
|
||||
for (var i = 0; i < grays.length; ++i)
|
||||
colors.push([CPColor colorWithCalibratedWhite:grays[i] alpha:1.0]);
|
||||
|
||||
return CPDrawColorTiledRects(boundsRect, clipRect, sides, colors);
|
||||
}
|
||||
|
||||
function CPDrawColorTiledRects(
|
||||
/* CGRect */ boundsRect,
|
||||
/* CGRect */ clipRect,
|
||||
/* CPRectEdge[] */ sides,
|
||||
/* CPColor[] */ colors)
|
||||
{
|
||||
if (sides.length != colors.length)
|
||||
[CPException raise:CPInvalidArgumentException reason:@"sides (length: " + sides.length + ") and colors (length: " + colors.length + ") must have the same length."];
|
||||
|
||||
var resultRect = _CGRectMakeCopy(boundsRect),
|
||||
slice = _CGRectMakeZero(),
|
||||
remainder = _CGRectMakeZero(),
|
||||
context = [[CPGraphicsContext currentContext] graphicsPort];
|
||||
|
||||
CGContextSaveGState(context);
|
||||
CGContextSetLineWidth(context, 1.0);
|
||||
|
||||
for (var sideIndex = 0; sideIndex < sides.length; ++sideIndex)
|
||||
{
|
||||
var side = sides[sideIndex];
|
||||
|
||||
CGRectDivide(resultRect, slice, remainder, 1.0, side);
|
||||
resultRect = remainder;
|
||||
slice = CGRectIntersection(slice, clipRect);
|
||||
|
||||
// Cocoa docs say that only slices that are within the clipRect are actually drawn
|
||||
if (_CGRectIsEmpty(slice))
|
||||
continue;
|
||||
|
||||
var minX, maxX, minY, maxY;
|
||||
|
||||
if (side == CPMinXEdge || side == CPMaxXEdge)
|
||||
{
|
||||
// Make sure we have at least 1 pixel to draw a line
|
||||
if (_CGRectGetWidth(slice) < 1.0)
|
||||
continue;
|
||||
|
||||
minX = _CGRectGetMinX(slice) + 0.5;
|
||||
maxX = minX;
|
||||
minY = _CGRectGetMinY(slice);
|
||||
maxY = _CGRectGetMaxY(slice);
|
||||
}
|
||||
else // CPMinYEdge || CPMaxYEdge
|
||||
{
|
||||
// Make sure we have at least 1 pixel to draw a line
|
||||
if (_CGRectGetHeight(slice) < 1.0)
|
||||
continue;
|
||||
|
||||
minX = _CGRectGetMinX(slice);
|
||||
maxX = _CGRectGetMaxX(slice);
|
||||
minY = _CGRectGetMinY(slice) + 0.5;
|
||||
maxY = minY;
|
||||
}
|
||||
|
||||
CGContextBeginPath(context);
|
||||
CGContextMoveToPoint(context, minX, minY);
|
||||
CGContextAddLineToPoint(context, maxX, maxY);
|
||||
CGContextSetStrokeColor(context, colors[sideIndex]);
|
||||
CGContextStrokePath(context);
|
||||
}
|
||||
|
||||
CGContextRestoreGState(context);
|
||||
|
||||
return resultRect;
|
||||
}
|
||||
@@ -193,6 +193,9 @@ function CPAppKitImage(aFilename, aSize)
|
||||
|
||||
var imageOrSize = AppKitImageForNames[aName];
|
||||
|
||||
if (!imageOrSize)
|
||||
return nil;
|
||||
|
||||
if (!imageOrSize.isa)
|
||||
{
|
||||
imageOrSize = CPAppKitImage("CPImage/" + aName + ".png", imageOrSize);
|
||||
@@ -205,17 +208,19 @@ function CPAppKitImage(aFilename, aSize)
|
||||
return imageOrSize;
|
||||
}
|
||||
|
||||
- (void)setName:(CPString)aName
|
||||
- (BOOL)setName:(CPString)aName
|
||||
{
|
||||
if (_name === aName)
|
||||
return;
|
||||
return YES;
|
||||
|
||||
if (imagesForNames[aName] === self)
|
||||
imagesForNames[aName] = nil;
|
||||
if (imagesForNames[aName])
|
||||
return NO;
|
||||
|
||||
_name = aName;
|
||||
|
||||
imagesForNames[aName] = self;
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (CPString)name
|
||||
|
||||
@@ -35,7 +35,18 @@ CPScaleProportionally = 0;
|
||||
CPScaleToFit = 1;
|
||||
CPScaleNone = 2;
|
||||
|
||||
var CPImageViewShadowBackgroundColor = nil;
|
||||
CPImageAlignCenter = 0;
|
||||
CPImageAlignTop = 1;
|
||||
CPImageAlignTopLeft = 2;
|
||||
CPImageAlignTopRight = 3;
|
||||
CPImageAlignLeft = 4;
|
||||
CPImageAlignBottom = 5;
|
||||
CPImageAlignBottomLeft = 6;
|
||||
CPImageAlignBottomRight = 7;
|
||||
CPImageAlignRight = 8;
|
||||
|
||||
var CPImageViewShadowBackgroundColor = nil,
|
||||
CPImageViewEmptyPlaceholderImage = nil;
|
||||
|
||||
var LEFT_SHADOW_INSET = 3.0,
|
||||
RIGHT_SHADOW_INSET = 3.0,
|
||||
@@ -52,14 +63,22 @@ var LEFT_SHADOW_INSET = 3.0,
|
||||
*/
|
||||
@implementation CPImageView : CPControl
|
||||
{
|
||||
DOMElement _DOMImageElement;
|
||||
DOMElement _DOMImageElement;
|
||||
|
||||
BOOL _hasShadow;
|
||||
CPView _shadowView;
|
||||
BOOL _hasShadow;
|
||||
CPView _shadowView;
|
||||
|
||||
BOOL _isEditable;
|
||||
BOOL _isEditable;
|
||||
|
||||
CGRect _imageRect;
|
||||
CGRect _imageRect;
|
||||
CPImageAlignment _imageAlignment;
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
var bundle = [CPBundle bundleForClass:[CPView class]];
|
||||
|
||||
CPImageViewEmptyPlaceholderImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"empty.png"]];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
@@ -120,7 +139,7 @@ var LEFT_SHADOW_INSET = 3.0,
|
||||
var newImage = [self objectValue];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
_DOMImageElement.src = newImage ? [newImage filename] : "";
|
||||
_DOMImageElement.src = newImage ? [newImage filename] : [CPImageViewEmptyPlaceholderImage filename];
|
||||
#endif
|
||||
|
||||
var size = [newImage size];
|
||||
@@ -191,6 +210,30 @@ var LEFT_SHADOW_INSET = 3.0,
|
||||
[self hideOrDisplayContents];
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the type of image alignment that should be used to
|
||||
render the image.
|
||||
@param anImageAlignment the type of scaling to use
|
||||
*/
|
||||
- (void)setImageAlignment:(CPImageAlignment)anImageAlignment
|
||||
{
|
||||
if (_imageAlignment == anImageAlignment)
|
||||
return;
|
||||
|
||||
_imageAlignment = anImageAlignment;
|
||||
|
||||
if (![self image])
|
||||
return;
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (unsigned)imageAlignment
|
||||
{
|
||||
return _imageAlignment;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the type of image scaling that should be used to
|
||||
render the image.
|
||||
@@ -318,8 +361,45 @@ var LEFT_SHADOW_INSET = 3.0,
|
||||
#endif
|
||||
}
|
||||
|
||||
var x = (boundsWidth - width) / 2.0,
|
||||
y = (boundsHeight - height) / 2.0;
|
||||
var x, y;
|
||||
|
||||
switch (_imageAlignment)
|
||||
{
|
||||
case CPImageAlignLeft:
|
||||
case CPImageAlignTopLeft:
|
||||
case CPImageAlignBottomLeft:
|
||||
x = 0.0;
|
||||
break;
|
||||
|
||||
case CPImageAlignRight:
|
||||
case CPImageAlignTopRight:
|
||||
case CPImageAlignBottomRight:
|
||||
x = boundsWidth - width;
|
||||
break;
|
||||
|
||||
default:
|
||||
x = (boundsWidth - width) / 2.0;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (_imageAlignment)
|
||||
{
|
||||
case CPImageAlignTop:
|
||||
case CPImageAlignTopLeft:
|
||||
case CPImageAlignTopRight:
|
||||
y = 0.0;
|
||||
break;
|
||||
|
||||
case CPImageAlignBottom:
|
||||
case CPImageAlignBottomLeft:
|
||||
case CPImageAlignBottomRight:
|
||||
y = boundsHeight - height;
|
||||
break;
|
||||
|
||||
default:
|
||||
y = (boundsHeight - height) / 2.0;
|
||||
break;
|
||||
}
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
CPDOMDisplayServerSetStyleLeftTop(_DOMImageElement, NULL, x, y);
|
||||
@@ -380,10 +460,11 @@ var LEFT_SHADOW_INSET = 3.0,
|
||||
|
||||
@end
|
||||
|
||||
var CPImageViewImageKey = @"CPImageViewImageKey",
|
||||
CPImageViewImageScalingKey = @"CPImageViewImageScalingKey",
|
||||
CPImageViewHasShadowKey = @"CPImageViewHasShadowKey",
|
||||
CPImageViewIsEditableKey = @"CPImageViewIsEditableKey";
|
||||
var CPImageViewImageKey = @"CPImageViewImageKey",
|
||||
CPImageViewImageScalingKey = @"CPImageViewImageScalingKey",
|
||||
CPImageViewImageAlignmentKey = @"CPImageViewImageAlignmentKey",
|
||||
CPImageViewHasShadowKey = @"CPImageViewHasShadowKey",
|
||||
CPImageViewIsEditableKey = @"CPImageViewIsEditableKey";
|
||||
|
||||
@implementation CPImageView (CPCoding)
|
||||
|
||||
@@ -416,6 +497,7 @@ var CPImageViewImageKey = @"CPImageViewImageKey",
|
||||
#endif
|
||||
|
||||
[self setHasShadow:[aCoder decodeBoolForKey:CPImageViewHasShadowKey]];
|
||||
[self setImageAlignment:[aCoder decodeIntForKey:CPImageViewImageAlignmentKey]];
|
||||
|
||||
if ([aCoder decodeBoolForKey:CPImageViewIsEditableKey] || NO)
|
||||
[self setEditable:YES];
|
||||
@@ -450,6 +532,7 @@ var CPImageViewImageKey = @"CPImageViewImageKey",
|
||||
_subviews = actualSubviews;
|
||||
|
||||
[aCoder encodeBool:_hasShadow forKey:CPImageViewHasShadowKey];
|
||||
[aCoder encodeInt:_imageAlignment forKey:CPImageViewImageAlignmentKey];
|
||||
|
||||
if (_isEditable)
|
||||
[aCoder encodeBool:_isEditable forKey:CPImageViewIsEditableKey];
|
||||
|
||||
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* CPKeyBinding.j
|
||||
* AppKit
|
||||
*
|
||||
* Created by Nicholas Small.
|
||||
* Copyright 2010, 280 North, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
|
||||
CPStandardKeyBindings = {
|
||||
@"@.": @"cancelOperation:",
|
||||
|
||||
@"^a": @"moveToBeginningOfParagraph:",
|
||||
@"^$a": @"moveToBeginningOfParagraphAndModifySelection:",
|
||||
@"^b": @"moveBackward:",
|
||||
@"^$b": @"moveBackwardAndModifySelection:",
|
||||
@"^~b": @"moveWordBackward:",
|
||||
@"^~$b": @"moveWordBackwardAndModifySelection:",
|
||||
@"^d": @"deleteForward:",
|
||||
@"^e": @"moveToEndOfParagraph:",
|
||||
@"^$e": @"moveToEndOfParagraphAndModifySelection:",
|
||||
@"^f": @"moveForward:",
|
||||
@"^$f": @"moveForwardAndModifySelection:",
|
||||
@"^~f": @"moveWordForward:",
|
||||
@"^~$f": @"moveWordForwardAndModifySelection:",
|
||||
@"^h": @"deleteBackward:",
|
||||
@"^k": @"deleteToEndOfParagraph:",
|
||||
@"^l": @"centerSelectionInVisibleArea:",
|
||||
@"^n": @"moveDown:",
|
||||
@"^$n": @"moveDownAndModifySelection:",
|
||||
@"^o": [@"insertNewlineIgnoringFieldEditor:", @"moveBackward:"],
|
||||
@"^p": @"moveUp:",
|
||||
@"^$p": @"moveUpAndModifySelection:",
|
||||
@"^t": @"transpose:",
|
||||
@"^v": @"pageDown:",
|
||||
@"^$v": @"pageDownAndModifySelection:",
|
||||
@"^y": @"yank:"
|
||||
};
|
||||
|
||||
CPStandardKeyBindings[CPNewlineCharacter] = @"insertNewline:";
|
||||
CPStandardKeyBindings[CPCarriageReturnCharacter] = @"insertNewline:";
|
||||
CPStandardKeyBindings[CPEnterCharacter] = @"insertNewline:";
|
||||
CPStandardKeyBindings[@"~" + CPNewlineCharacter] = @"insertNewlineIgnoringFieldEditor:";
|
||||
CPStandardKeyBindings[@"~" + CPCarriageReturnCharacter] = @"insertNewlineIgnoringFieldEditor:";
|
||||
CPStandardKeyBindings[@"~" + CPEnterCharacter] = @"insertNewlineIgnoringFieldEditor:";
|
||||
CPStandardKeyBindings[@"^" + CPNewlineCharacter] = @"insertLineBreak:";
|
||||
CPStandardKeyBindings[@"^" + CPCarriageReturnCharacter] = @"insertLineBreak:";
|
||||
CPStandardKeyBindings[@"^" + CPEnterCharacter] = @"insertLineBreak:";
|
||||
|
||||
CPStandardKeyBindings[CPBackspaceCharacter] = @"deleteBackward:";
|
||||
CPStandardKeyBindings[@"~" + CPBackspaceCharacter] = @"deleteWordBackward:";
|
||||
CPStandardKeyBindings[CPDeleteCharacter] = @"deleteBackward:";
|
||||
CPStandardKeyBindings[@"@" + CPDeleteCharacter] = @"deleteToBeginningOfLine:";
|
||||
CPStandardKeyBindings[@"~" + CPDeleteCharacter] = @"deleteWordBackward:";
|
||||
CPStandardKeyBindings[@"^" + CPDeleteCharacter] = @"deleteBackwardByDecomposingPreviousCharacter:";
|
||||
CPStandardKeyBindings[@"^~" + CPDeleteCharacter] = @"deleteWordBackward:";
|
||||
|
||||
CPStandardKeyBindings[CPDeleteFunctionKey] = @"deleteForward:";
|
||||
CPStandardKeyBindings[@"~" + CPDeleteFunctionKey] = @"deleteWordForward:";
|
||||
|
||||
CPStandardKeyBindings[CPTabCharacter] = @"insertTab:";
|
||||
CPStandardKeyBindings[@"~" + CPTabCharacter] = @"insertTabIgnoringFieldEditor:";
|
||||
CPStandardKeyBindings[@"^" + CPTabCharacter] = @"selectNextKeyView:";
|
||||
CPStandardKeyBindings[CPBackTabCharacter] = @"insertBacktab:";
|
||||
CPStandardKeyBindings[@"^" + CPBackTabCharacter] = @"selectPreviousKeyView:";
|
||||
|
||||
CPStandardKeyBindings[CPEscapeFunctionKey] = @"cancelOperation:";
|
||||
CPStandardKeyBindings[@"~" + CPEscapeFunctionKey] = @"complete:";
|
||||
CPStandardKeyBindings[CPF5FunctionKey] = @"complete:";
|
||||
|
||||
CPStandardKeyBindings[CPLeftArrowFunctionKey] = @"moveLeft:";
|
||||
CPStandardKeyBindings[@"~" + CPLeftArrowFunctionKey] = @"moveWordLeft:";
|
||||
CPStandardKeyBindings[@"^" + CPLeftArrowFunctionKey] = @"moveToLeftEndOfLine:";
|
||||
CPStandardKeyBindings[@"@" + CPLeftArrowFunctionKey] = @"moveToLeftEndOfLine:";
|
||||
CPStandardKeyBindings[@"$" + CPLeftArrowFunctionKey] = @"moveLeftAndModifySelection:";
|
||||
CPStandardKeyBindings[@"$~" + CPLeftArrowFunctionKey] = @"moveWordLeftAndModifySelection:";
|
||||
CPStandardKeyBindings[@"$^" + CPLeftArrowFunctionKey] = @"moveToLeftEndOfLineAndModifySelection:";
|
||||
CPStandardKeyBindings[@"$@" + CPLeftArrowFunctionKey] = @"moveToLeftEndOfLineAndModifySelection:";
|
||||
CPStandardKeyBindings[@"@^" + CPLeftArrowFunctionKey] = @"makeBaseWritingDirectionRightToLeft:";
|
||||
CPStandardKeyBindings[@"@^~" + CPLeftArrowFunctionKey] = @"makeTextWritingDirectionRightToLeft:";
|
||||
|
||||
CPStandardKeyBindings[CPRightArrowFunctionKey] = @"moveRight:";
|
||||
CPStandardKeyBindings[@"~" + CPRightArrowFunctionKey] = @"moveWordRight:";
|
||||
CPStandardKeyBindings[@"^" + CPRightArrowFunctionKey] = @"moveToRightEndOfLine:";
|
||||
CPStandardKeyBindings[@"@" + CPRightArrowFunctionKey] = @"moveToRightEndOfLine:";
|
||||
CPStandardKeyBindings[@"$" + CPRightArrowFunctionKey] = @"moveRightAndModifySelection:";
|
||||
CPStandardKeyBindings[@"$~" + CPRightArrowFunctionKey] = @"moveWordRightAndModifySelection:";
|
||||
CPStandardKeyBindings[@"$^" + CPRightArrowFunctionKey] = @"moveToRightEndOfLineAndModifySelection:";
|
||||
CPStandardKeyBindings[@"$@" + CPRightArrowFunctionKey] = @"moveToRightEndOfLineAndModifySelection:";
|
||||
CPStandardKeyBindings[@"@^" + CPRightArrowFunctionKey] = @"makeBaseWritingDirectionLeftToRight:";
|
||||
CPStandardKeyBindings[@"@^~" + CPRightArrowFunctionKey] = @"makeTextWritingDirectionLeftToRight:";
|
||||
|
||||
CPStandardKeyBindings[CPUpArrowFunctionKey] = @"moveUp:";
|
||||
CPStandardKeyBindings[@"~" + CPUpArrowFunctionKey] = [@"moveBackward:", @"moveToBeginningOfParagraph:"];
|
||||
CPStandardKeyBindings[@"^" + CPUpArrowFunctionKey] = @"scrollPageUp:";
|
||||
CPStandardKeyBindings[@"@" + CPUpArrowFunctionKey] = @"moveToBeginningOfDocument:";
|
||||
CPStandardKeyBindings[@"$" + CPUpArrowFunctionKey] = @"moveUpAndModifySelection:";
|
||||
CPStandardKeyBindings[@"$~" + CPUpArrowFunctionKey] = @"moveParagraphBackwardAndModifySelection:";
|
||||
CPStandardKeyBindings[@"$@" + CPUpArrowFunctionKey] = @"moveToBeginningOfDocumentAndModifySelection:";
|
||||
|
||||
CPStandardKeyBindings[CPDownArrowFunctionKey] = @"moveDown:";
|
||||
CPStandardKeyBindings[@"~" + CPDownArrowFunctionKey] = [@"moveForward:", @"moveToEndOfParagraph:"];
|
||||
CPStandardKeyBindings[@"^" + CPDownArrowFunctionKey] = @"scrollPageDown:";
|
||||
CPStandardKeyBindings[@"@" + CPDownArrowFunctionKey] = @"moveToEndOfDocument:";
|
||||
CPStandardKeyBindings[@"$" + CPDownArrowFunctionKey] = @"moveDownAndModifySelection:";
|
||||
CPStandardKeyBindings[@"$~" + CPDownArrowFunctionKey] = @"moveParagraphForwardAndModifySelection:";
|
||||
CPStandardKeyBindings[@"$@" + CPDownArrowFunctionKey] = @"moveToEndOfDocumentAndModifySelection:";
|
||||
CPStandardKeyBindings[@"@^" + CPDownArrowFunctionKey] = @"makeBaseWritingDirectionNatural:";
|
||||
CPStandardKeyBindings[@"@^~" + CPDownArrowFunctionKey] = @"makeTextWritingDirectionNatural:";
|
||||
|
||||
CPStandardKeyBindings[CPHomeFunctionKey] = @"scrollToBeginningOfDocument:";
|
||||
CPStandardKeyBindings[@"$" + CPHomeFunctionKey] = @"moveToBeginningOfDocumentAndModifySelection:";
|
||||
CPStandardKeyBindings[CPEndFunctionKey] = @"scrollToEndOfDocument:";
|
||||
CPStandardKeyBindings[@"$" + CPEndFunctionKey] = @"moveToEndOfDocumentAndModifySelection:";
|
||||
|
||||
CPStandardKeyBindings[CPPageUpFunctionKey] = @"scrollPageUp:";
|
||||
CPStandardKeyBindings[@"~" + CPPageUpFunctionKey] = @"pageUp:";
|
||||
CPStandardKeyBindings[@"$" + CPPageUpFunctionKey] = @"pageUpAndModifySelection:";
|
||||
CPStandardKeyBindings[CPPageDownFunctionKey] = @"scrollPageDown:";
|
||||
CPStandardKeyBindings[@"~" + CPPageDownFunctionKey] = @"pageDown:";
|
||||
CPStandardKeyBindings[@"$" + CPPageDownFunctionKey] = @"pageDownAndModifySelection:";
|
||||
|
||||
var CPKeyBindingCache = {};
|
||||
|
||||
@implementation CPKeyBinding : CPObject
|
||||
{
|
||||
CPString _key;
|
||||
unsigned _modifierFlags;
|
||||
|
||||
CPArray _selectors;
|
||||
|
||||
CPString _cacheName;
|
||||
}
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if ([self class] !== CPKeyBinding)
|
||||
return;
|
||||
|
||||
[self createKeyBindingsFromJSObject:CPStandardKeyBindings];
|
||||
}
|
||||
|
||||
+ (void)createKeyBindingsFromJSObject:(JSObject)anObject
|
||||
{
|
||||
var binding;
|
||||
for (binding in anObject)
|
||||
{
|
||||
var components = binding.split(@""),
|
||||
modifierFlags = ([components containsObject:@"$"] ? CPShiftKeyMask : 0) |
|
||||
([components containsObject:@"^"] ? CPControlKeyMask : 0) |
|
||||
([components containsObject:@"~"] ? CPAlternateKeyMask : 0) |
|
||||
([components containsObject:@"@"] ? CPCommandKeyMask : 0);
|
||||
|
||||
var selectors = anObject[binding];
|
||||
if (![selectors isKindOfClass:CPArray])
|
||||
selectors = [selectors];
|
||||
|
||||
var keyBinding = [[self alloc] initWithKey:[components lastObject] modifierFlags:modifierFlags selectors:selectors];
|
||||
[self cacheKeyBinding:keyBinding];
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)cacheKeyBinding:(CPKeyBinding)aBinding
|
||||
{
|
||||
if (!aBinding)
|
||||
return;
|
||||
|
||||
CPKeyBindingCache[[aBinding _cacheName]] = aBinding;
|
||||
}
|
||||
|
||||
+ (CPKeyBinding)keyBindingForKey:(CPString)aKey modifierFlags:(unsigned)aFlag
|
||||
{
|
||||
var tempBinding = [[self alloc] initWithKey:aKey modifierFlags:aFlag selectors:nil];
|
||||
return CPKeyBindingCache[[tempBinding _cacheName]];
|
||||
}
|
||||
|
||||
+ (CPArray)selectorsForKey:(CPString)aKey modifierFlags:(unsigned)aFlag
|
||||
{
|
||||
return [[self keyBindingForKey:aKey modifierFlags:aFlag] selectors];
|
||||
}
|
||||
|
||||
- (id)initWithKey:(CPString)aKey modifierFlags:(unsigned)aFlag selectors:(CPArray)selectors
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_key = aKey;
|
||||
_modifierFlags = aFlag;
|
||||
|
||||
_selectors = selectors;
|
||||
|
||||
// We normalize our key binding string in order to properly cache it.
|
||||
// We want to ensure the modifiers are always in the same order.
|
||||
var cacheName = [];
|
||||
|
||||
if (_modifierFlags & CPCommandKeyMask)
|
||||
cacheName.push(@"@");
|
||||
if (_modifierFlags & CPControlKeyMask)
|
||||
cacheName.push(@"^");
|
||||
if (_modifierFlags & CPAlternateKeyMask)
|
||||
cacheName.push(@"~");
|
||||
if (_modifierFlags & CPShiftKeyMask)
|
||||
cacheName.push(@"$");
|
||||
|
||||
cacheName.push(_key);
|
||||
|
||||
_cacheName = cacheName.join(@"");
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CPString)key
|
||||
{
|
||||
return _key;
|
||||
}
|
||||
|
||||
- (unsigned)modifierFlags
|
||||
{
|
||||
return _modifierFlags;
|
||||
}
|
||||
|
||||
- (CPArray)selectors
|
||||
{
|
||||
return _selectors;
|
||||
}
|
||||
|
||||
- (CPString)_cacheName
|
||||
{
|
||||
return _cacheName;
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(CPKeyBinding)rhs
|
||||
{
|
||||
return _key === [rhs key] && _modifierFlags === [rhs modifierFlags];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -108,7 +108,7 @@ var CPBindingOperationAnd = 0,
|
||||
count = allKeys.length;
|
||||
|
||||
while (count--)
|
||||
[anObject unbind:[bindings objectForKey:allKeys[count]]]
|
||||
[anObject unbind:[bindings objectForKey:allKeys[count]]];
|
||||
|
||||
[bindingsMap removeObjectForKey:[anObject hash]];
|
||||
}
|
||||
@@ -181,7 +181,19 @@ var CPBindingOperationAnd = 0,
|
||||
valueTransformer;
|
||||
|
||||
if (valueTransformerName)
|
||||
{
|
||||
valueTransformer = [CPValueTransformer valueTransformerForName:valueTransformerName];
|
||||
|
||||
if (!valueTransformer)
|
||||
{
|
||||
var valueTransformerClass = CPClassFromString(valueTransformerName);
|
||||
if (valueTransformerClass)
|
||||
{
|
||||
valueTransformer = [[valueTransformerClass alloc] init];
|
||||
[valueTransformerClass setValueTransformer:valueTransformer forName:valueTransformerName];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
valueTransformer = [options objectForKey:CPValueTransformerBindingOption];
|
||||
|
||||
@@ -263,7 +275,7 @@ var CPBindingOperationAnd = 0,
|
||||
// CPLog.warn("No binding exposed on "+self+" for "+aBinding);
|
||||
|
||||
[self unbind:aBinding];
|
||||
[[CPKeyValueBinding alloc] initWithBinding:[anObject _replacementKeyPathForBinding:aBinding] name:aBinding to:anObject keyPath:aKeyPath options:options from:self];
|
||||
[[CPKeyValueBinding alloc] initWithBinding:[self _replacementKeyPathForBinding:aBinding] name:aBinding to:anObject keyPath:aKeyPath options:options from:self];
|
||||
}
|
||||
|
||||
- (CPDictionary)infoForBinding:(CPString)aBinding
|
||||
|
||||
@@ -75,7 +75,7 @@ var _CPMenuBarVisible = NO,
|
||||
|
||||
id _delegate;
|
||||
|
||||
CPMenuItem _highlightedIndex;
|
||||
int _highlightedIndex;
|
||||
_CPMenuWindow _menuWindow;
|
||||
}
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ var SharedMenuManager = nil;
|
||||
|
||||
// Close Menu Event.
|
||||
if (type === CPAppKitDefined)
|
||||
return [self completeTracking]
|
||||
return [self completeTracking];
|
||||
|
||||
[CPApp setTarget:self selector:@selector(trackEvent:) forNextEventMatchingMask:CPPeriodicMask | CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPAppKitDefinedMask untilDate:nil inMode:nil dequeue:YES];
|
||||
|
||||
|
||||
@@ -591,7 +591,8 @@ CPControlKeyMask
|
||||
return @"";
|
||||
|
||||
var string = _keyEquivalent.toUpperCase(),
|
||||
needsShift = _keyEquivalentModifierMask & CPShiftKeyMask || string === _keyEquivalent;
|
||||
needsShift = _keyEquivalentModifierMask & CPShiftKeyMask ||
|
||||
(string === _keyEquivalent && _keyEquivalent.toLowerCase() !== _keyEquivalent.toUpperCase());
|
||||
|
||||
if (CPBrowserIsOperatingSystem(CPMacOperatingSystem))
|
||||
{
|
||||
@@ -781,7 +782,48 @@ CPControlKeyMask
|
||||
return [[self menu] highlightedItem] == self;
|
||||
}
|
||||
|
||||
//
|
||||
#pragma mark CPObject Overrides
|
||||
|
||||
/*!
|
||||
Returns a copy of the item. The copy does not belong If the item has a submenu, it is NOT copied.
|
||||
*/
|
||||
- (id)copy
|
||||
{
|
||||
var item = [[CPMenuItem alloc] init];
|
||||
|
||||
// No point in going through accessors and doing lots of unnecessary state checking/updating
|
||||
item._isSeparator = _isSeparator;
|
||||
|
||||
[item setTitle:_title];
|
||||
[item setFont:_font];
|
||||
[item setTarget:_target];
|
||||
[item setAction:_action];
|
||||
[item setEnabled:_isEnabled];
|
||||
[item setHidden:_isHidden]
|
||||
[item setTag:_tag];
|
||||
[item setState:_state];
|
||||
[item setImage:_image];
|
||||
[item setAlternateImage:_alternateImage];
|
||||
[item setOnStateImage:_onStateImage];
|
||||
[item setOffStateImage:_offStateImage];
|
||||
[item setMixedStateImage:_mixedStateImage];
|
||||
[item setKeyEquivalent:_keyEquivalent];
|
||||
[item setKeyEquivalentModifierMask:_keyEquivalentModifierMask];
|
||||
[item setMnemonicLocation:_mnemonicLocation];
|
||||
[item setAlternate:_isAlternate];
|
||||
[item setIndentationLevel:_indentationLevel];
|
||||
[item setToolTip:_toolTip];
|
||||
[item setRepresentedObject:_representedObject];
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
- (id)mutableCopy
|
||||
{
|
||||
return [self copy];
|
||||
}
|
||||
|
||||
#pragma mark Internal
|
||||
|
||||
/*
|
||||
@ignore
|
||||
@@ -860,7 +902,6 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
|
||||
_isHidden = DEFAULT_VALUE(CPMenuItemIsHiddenKey, NO);
|
||||
_tag = DEFAULT_VALUE(CPMenuItemTagKey, 0);
|
||||
_state = DEFAULT_VALUE(CPMenuItemStateKey, CPOffState);
|
||||
// int _state;
|
||||
|
||||
_image = DEFAULT_VALUE(CPMenuItemImageKey, nil);
|
||||
_alternateImage = DEFAULT_VALUE(CPMenuItemAlternateImageKey, nil);
|
||||
|
||||
@@ -62,6 +62,7 @@ var SelectionColor = nil,
|
||||
_imageAndTextView = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(HORIZONTAL_MARGIN, 0.0, 0.0, 0.0)];
|
||||
|
||||
[_imageAndTextView setImagePosition:CPImageLeft];
|
||||
[_imageAndTextView setImageOffset:3.0];
|
||||
[_imageAndTextView setTextShadowOffset:CGSizeMake(0.0, 1.0)];
|
||||
[_imageAndTextView setAutoresizingMask:CPViewMinYMargin | CPViewMaxYMargin];
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ var SUBMENU_INDICATOR_COLOR = nil,
|
||||
SUBMENU_INDICATOR_COLOR = [CPColor grayColor];
|
||||
|
||||
_CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0];
|
||||
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0]
|
||||
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0];
|
||||
|
||||
var bundle = [CPBundle bundleForClass:self];
|
||||
|
||||
@@ -257,10 +257,13 @@ var SUBMENU_INDICATOR_COLOR = nil,
|
||||
[_keyEquivalentView setTextShadowColor:[self textShadowColor]];
|
||||
}
|
||||
|
||||
if (shouldHighlight)
|
||||
[_stateView setImage:_CPMenuItemDefaultStateHighlightedImages[[_menuItem state]] || nil];
|
||||
else
|
||||
[_stateView setImage:_CPMenuItemDefaultStateImages[[_menuItem state]] || nil];
|
||||
if ([[_menuItem menu] showsStateColumn])
|
||||
{
|
||||
if (shouldHighlight)
|
||||
[_stateView setImage:_CPMenuItemDefaultStateHighlightedImages[[_menuItem state]] || nil];
|
||||
else
|
||||
[_stateView setImage:_CPMenuItemDefaultStateImages[[_menuItem state]] || nil];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -43,7 +43,7 @@ var _CPMenuItemSelectionColor = nil,
|
||||
return;
|
||||
|
||||
_CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0];
|
||||
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0]
|
||||
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0];
|
||||
|
||||
var bundle = [CPBundle bundleForClass:self];
|
||||
|
||||
|
||||
@@ -51,15 +51,20 @@
|
||||
return [CPSet setWithObjects:"editable", "selection"];
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
return [self initWithContent:nil];
|
||||
}
|
||||
|
||||
- (id)initWithContent:(id)aContent
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (self)
|
||||
if (self = [super init])
|
||||
{
|
||||
[self setContent:aContent];
|
||||
[self setEditable:YES];
|
||||
[self setObjectClass:[CPMutableDictionary class]];
|
||||
|
||||
_observedKeys = [[CPCountedSet alloc] init];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -452,7 +457,12 @@ var CPObjectControllerObjectClassNameKey = @"CPObjectControllerOb
|
||||
[self didChangeValueForKey:keyPath];
|
||||
}
|
||||
|
||||
[self removeObjectAtIndex:anIndex];
|
||||
[super removeObjectAtIndex:anIndex];
|
||||
}
|
||||
|
||||
- (_CPObservableArray)objectsAtIndexes:(CPIndexSet)theIndexes
|
||||
{
|
||||
return [_CPObservableArray arrayWithArray:[super objectsAtIndexes:theIndexes]];
|
||||
}
|
||||
|
||||
- (void)addObject:(id)anObject
|
||||
|
||||
@@ -624,7 +624,7 @@ CPOutlineViewDropOnItemIndex = -1;
|
||||
if (_dropItem)
|
||||
{
|
||||
[_dropOperationFeedbackView blink];
|
||||
[CPTimer scheduledTimerWithTimeInterval:.3 callback:objj_msgSend(self, "expandItem:", _dropItem) repeats:NO]; //[self expandItem:_dropItem];
|
||||
[CPTimer scheduledTimerWithTimeInterval:.3 callback:objj_msgSend(self, "expandItem:", _dropItem) repeats:NO];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -645,10 +645,18 @@ CPOutlineViewDropOnItemIndex = -1;
|
||||
_shouldRetargetChildIndex = YES;
|
||||
|
||||
// set CPTableView's _retargetedDropRow based on retargetedItem and retargetedChildIndex
|
||||
var retargetedItemInfo = (_retargetedItem !== nil) ? _itemInfosForItems[[_retargetedItem UID]] : _rootItemInfo,
|
||||
retargetedChildItem = (_retargedChildIndex !== CPOutlineViewDropOnItemIndex) ? retargetedItemInfo.children[_retargedChildIndex] : _retargetedItem;
|
||||
var retargetedItemInfo = (_retargetedItem !== nil) ? _itemInfosForItems[[_retargetedItem UID]] : _rootItemInfo;
|
||||
|
||||
_retargetedDropRow = [self rowForItem:retargetedChildItem];
|
||||
if (_retargedChildIndex === [retargetedItemInfo.children count])
|
||||
{
|
||||
var retargetedChildItem = [retargetedItemInfo.children lastObject];
|
||||
_retargetedDropRow = [self rowForItem:retargetedChildItem] + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
var retargetedChildItem = (_retargedChildIndex !== CPOutlineViewDropOnItemIndex) ? retargetedItemInfo.children[_retargedChildIndex] : _retargetedItem;
|
||||
_retargetedDropRow = [self rowForItem:retargetedChildItem];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_draggingEnded
|
||||
@@ -1102,7 +1110,7 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
_outlineView._shouldRetargetChildIndex = NO;
|
||||
|
||||
var location = [_outlineView convertPoint:[theInfo draggingLocation] fromView:nil],
|
||||
parentItem = [self _parentItemForDropOperation:theOperation row:theRow offset:location];
|
||||
parentItem = [self _parentItemForDropOperation:theOperation row:theRow offset:location],
|
||||
childIndex = [self _childIndexForDropOperation:theOperation row:theRow offset:location];
|
||||
|
||||
return [_outlineView._outlineViewDataSource outlineView:_outlineView validateDrop:theInfo proposedItem:parentItem proposedChildIndex:childIndex];
|
||||
@@ -1247,11 +1255,82 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
|
||||
CGContextAddLineToPoint(context, 0.0, 0.0);
|
||||
|
||||
CGContextClosePath(context);
|
||||
var isHighlighted = [self hasThemeState:CPThemeStateHighlighted];
|
||||
var color = [self hasThemeState:CPThemeStateSelected] ? (isHighlighted ? [CPColor lightGrayColor] : [CPColor whiteColor]) : (isHighlighted ? [CPColor blackColor] : [CPColor grayColor]);
|
||||
|
||||
CGContextSetFillColor(context, color);
|
||||
CGContextSetFillColor(context,
|
||||
colorForDisclosureTriangle([self hasThemeState:CPThemeStateSelected],
|
||||
[self hasThemeState:CPThemeStateHighlighted]));
|
||||
CGContextFillPath(context);
|
||||
|
||||
|
||||
CGContextBeginPath(context);
|
||||
CGContextMoveToPoint(context, 0.0, 0.0);
|
||||
if(_angle === 0.0) {
|
||||
CGContextAddLineToPoint(context, 4.5, 8.0);
|
||||
CGContextAddLineToPoint(context, 9.0, 0.0);
|
||||
} else {
|
||||
CGContextAddLineToPoint(context, 4.5, 8.0);
|
||||
}
|
||||
CGContextSetStrokeColor(context, [CPColor colorWithCalibratedWhite:1.0 alpha: 0.8]);
|
||||
CGContextStrokePath(context);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
var CPOutlineViewIndentationPerLevelKey = @"CPOutlineViewIndentationPerLevelKey",
|
||||
CPOutlineViewOutlineTableColumnKey = @"CPOutlineViewOutlineTableColumnKey",
|
||||
CPOutlineViewDataSourceKey = @"CPOutlineViewDataSourceKey",
|
||||
CPOutlineViewDelegateKey = @"CPOutlineViewDelegateKey";
|
||||
|
||||
@implementation CPOutlineView (CPCoding)
|
||||
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
|
||||
if (self)
|
||||
{
|
||||
// The root item has weight "0", thus represents the weight solely of its descendants.
|
||||
_rootItemInfo = { isExpanded:YES, isExpandable:NO, level:-1, row:-1, children:[], weight:0 };
|
||||
|
||||
_itemsForRows = [];
|
||||
_itemInfosForItems = { };
|
||||
_disclosureControlsForRows = [];
|
||||
|
||||
[self setIndentationMarkerFollowsDataView:YES];
|
||||
[self setDisclosureControlPrototype:[[CPDisclosureButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 10.0, 10.0)]];
|
||||
|
||||
_outlineTableColumn = [aCoder decodeObjectForKey:CPOutlineViewOutlineTableColumnKey];
|
||||
_indentationPerLevel = [aCoder decodeFloatForKey:CPOutlineViewIndentationPerLevelKey];
|
||||
|
||||
_outlineViewDataSource = [aCoder decodeObjectForKey:CPOutlineViewDataSourceKey];
|
||||
_outlineViewDelegate = [aCoder decodeObjectForKey:CPOutlineViewDelegateKey];
|
||||
|
||||
[super setDataSource:[[_CPOutlineViewTableViewDataSource alloc] initWithOutlineView:self]];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
[aCoder encodeObject:_outlineTableColumn forKey:CPOutlineViewOutlineTableColumnKey];
|
||||
[aCoder encodeFloat:_indentationPerLevel forKey:CPOutlineViewIndentationPerLevelKey];
|
||||
|
||||
[aCoder encodeObject:_outlineViewDataSource forKey:CPOutlineViewDataSourceKey];
|
||||
[aCoder encodeObject:_outlineViewDelegate forKey:CPOutlineViewDelegateKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
var colorForDisclosureTriangle = function(isSelected, isHighlighted) {
|
||||
return isSelected
|
||||
? (isHighlighted
|
||||
? [CPColor colorWithCalibratedWhite:0.9 alpha: 1.0]
|
||||
: [CPColor colorWithCalibratedWhite:1.0 alpha: 1.0])
|
||||
: (isHighlighted
|
||||
? [CPColor colorWithCalibratedWhite:0.4 alpha: 1.0]
|
||||
: [CPColor colorWithCalibratedWhite:0.5 alpha: 1.0]);
|
||||
}
|
||||
|
||||
@@ -662,6 +662,9 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
|
||||
location = CGPointMake(CGRectGetMinX(contentRect) - standardLeftMargin, 0.0);
|
||||
|
||||
minimumWidth += standardLeftMargin;
|
||||
|
||||
// To ensure the selected item is highlighted correctly, unset the highlighted item
|
||||
[menu _highlightItemAtIndex:CPNotFound];
|
||||
}
|
||||
|
||||
[menu setMinimumWidth:minimumWidth];
|
||||
|
||||
@@ -27,26 +27,26 @@
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
|
||||
|
||||
from this mailing list thread:
|
||||
http://groups.google.com/group/objectivej/browse_thread/thread/7c41cbd9cbee9ea3
|
||||
|
||||
http://groups.google.com/group/objectivej/browse_thread/thread/7c41cbd9cbee9ea3
|
||||
|
||||
-----------------------------------
|
||||
|
||||
|
||||
Creating a checkbox is easy enough:
|
||||
|
||||
|
||||
checkbox = [[CPCheckBox alloc] initWithFrame:aFrame];
|
||||
|
||||
|
||||
That's basically all there is to it. Radio buttons are very similar,
|
||||
the key difference is the introduction of a new class CPRadioGroup,
|
||||
which defines which radio buttons are part of the same group:
|
||||
|
||||
|
||||
[myRadioButton setRadioGroup:aRadioGroup];
|
||||
|
||||
|
||||
Every radio button receives a unique radio group by default (so if you
|
||||
do nothing further, they will all behave independently), but you can
|
||||
use an existing radio button's group with other buttons as so:
|
||||
|
||||
|
||||
button1 = [[CPRadio alloc] initWithFrame:aFrame];
|
||||
...
|
||||
button2 = [[CPRadio alloc] initWithFrame:aFrame radioGroup:[button1
|
||||
@@ -55,13 +55,16 @@
|
||||
button3 = [[CPRadio alloc] initWithFrame:aFrame radioGroup:[button1
|
||||
radioGroup]];
|
||||
...etc...
|
||||
|
||||
|
||||
Here, all the radio buttons will act "together". [[button1 radioGroup]
|
||||
allRadios] returns every button that's part of this group, and
|
||||
[[button1 radioGroup] selectedRadio] returns the currently selected
|
||||
option.
|
||||
|
||||
*/
|
||||
|
||||
CPRadioImageOffset = 4.0;
|
||||
|
||||
@implementation CPRadio : CPButton
|
||||
{
|
||||
CPRadioGroup _radioGroup;
|
||||
@@ -95,7 +98,7 @@
|
||||
- (id)initWithFrame:(CGRect)aFrame radioGroup:(CPRadioGroup)aRadioGroup
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
[self setRadioGroup:aRadioGroup];
|
||||
@@ -109,8 +112,8 @@
|
||||
|
||||
[self setBordered:YES];
|
||||
}
|
||||
|
||||
return self;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
@@ -141,7 +144,7 @@
|
||||
- (void)setObjectValue:(id)aValue
|
||||
{
|
||||
[super setObjectValue:aValue];
|
||||
|
||||
|
||||
if ([self state] === CPOnState)
|
||||
[_radioGroup _setSelectedRadio:self];
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
|
||||
@import <Foundation/CPObject.j>
|
||||
|
||||
|
||||
CPDeleteKeyCode = 8;
|
||||
CPTabKeyCode = 9;
|
||||
CPReturnKeyCode = 13;
|
||||
@@ -39,7 +38,7 @@ CPDeleteForwardKeyCode = 46;
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPResponder
|
||||
|
||||
|
||||
Subclasses of CPResonder can be part of the responder chain.
|
||||
*/
|
||||
@implementation CPResponder : CPObject
|
||||
@@ -105,42 +104,24 @@ CPDeleteForwardKeyCode = 46;
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var event = events[index];
|
||||
var event = events[index],
|
||||
modifierFlags = [event modifierFlags],
|
||||
character = [event charactersIgnoringModifiers],
|
||||
selectorNames = [CPKeyBinding selectorsForKey:character modifierFlags:modifierFlags];
|
||||
|
||||
switch([event keyCode])
|
||||
if (selectorNames)
|
||||
{
|
||||
case CPPageUpKeyCode: [self doCommandBySelector:@selector(pageUp:)];
|
||||
break;
|
||||
case CPPageDownKeyCode: [self doCommandBySelector:@selector(pageDown:)];
|
||||
break;
|
||||
case CPLeftArrowKeyCode: [self doCommandBySelector:@selector(moveLeft:)];
|
||||
break;
|
||||
case CPRightArrowKeyCode: [self doCommandBySelector:@selector(moveRight:)];
|
||||
break;
|
||||
case CPUpArrowKeyCode: [self doCommandBySelector:@selector(moveUp:)];
|
||||
break;
|
||||
case CPDownArrowKeyCode: [self doCommandBySelector:@selector(moveDown:)];
|
||||
break;
|
||||
case CPDeleteKeyCode: [self doCommandBySelector:@selector(deleteBackward:)];
|
||||
break;
|
||||
case CPReturnKeyCode:
|
||||
case 3: [self doCommandBySelector:@selector(insertLineBreak:)];
|
||||
break;
|
||||
|
||||
case CPEscapeKeyCode: [self doCommandBySelector:@selector(cancel:)];
|
||||
break;
|
||||
for (var s = 0, scount = selectorNames.length; s < scount; s++)
|
||||
{
|
||||
var selector = selectorNames[s];
|
||||
if (!selector)
|
||||
continue;
|
||||
|
||||
case CPTabKeyCode: var shift = [event modifierFlags] & CPShiftKeyMask;
|
||||
|
||||
if (!shift)
|
||||
[self doCommandBySelector:@selector(insertTab:)];
|
||||
else
|
||||
[self doCommandBySelector:@selector(insertBackTab:)];
|
||||
|
||||
break;
|
||||
|
||||
default: [self insertText:[event characters]];
|
||||
[self doCommandBySelector:CPSelectorFromString(selector)];
|
||||
}
|
||||
}
|
||||
else if (!(modifierFlags & (CPCommandKeyMask | CPControlKeyMask)) && [self respondsToSelector:@selector(insertText:)])
|
||||
[self insertText:[event characters]];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,6 +221,15 @@ CPDeleteForwardKeyCode = 46;
|
||||
[_nextResponder performSelector:_cmd withObject:anEvent];
|
||||
}
|
||||
|
||||
/*!
|
||||
Notifies the receiver that the user has pressed or released a modifier key (Shift, Control, and so on).
|
||||
@param anEvent information about the key press
|
||||
*/
|
||||
- (void)flagsChanged:(CPEvent)anEvent
|
||||
{
|
||||
[_nextResponder performSelector:_cmd withObject:anEvent];
|
||||
}
|
||||
|
||||
/*
|
||||
FIXME This description is bad.
|
||||
Based on \c anEvent, the receiver should simulate the event.
|
||||
@@ -316,7 +306,7 @@ CPDeleteForwardKeyCode = 46;
|
||||
if([self respondsToSelector:aSelector])
|
||||
{
|
||||
[self performSelector:aSelector withObject:anObject];
|
||||
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
@@ -367,10 +357,10 @@ var CPResponderNextResponderKey = @"CPResponderNextResponderKey";
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
if (self)
|
||||
_nextResponder = [aCoder decodeObjectForKey:CPResponderNextResponderKey];
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,23 +37,39 @@
|
||||
*/
|
||||
@implementation CPScrollView : CPView
|
||||
{
|
||||
CPClipView _contentView;
|
||||
CPClipView _headerClipView;
|
||||
CPView _cornerView;
|
||||
CPClipView _contentView;
|
||||
CPClipView _headerClipView;
|
||||
CPView _cornerView;
|
||||
CPView _bottomCornerView;
|
||||
|
||||
BOOL _hasVerticalScroller;
|
||||
BOOL _hasHorizontalScroller;
|
||||
BOOL _autohidesScrollers;
|
||||
BOOL _hasVerticalScroller;
|
||||
BOOL _hasHorizontalScroller;
|
||||
BOOL _autohidesScrollers;
|
||||
|
||||
CPScroller _verticalScroller;
|
||||
CPScroller _horizontalScroller;
|
||||
CPScroller _verticalScroller;
|
||||
CPScroller _horizontalScroller;
|
||||
|
||||
int _recursionCount;
|
||||
int _recursionCount;
|
||||
|
||||
float _verticalLineScroll;
|
||||
float _verticalPageScroll;
|
||||
float _horizontalLineScroll;
|
||||
float _horizontalPageScroll;
|
||||
float _verticalLineScroll;
|
||||
float _verticalPageScroll;
|
||||
float _horizontalLineScroll;
|
||||
float _horizontalPageScroll;
|
||||
|
||||
CPBorderType _borderType;
|
||||
}
|
||||
|
||||
+ (CPString)themeClass
|
||||
{
|
||||
return @"scrollview"
|
||||
}
|
||||
|
||||
+ (CPDictionary)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithJSObject:{
|
||||
@"bottom-corner-color": [CPColor whiteColor],
|
||||
@"border-color": [CPColor blackColor]
|
||||
}];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
@@ -68,14 +84,18 @@
|
||||
_horizontalLineScroll = 10.0;
|
||||
_horizontalPageScroll = 10.0;
|
||||
|
||||
_contentView = [[CPClipView alloc] initWithFrame:[self bounds]];
|
||||
_borderType = CPNoBorder;
|
||||
|
||||
_contentView = [[CPClipView alloc] initWithFrame:[self _insetBounds]];
|
||||
|
||||
[self addSubview:_contentView];
|
||||
|
||||
_headerClipView = [[CPClipView alloc] init];
|
||||
|
||||
[self addSubview:_headerClipView];
|
||||
|
||||
_bottomCornerView = [[CPView alloc] init];
|
||||
[self addSubview:_bottomCornerView];
|
||||
|
||||
[self setHasVerticalScroller:YES];
|
||||
[self setHasHorizontalScroller:YES];
|
||||
}
|
||||
@@ -83,6 +103,65 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
// Calculating Layout
|
||||
|
||||
+ (CGSize)contentSizeForFrameSize:(CGSize)frameSize hasHorizontalScroller:(BOOL)hFlag hasVerticalScroller:(BOOL)vFlag borderType:(CPBorderType)borderType
|
||||
{
|
||||
var bounds = [self _insetBounds:_CGRectMake(0.0, 0.0, frameSize.width, frameSize.height) borderType:borderType],
|
||||
scrollerWidth = [CPScroller scrollerWidth];
|
||||
|
||||
if (hFlag)
|
||||
bounds.size.height -= scrollerWidth;
|
||||
|
||||
if (vFlag)
|
||||
bounds.size.width -= scrollerWidth;
|
||||
|
||||
return bounds.size;
|
||||
}
|
||||
|
||||
+ (CGSize)frameSizeForContentSize:(CGSize)contentSize hasHorizontalScroller:(BOOL)hFlag hasVerticalScroller:(BOOL)vFlag borderType:(CPBorderType)borderType
|
||||
{
|
||||
var bounds = [self _insetBounds:_CGRectMake(0.0, 0.0, contentSize.width, contentSize.height) borderType:borderType],
|
||||
widthInset = contentSize.width - bounds.size.width,
|
||||
heightInset = contentSize.height - bounds.size.height,
|
||||
frameSize = _CGSizeMake(contentSize.width + widthInset, contentSize.height + heightInset),
|
||||
scrollerWidth = [CPScroller scrollerWidth];
|
||||
|
||||
if (hFlag)
|
||||
frameSize.height -= scrollerWidth;
|
||||
|
||||
if (vFlag)
|
||||
frameSize.width -= scrollerWidth;
|
||||
|
||||
return frameSize;
|
||||
}
|
||||
|
||||
+ (CGRect)_insetBounds:(CGRect)bounds borderType:(CPBorderType)borderType
|
||||
{
|
||||
switch (borderType)
|
||||
{
|
||||
case CPLineBorder:
|
||||
case CPBezelBorder:
|
||||
return _CGRectInset(bounds, 1.0, 1.0);
|
||||
|
||||
case CPGrooveBorder:
|
||||
bounds = _CGRectInset(bounds, 2.0, 2.0);
|
||||
++bounds.origin.y;
|
||||
--bounds.size.height;
|
||||
|
||||
return bounds;
|
||||
|
||||
case CPNoBorder:
|
||||
default:
|
||||
return bounds;
|
||||
}
|
||||
}
|
||||
|
||||
- (CGRect)_insetBounds
|
||||
{
|
||||
return [[self class] _insetBounds:[self bounds] borderType:_borderType];
|
||||
}
|
||||
|
||||
// Determining component sizes
|
||||
/*!
|
||||
Returns the size of the scroll view's content view.
|
||||
@@ -176,7 +255,7 @@
|
||||
// [_horizontalScroller setEnabled:NO];
|
||||
}
|
||||
|
||||
[_contentView setFrame:[self bounds]];
|
||||
[_contentView setFrame:[self _insetBounds]];
|
||||
[_headerClipView setFrame:_CGRectMakeZero()];
|
||||
|
||||
--_recursionCount;
|
||||
@@ -185,7 +264,7 @@
|
||||
}
|
||||
|
||||
var documentFrame = [documentView frame], // the size of the whole document
|
||||
contentFrame = [self bounds], // assume it takes up the entire size of the scrollview (no scrollers)
|
||||
contentFrame = [self _insetBounds], // assume it takes up the entire size of the scrollview (no scrollers)
|
||||
headerClipViewFrame = [self _headerClipViewFrame],
|
||||
headerClipViewHeight = _CGRectGetHeight(headerClipViewFrame);
|
||||
|
||||
@@ -235,11 +314,10 @@
|
||||
|
||||
if (shouldShowVerticalScroller)
|
||||
{
|
||||
var verticalScrollerY = MAX(_CGRectGetHeight([self _cornerViewFrame]), headerClipViewHeight),
|
||||
verticalScrollerHeight = _CGRectGetHeight([self bounds]) - verticalScrollerY;
|
||||
var verticalScrollerY =
|
||||
MAX(_CGRectGetMinY(contentFrame), MAX(_CGRectGetMaxY([self _cornerViewFrame]), _CGRectGetMaxY(headerClipViewFrame)));
|
||||
|
||||
if (shouldShowHorizontalScroller)
|
||||
verticalScrollerHeight -= horizontalScrollerHeight;
|
||||
var verticalScrollerHeight = _CGRectGetMaxY(contentFrame) - verticalScrollerY;
|
||||
|
||||
[_verticalScroller setFloatValue:(difference.height <= 0.0) ? 0.0 : scrollPoint.y / difference.height];
|
||||
[_verticalScroller setKnobProportion:_CGRectGetHeight(contentFrame) / _CGRectGetHeight(documentFrame)];
|
||||
@@ -255,7 +333,7 @@
|
||||
{
|
||||
[_horizontalScroller setFloatValue:(difference.width <= 0.0) ? 0.0 : scrollPoint.x / difference.width];
|
||||
[_horizontalScroller setKnobProportion:_CGRectGetWidth(contentFrame) / _CGRectGetWidth(documentFrame)];
|
||||
[_horizontalScroller setFrame:_CGRectMake(0.0, _CGRectGetMaxY(contentFrame), _CGRectGetWidth(contentFrame), horizontalScrollerHeight)];
|
||||
[_horizontalScroller setFrame:_CGRectMake(_CGRectGetMinX(contentFrame), _CGRectGetMaxY(contentFrame), _CGRectGetWidth(contentFrame), horizontalScrollerHeight)];
|
||||
}
|
||||
else if (wasShowingHorizontalScroller)
|
||||
{
|
||||
@@ -267,9 +345,36 @@
|
||||
[_headerClipView setFrame:headerClipViewFrame];
|
||||
[_cornerView setFrame:[self _cornerViewFrame]];
|
||||
|
||||
[[self bottomCornerView] setFrame:[self _bottomCornerViewFrame]];
|
||||
[[self bottomCornerView] setBackgroundColor:[self currentValueForThemeAttribute:@"bottom-corner-color"]];
|
||||
|
||||
--_recursionCount;
|
||||
}
|
||||
|
||||
// Managing Graphics Attributes
|
||||
|
||||
/*!
|
||||
Sets the type of border to be drawn around the view.
|
||||
*/
|
||||
- (void)setBorderType:(CPBorderType)borderType
|
||||
{
|
||||
if (_borderType == borderType)
|
||||
return;
|
||||
|
||||
_borderType = borderType;
|
||||
|
||||
[self reflectScrolledClipView:_contentView];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the border type drawn around the view.
|
||||
*/
|
||||
- (CPBorderType)borderType
|
||||
{
|
||||
return _borderType;
|
||||
}
|
||||
|
||||
// Managing Scrollers
|
||||
/*!
|
||||
Sets the scroll view's horizontal scroller.
|
||||
@@ -316,8 +421,10 @@
|
||||
|
||||
if (_hasHorizontalScroller && !_horizontalScroller)
|
||||
{
|
||||
[self setHorizontalScroller:[[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, MAX(_CGRectGetWidth([self bounds]), [CPScroller scrollerWidth]+1), [CPScroller scrollerWidth])]];
|
||||
[[self horizontalScroller] setFrameSize:CGSizeMake(_CGRectGetWidth([self bounds]), [CPScroller scrollerWidth])];
|
||||
var bounds = [self _insetBounds];
|
||||
|
||||
[self setHorizontalScroller:[[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, MAX(_CGRectGetWidth(bounds), [CPScroller scrollerWidth] + 1), [CPScroller scrollerWidth])]];
|
||||
[[self horizontalScroller] setFrameSize:CGSizeMake(_CGRectGetWidth(bounds), [CPScroller scrollerWidth])];
|
||||
}
|
||||
|
||||
[self reflectScrolledClipView:_contentView];
|
||||
@@ -377,8 +484,10 @@
|
||||
|
||||
if (_hasVerticalScroller && !_verticalScroller)
|
||||
{
|
||||
[self setVerticalScroller:[[CPScroller alloc] initWithFrame:_CGRectMake(0.0, 0.0, [CPScroller scrollerWidth], MAX(_CGRectGetHeight([self bounds]), [CPScroller scrollerWidth]+1))]];
|
||||
[[self verticalScroller] setFrameSize:CGSizeMake([CPScroller scrollerWidth], _CGRectGetHeight([self bounds]))];
|
||||
var bounds = [self _insetBounds];
|
||||
|
||||
[self setVerticalScroller:[[CPScroller alloc] initWithFrame:_CGRectMake(0.0, 0.0, [CPScroller scrollerWidth], MAX(_CGRectGetHeight(bounds), [CPScroller scrollerWidth] + 1))]];
|
||||
[[self verticalScroller] setFrameSize:CGSizeMake([CPScroller scrollerWidth], _CGRectGetHeight(bounds))];
|
||||
}
|
||||
|
||||
[self reflectScrolledClipView:_contentView];
|
||||
@@ -453,11 +562,11 @@
|
||||
if (!_cornerView)
|
||||
return _CGRectMakeZero();
|
||||
|
||||
var bounds = [self bounds],
|
||||
var bounds = [self _insetBounds],
|
||||
frame = [_cornerView frame];
|
||||
|
||||
frame.origin.x = _CGRectGetMaxX(bounds) - _CGRectGetWidth(frame);
|
||||
frame.origin.y = 0;
|
||||
frame.origin.y = _CGRectGetMinY(bounds);
|
||||
|
||||
return frame;
|
||||
}
|
||||
@@ -469,7 +578,7 @@
|
||||
if (!headerView)
|
||||
return _CGRectMakeZero();
|
||||
|
||||
var frame = [self bounds];
|
||||
var frame = [self _insetBounds];
|
||||
|
||||
frame.size.height = _CGRectGetHeight([headerView frame]);
|
||||
frame.size.width -= _CGRectGetWidth([self _cornerViewFrame]);
|
||||
@@ -477,6 +586,42 @@
|
||||
return frame;
|
||||
}
|
||||
|
||||
- (CGRect)_bottomCornerViewFrame
|
||||
{
|
||||
if ([[self horizontalScroller] isHidden] || [[self verticalScroller] isHidden])
|
||||
return CGRectMakeZero();
|
||||
|
||||
var verticalFrame = [[self verticalScroller] frame],
|
||||
bottomCornerFrame = CGRectMakeZero();
|
||||
|
||||
bottomCornerFrame.origin.x = CGRectGetMinX(verticalFrame);
|
||||
bottomCornerFrame.origin.y = CGRectGetMaxY(verticalFrame);
|
||||
bottomCornerFrame.size.width = [CPScroller scrollerWidth];
|
||||
bottomCornerFrame.size.height = [CPScroller scrollerWidth];
|
||||
|
||||
return bottomCornerFrame;
|
||||
}
|
||||
|
||||
- (void)setBottomCornerView:(CPView)aBottomCornerView
|
||||
{
|
||||
if (_bottomCornerView === aBottomCornerView)
|
||||
return;
|
||||
|
||||
[_bottomCornerView removeFromSuperview];
|
||||
|
||||
[aBottomCornerView setFrame:[self _bottomCornerViewFrame]];
|
||||
[self addSubview:aBottomCornerView];
|
||||
|
||||
_bottomCornerView = aBottomCornerView;
|
||||
|
||||
[self _updateCornerAndHeaderView];
|
||||
}
|
||||
|
||||
- (CPView)bottomCornerView
|
||||
{
|
||||
return _bottomCornerView;
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
- (void)_verticalScrollerDidScroll:(CPScroller)aScroller
|
||||
{
|
||||
@@ -662,14 +807,138 @@
|
||||
return _verticalPageScroll;
|
||||
}
|
||||
|
||||
// CPView Overrides
|
||||
|
||||
- (void)drawRect:(CPRect)aRect
|
||||
{
|
||||
[super drawRect:aRect];
|
||||
|
||||
if (_borderType == CPNoBorder)
|
||||
return;
|
||||
|
||||
var strokeRect = [self bounds],
|
||||
context = [[CPGraphicsContext currentContext] graphicsPort];
|
||||
|
||||
CGContextSetLineWidth(context, 1);
|
||||
|
||||
switch (_borderType)
|
||||
{
|
||||
case CPLineBorder:
|
||||
CGContextSetStrokeColor(context, [self currentValueForThemeAttribute:@"border-color"]);
|
||||
CGContextStrokeRect(context, _CGRectInset(strokeRect, 0.5, 0.5));
|
||||
break;
|
||||
|
||||
case CPBezelBorder:
|
||||
[self _drawGrayBezelInContext:context bounds:strokeRect];
|
||||
break;
|
||||
|
||||
case CPGrooveBorder:
|
||||
[self _drawGrooveInContext:context bounds:strokeRect];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_drawGrayBezelInContext:(CGContext)context bounds:(CGRect)aRect
|
||||
{
|
||||
CGContextBeginPath(context);
|
||||
CGContextSetStrokeColor(context, [CPColor colorWithWhite:142.0/255.0 alpha:1.0]);
|
||||
|
||||
var y = _CGRectGetMinY(aRect) + 0.5;
|
||||
|
||||
CGContextMoveToPoint(context, _CGRectGetMinX(aRect), y);
|
||||
CGContextAddLineToPoint(context, _CGRectGetMinX(aRect) + 1.0, y);
|
||||
CGContextStrokePath(context);
|
||||
|
||||
CGContextBeginPath(context);
|
||||
CGContextSetStrokeColor(context, [CPColor colorWithWhite:192.0/255.0 alpha:1.0]);
|
||||
CGContextMoveToPoint(context, _CGRectGetMinX(aRect) + 1.0, y);
|
||||
CGContextAddLineToPoint(context, _CGRectGetMaxX(aRect) - 1.0, y);
|
||||
CGContextStrokePath(context);
|
||||
|
||||
CGContextBeginPath(context);
|
||||
CGContextSetStrokeColor(context, [CPColor colorWithWhite:142.0/255.0 alpha:1.0]);
|
||||
CGContextMoveToPoint(context, _CGRectGetMaxX(aRect) - 1.0, y);
|
||||
CGContextAddLineToPoint(context, _CGRectGetMaxX(aRect), y);
|
||||
CGContextStrokePath(context);
|
||||
|
||||
CGContextBeginPath(context);
|
||||
CGContextSetStrokeColor(context, [CPColor colorWithWhite:190.0/255.0 alpha:1.0]);
|
||||
|
||||
var x = _CGRectGetMaxX(aRect) - 0.5;
|
||||
|
||||
CGContextMoveToPoint(context, x, _CGRectGetMinY(aRect) + 1.0);
|
||||
CGContextAddLineToPoint(context, x, _CGRectGetMaxY(aRect));
|
||||
|
||||
CGContextMoveToPoint(context, x - 0.5, _CGRectGetMaxY(aRect) - 0.5);
|
||||
CGContextAddLineToPoint(context, _CGRectGetMinX(aRect), _CGRectGetMaxY(aRect) - 0.5);
|
||||
|
||||
x = _CGRectGetMinX(aRect) + 0.5;
|
||||
|
||||
CGContextMoveToPoint(context, x, _CGRectGetMaxY(aRect));
|
||||
CGContextAddLineToPoint(context, x, _CGRectGetMinY(aRect) + 1.0);
|
||||
|
||||
CGContextStrokePath(context);
|
||||
}
|
||||
|
||||
- (void)_drawGrooveInContext:(CGContext)context bounds:(CGRect)aRect
|
||||
{
|
||||
CGContextBeginPath(context);
|
||||
CGContextSetStrokeColor(context, [CPColor colorWithWhite:159.0/255.0 alpha:1.0]);
|
||||
|
||||
var y = _CGRectGetMinY(aRect) + 0.5;
|
||||
|
||||
CGContextMoveToPoint(context, _CGRectGetMinX(aRect), y);
|
||||
CGContextAddLineToPoint(context, _CGRectGetMaxX(aRect), y);
|
||||
|
||||
var x = _CGRectGetMaxX(aRect) - 1.5;
|
||||
|
||||
CGContextMoveToPoint(context, x, _CGRectGetMinY(aRect) + 2.0);
|
||||
CGContextAddLineToPoint(context, x, _CGRectGetMaxY(aRect) - 1.0);
|
||||
|
||||
y = _CGRectGetMaxY(aRect) - 1.5;
|
||||
|
||||
CGContextMoveToPoint(context, _CGRectGetMaxX(aRect) - 1.0, y);
|
||||
CGContextAddLineToPoint(context, _CGRectGetMinX(aRect) + 2.0, y);
|
||||
|
||||
x = _CGRectGetMinX(aRect) + 0.5;
|
||||
|
||||
CGContextMoveToPoint(context, x, _CGRectGetMaxY(aRect));
|
||||
CGContextAddLineToPoint(context, x, _CGRectGetMinY(aRect));
|
||||
|
||||
CGContextStrokePath(context);
|
||||
|
||||
CGContextBeginPath(context);
|
||||
CGContextSetStrokeColor(context, [CPColor whiteColor]);
|
||||
|
||||
var rect = _CGRectOffset(aRect, 1.0, 1.0);
|
||||
|
||||
rect.size.width -= 1.0;
|
||||
rect.size.height -= 1.0;
|
||||
CGContextStrokeRect(context, _CGRectInset(rect, 0.5, 0.5));
|
||||
|
||||
CGContextBeginPath(context);
|
||||
CGContextSetStrokeColor(context, [CPColor colorWithWhite:192.0/255.0 alpha:1.0]);
|
||||
|
||||
y = _CGRectGetMinY(aRect) + 2.5;
|
||||
|
||||
CGContextMoveToPoint(context, _CGRectGetMinX(aRect) + 2.0, y);
|
||||
CGContextAddLineToPoint(context, _CGRectGetMaxX(aRect) - 2.0, y);
|
||||
CGContextStrokePath(context);
|
||||
}
|
||||
|
||||
|
||||
// CPResponder Overrides
|
||||
|
||||
/*!
|
||||
Handles a scroll wheel event from the user.
|
||||
@param anEvent the scroll wheel event
|
||||
*/
|
||||
- (void)scrollWheel:(CPEvent)anEvent
|
||||
{
|
||||
[self _respondToScrollWheelEventWithDeltaX:[anEvent deltaX] * _horizontalLineScroll
|
||||
deltaY:[anEvent deltaY] * _verticalLineScroll];
|
||||
[self _respondToScrollWheelEventWithDeltaX:[anEvent deltaX] deltaY:[anEvent deltaY]];
|
||||
}
|
||||
|
||||
- (void)_respondToScrollWheelEventWithDeltaX:(float)deltaX deltaY:(float)deltaY
|
||||
@@ -677,17 +946,15 @@
|
||||
var documentFrame = [[self documentView] frame],
|
||||
contentBounds = [_contentView bounds],
|
||||
contentFrame = [_contentView frame],
|
||||
enclosingScrollView = [self enclosingScrollView],
|
||||
extraX = 0,
|
||||
extraY = 0;
|
||||
enclosingScrollView = [self enclosingScrollView];
|
||||
|
||||
// We want integral bounds!
|
||||
contentBounds.origin.x = ROUND(contentBounds.origin.x + deltaX);
|
||||
contentBounds.origin.y = ROUND(contentBounds.origin.y + deltaY);
|
||||
|
||||
var constrainedOrigin = [_contentView constrainScrollPoint:CGPointCreateCopy(contentBounds.origin)];
|
||||
extraX = ((contentBounds.origin.x - constrainedOrigin.x) / _horizontalLineScroll) * [enclosingScrollView horizontalLineScroll];
|
||||
extraY = ((contentBounds.origin.y - constrainedOrigin.y) / _verticalLineScroll) * [enclosingScrollView verticalLineScroll];
|
||||
var constrainedOrigin = [_contentView constrainScrollPoint:CGPointCreateCopy(contentBounds.origin)],
|
||||
extraX = contentBounds.origin.x - constrainedOrigin.x,
|
||||
extraY = contentBounds.origin.y - constrainedOrigin.y;
|
||||
|
||||
[_contentView scrollToPoint:constrainedOrigin];
|
||||
[_headerClipView scrollToPoint:CGPointMake(constrainedOrigin.x, 0.0)];
|
||||
@@ -758,7 +1025,8 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView",
|
||||
CPScrollViewVScrollerKey = "CPScrollViewVScroller",
|
||||
CPScrollViewHScrollerKey = "CPScrollViewHScroller",
|
||||
CPScrollViewAutohidesScrollerKey = "CPScrollViewAutohidesScroller",
|
||||
CPScrollViewCornerViewKey = "CPScrollViewCornerViewKey";
|
||||
CPScrollViewCornerViewKey = "CPScrollViewCornerViewKey",
|
||||
CPScrollViewBorderTypeKey = "CPScrollViewBorderTypeKey";
|
||||
|
||||
@implementation CPScrollView (CPCoding)
|
||||
|
||||
@@ -781,6 +1049,9 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView",
|
||||
[self addSubview:_headerClipView];
|
||||
}
|
||||
|
||||
_bottomCornerView = [[CPView alloc] init];
|
||||
[self addSubview:_bottomCornerView];
|
||||
|
||||
_verticalScroller = [aCoder decodeObjectForKey:CPScrollViewVScrollerKey];
|
||||
_horizontalScroller = [aCoder decodeObjectForKey:CPScrollViewHScrollerKey];
|
||||
|
||||
@@ -788,6 +1059,8 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView",
|
||||
_hasHorizontalScroller = [aCoder decodeBoolForKey:CPScrollViewHasHScrollerKey];
|
||||
_autohidesScrollers = [aCoder decodeBoolForKey:CPScrollViewAutohidesScrollerKey];
|
||||
|
||||
_borderType = [aCoder decodeIntForKey:CPScrollViewBorderTypeKey];
|
||||
|
||||
_cornerView = [aCoder decodeObjectForKey:CPScrollViewCornerViewKey];
|
||||
|
||||
// Do to the anything goes nature of decoding, our subviews may not exist yet, so layout at the end of the run loop when we're sure everything is in a correct state.
|
||||
@@ -817,6 +1090,8 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView",
|
||||
[aCoder encodeBool:_autohidesScrollers forKey:CPScrollViewAutohidesScrollerKey];
|
||||
|
||||
[aCoder encodeObject:_cornerView forKey:CPScrollViewCornerViewKey];
|
||||
|
||||
[aCoder encodeInt:_borderType forKey:CPScrollViewBorderTypeKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -41,9 +41,9 @@ CPNoScrollerParts = 0;
|
||||
CPOnlyScrollerArrows = 1;
|
||||
CPAllScrollerParts = 2;
|
||||
|
||||
/*!
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPScroller
|
||||
@class CPScroller
|
||||
*/
|
||||
|
||||
var PARTS_ARRANGEMENT = [CPScrollerKnobSlot, CPScrollerDecrementLine, CPScrollerIncrementLine, CPScrollerKnob],
|
||||
@@ -79,17 +79,18 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[ [CPNull null], [CPNull null], [CPNull null], [CPNull null],
|
||||
_CGSizeMakeZero(), _CGSizeMakeZero(), _CGInsetMakeZero(), _CGInsetMakeZero(), _CGSizeMakeZero()]
|
||||
forKeys:[ @"knob-slot-color",
|
||||
@"decrement-line-color",
|
||||
@"increment-line-color",
|
||||
@"knob-color",
|
||||
@"decrement-line-size",
|
||||
@"increment-line-size",
|
||||
@"track-inset",
|
||||
@"knob-inset",
|
||||
@"minimum-knob-length"]];
|
||||
return [CPDictionary dictionaryWithJSObject:{
|
||||
@"scroller-width": 15.0,
|
||||
@"knob-slot-color": [CPColor lightGrayColor],
|
||||
@"decrement-line-color": [CPNull null],
|
||||
@"increment-line-color": [CPNull null],
|
||||
@"knob-color": [CPColor grayColor],
|
||||
@"decrement-line-size":_CGSizeMakeZero(),
|
||||
@"increment-line-size":_CGSizeMakeZero(),
|
||||
@"track-inset":_CGInsetMakeZero(),
|
||||
@"knob-inset": _CGInsetMakeZero(),
|
||||
@"minimum-knob-length":21.0
|
||||
}]
|
||||
}
|
||||
|
||||
|
||||
@@ -98,7 +99,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_controlSize = CPRegularControlSize;
|
||||
@@ -106,7 +107,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
|
||||
[self setFloatValue:0.0];
|
||||
[self setKnobProportion:1.0];
|
||||
|
||||
|
||||
_hitPart = CPScrollerNoPart;
|
||||
|
||||
[self _calculateIsVertical];
|
||||
@@ -121,7 +122,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
*/
|
||||
+ (float)scrollerWidth
|
||||
{
|
||||
return 15.0;//[self scrollerWidthForControlSize:CPRegularControlSize];
|
||||
return [[[CPScroller alloc] init] currentValueForThemeAttribute:@"scroller-width"];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -130,7 +131,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
*/
|
||||
+ (float)scrollerWidthForControlSize:(CPControlSize)aControlSize
|
||||
{
|
||||
return 15.0;//_CPScrollerWidths[aControlSize];
|
||||
return [self scrollerWidth];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -180,10 +181,10 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
- (id)currentValueForThemeAttribute:(CPString)anAttributeName
|
||||
{
|
||||
var themeState = _themeState;
|
||||
|
||||
|
||||
if (NAMES_FOR_PARTS[_hitPart] + "-color" !== anAttributeName)
|
||||
themeState &= ~CPThemeStateHighlighted;
|
||||
|
||||
|
||||
return [self valueForThemeAttribute:anAttributeName inState:themeState];
|
||||
}
|
||||
|
||||
@@ -205,25 +206,25 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
- (CPScrollerPart)testPart:(CGPoint)aPoint
|
||||
{
|
||||
aPoint = [self convertPoint:aPoint fromView:nil];
|
||||
|
||||
// The ordering of these tests is important. We check the knob and
|
||||
|
||||
// The ordering of these tests is important. We check the knob and
|
||||
// page rects first since they may overlap with the arrows.
|
||||
|
||||
|
||||
if (CGRectContainsPoint([self rectForPart:CPScrollerKnob], aPoint))
|
||||
return CPScrollerKnob;
|
||||
|
||||
|
||||
if (CGRectContainsPoint([self rectForPart:CPScrollerDecrementPage], aPoint))
|
||||
return CPScrollerDecrementPage;
|
||||
|
||||
|
||||
if (CGRectContainsPoint([self rectForPart:CPScrollerIncrementPage], aPoint))
|
||||
return CPScrollerIncrementPage;
|
||||
|
||||
|
||||
if (CGRectContainsPoint([self rectForPart:CPScrollerDecrementLine], aPoint))
|
||||
return CPScrollerDecrementLine;
|
||||
|
||||
|
||||
if (CGRectContainsPoint([self rectForPart:CPScrollerIncrementLine], aPoint))
|
||||
return CPScrollerIncrementLine;
|
||||
|
||||
|
||||
if (CGRectContainsPoint([self rectForPart:CPScrollerKnobSlot], aPoint))
|
||||
return CPScrollerKnobSlot;
|
||||
|
||||
@@ -241,7 +242,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
if (_knobProportion === 1.0)
|
||||
{
|
||||
_usableParts = CPNoScrollerParts;
|
||||
|
||||
|
||||
_partRects[CPScrollerDecrementPage] = CGRectMakeZero();
|
||||
_partRects[CPScrollerKnob] = CGRectMakeZero();
|
||||
_partRects[CPScrollerIncrementPage] = CGRectMakeZero();
|
||||
@@ -250,7 +251,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
|
||||
// In this case, the slot is the entirety of the scroller.
|
||||
_partRects[CPScrollerKnobSlot] = CGRectMakeCopy(bounds);
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -260,8 +261,8 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
var knobInset = [self currentValueForThemeAttribute:@"knob-inset"],
|
||||
trackInset = [self currentValueForThemeAttribute:@"track-inset"],
|
||||
width = _CGRectGetWidth(bounds),
|
||||
height = _CGRectGetHeight(bounds);
|
||||
|
||||
height = _CGRectGetHeight(bounds);
|
||||
|
||||
if ([self isVertical])
|
||||
{
|
||||
var decrementLineSize = [self currentValueForThemeAttribute:"decrement-line-size"],
|
||||
@@ -280,10 +281,10 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
_partRects[CPScrollerKnobSlot] = _CGRectMake(trackInset.left, effectiveDecrementLineHeight, width - trackInset.left - trackInset.right, slotHeight);
|
||||
_partRects[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
|
||||
_partRects[CPScrollerIncrementLine] = _CGRectMake(0.0, height - incrementLineSize.height, incrementLineSize.width, incrementLineSize.height);
|
||||
|
||||
|
||||
if(height < knobHeight + decrementLineSize.height + incrementLineSize.height + trackInset.top + trackInset.bottom)
|
||||
_partRects[CPScrollerKnob] = _CGRectMakeZero();
|
||||
|
||||
|
||||
if(height < decrementLineSize.height + incrementLineSize.height - 2)
|
||||
{
|
||||
_partRects[CPScrollerIncrementLine] = _CGRectMakeZero();
|
||||
@@ -309,10 +310,10 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
_partRects[CPScrollerKnobSlot] = _CGRectMake(effectiveDecrementLineWidth, trackInset.top, slotWidth, height - trackInset.top - trackInset.bottom);
|
||||
_partRects[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
|
||||
_partRects[CPScrollerIncrementLine] = _CGRectMake(width - incrementLineSize.width, 0.0, incrementLineSize.width, incrementLineSize.height);
|
||||
|
||||
|
||||
if(width < knobWidth + decrementLineSize.width + incrementLineSize.width + trackInset.left + trackInset.right)
|
||||
_partRects[CPScrollerKnob] = _CGRectMakeZero();
|
||||
|
||||
|
||||
if(width < decrementLineSize.width + incrementLineSize.width - 2)
|
||||
{
|
||||
_partRects[CPScrollerIncrementLine] = _CGRectMakeZero();
|
||||
@@ -358,9 +359,9 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
- (CPView)createViewForPart:(CPScrollerPart)aPart
|
||||
{
|
||||
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
|
||||
|
||||
[view setHitTests:NO];
|
||||
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@@ -374,7 +375,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
|
||||
[view setHitTests:NO];
|
||||
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@@ -388,12 +389,12 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var part = PARTS_ARRANGEMENT[index];
|
||||
|
||||
|
||||
if (index === 0)
|
||||
view = [self layoutEphemeralSubviewNamed:part positioned:CPWindowBelow relativeToEphemeralSubviewNamed:PARTS_ARRANGEMENT[index + 1]];
|
||||
else
|
||||
view = [self layoutEphemeralSubviewNamed:part positioned:CPWindowAbove relativeToEphemeralSubviewNamed:PARTS_ARRANGEMENT[index - 1]];
|
||||
|
||||
|
||||
if (view)
|
||||
[view setBackgroundColor:[self currentValueForThemeAttribute:NAMES_FOR_PARTS[part] + "-color"]];
|
||||
}
|
||||
@@ -403,7 +404,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
Caches images for the scroll arrow and knob.
|
||||
*/
|
||||
- (void)drawParts
|
||||
{
|
||||
{
|
||||
[self drawKnobSlot];
|
||||
[self drawKnob];
|
||||
[self drawArrow:CPScrollerDecrementArrow highlight:NO];
|
||||
@@ -426,37 +427,37 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
- (void)trackKnob:(CPEvent)anEvent
|
||||
{
|
||||
var type = [anEvent type];
|
||||
|
||||
|
||||
if (type === CPLeftMouseUp)
|
||||
{
|
||||
_hitPart = CPScrollerNoPart;
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (type === CPLeftMouseDown)
|
||||
{
|
||||
_trackingFloatValue = [self floatValue];
|
||||
_trackingStartPoint = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||
}
|
||||
|
||||
|
||||
else if (type === CPLeftMouseDragged)
|
||||
{
|
||||
var knobRect = [self rectForPart:CPScrollerKnob],
|
||||
knobSlotRect = [self rectForPart:CPScrollerKnobSlot],
|
||||
remainder = ![self isVertical] ? (_CGRectGetWidth(knobSlotRect) - _CGRectGetWidth(knobRect)) : (_CGRectGetHeight(knobSlotRect) - _CGRectGetHeight(knobRect));
|
||||
|
||||
|
||||
if (remainder <= 0)
|
||||
[self setFloatValue:0.0];
|
||||
else
|
||||
{
|
||||
var location = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||
var location = [self convertPoint:[anEvent locationInWindow] fromView:nil],
|
||||
delta = ![self isVertical] ? location.x - _trackingStartPoint.x : location.y - _trackingStartPoint.y;
|
||||
|
||||
[self setFloatValue:_trackingFloatValue + delta / remainder];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[CPApp setTarget:self selector:@selector(trackKnob:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
|
||||
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
@@ -474,26 +475,26 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
{
|
||||
[self highlight:NO];
|
||||
[CPEvent stopPeriodicEvents];
|
||||
|
||||
|
||||
_hitPart = CPScrollerNoPart;
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (type === CPLeftMouseDown)
|
||||
{
|
||||
_trackingPart = [self hitPart];
|
||||
|
||||
|
||||
_trackingStartPoint = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||
|
||||
if ([anEvent modifierFlags] & CPAlternateKeyMask)
|
||||
{
|
||||
if (_trackingPart == CPScrollerDecrementLine)
|
||||
_hitPart = CPScrollerDecrementPage;
|
||||
|
||||
|
||||
else if (_trackingPart == CPScrollerIncrementLine)
|
||||
_hitPart = CPScrollerIncrementPage;
|
||||
|
||||
|
||||
else if (_trackingPart == CPScrollerDecrementPage || _trackingPart == CPScrollerIncrementPage)
|
||||
{
|
||||
var knobRect = [self rectForPart:CPScrollerKnob],
|
||||
@@ -502,42 +503,42 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
remainder = (![self isVertical] ? _CGRectGetWidth(knobSlotRect) : _CGRectGetHeight(knobSlotRect)) - knobWidth;
|
||||
|
||||
[self setFloatValue:((![self isVertical] ? _trackingStartPoint.x - _CGRectGetMinX(knobSlotRect) : _trackingStartPoint.y - _CGRectGetMinY(knobSlotRect)) - knobWidth / 2.0) / remainder];
|
||||
|
||||
|
||||
_hitPart = CPScrollerKnob;
|
||||
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
|
||||
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
|
||||
// Now just track the knob.
|
||||
return [self trackKnob:anEvent];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[self highlight:YES];
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
|
||||
|
||||
[CPEvent startPeriodicEventsAfterDelay:0.5 withPeriod:0.04];
|
||||
}
|
||||
|
||||
|
||||
else if (type === CPLeftMouseDragged)
|
||||
{
|
||||
_trackingStartPoint = [self convertPoint:[anEvent locationInWindow] fromView:nil];
|
||||
|
||||
|
||||
if (_trackingPart == CPScrollerDecrementPage || _trackingPart == CPScrollerIncrementPage)
|
||||
{
|
||||
var hitPart = [self testPart:[anEvent locationInWindow]];
|
||||
|
||||
|
||||
if (hitPart == CPScrollerDecrementPage || hitPart == CPScrollerIncrementPage)
|
||||
{
|
||||
_trackingPart = hitPart;
|
||||
_hitPart = hitPart;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[self highlight:CGRectContainsPoint([self rectForPart:_trackingPart], _trackingStartPoint)];
|
||||
}
|
||||
else if (type == CPPeriodic && CGRectContainsPoint([self rectForPart:_trackingPart], _trackingStartPoint))
|
||||
[self sendAction:[self action] to:[self target]];
|
||||
|
||||
|
||||
[CPApp setTarget:self selector:@selector(trackScrollButtons:) forNextEventMatchingMask:CPPeriodicMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
|
||||
|
||||
}
|
||||
@@ -569,15 +570,15 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
|
||||
{
|
||||
if (![self isEnabled])
|
||||
return;
|
||||
|
||||
|
||||
_hitPart = [self testPart:[anEvent locationInWindow]];
|
||||
|
||||
|
||||
switch (_hitPart)
|
||||
{
|
||||
case CPScrollerKnob: return [self trackKnob:anEvent];
|
||||
|
||||
case CPScrollerDecrementLine:
|
||||
case CPScrollerIncrementLine:
|
||||
|
||||
case CPScrollerDecrementLine:
|
||||
case CPScrollerIncrementLine:
|
||||
case CPScrollerDecrementPage:
|
||||
case CPScrollerIncrementPage: return [self trackScrollButtons:anEvent];
|
||||
}
|
||||
@@ -603,19 +604,32 @@ var CPScrollerControlSizeKey = "CPScrollerControlSize",
|
||||
_knobProportion = [aCoder decodeFloatForKey:CPScrollerKnobProportionKey];
|
||||
|
||||
_partRects = [];
|
||||
|
||||
|
||||
_hitPart = CPScrollerNoPart;
|
||||
|
||||
[self _calculateIsVertical];
|
||||
|
||||
// Adjust the size of the scroller if the size from cib
|
||||
// isn't equal to the scrollerWidth
|
||||
var frame = [self frame],
|
||||
scrollerWidth = [CPScroller scrollerWidth];
|
||||
|
||||
if ([self isVertical] && CGRectGetWidth(frame) !== scrollerWidth)
|
||||
frame.size.width = scrollerWidth;
|
||||
|
||||
if (![self isVertical] && CGRectGetHeight(frame) !== scrollerWidth)
|
||||
frame.size.height = scrollerWidth;
|
||||
|
||||
[self setFrame:frame];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
|
||||
[aCoder encodeInt:_controlSize forKey:CPScrollerControlSizeKey];
|
||||
[aCoder encodeFloat:_knobProportion forKey:CPScrollerKnobProportionKey];
|
||||
}
|
||||
|
||||
@@ -22,18 +22,27 @@
|
||||
|
||||
@import "CPTextField.j"
|
||||
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
#include "Platform/Platform.h"
|
||||
|
||||
CPSearchFieldRecentsTitleMenuItemTag = 1000;
|
||||
CPSearchFieldRecentsMenuItemTag = 1001;
|
||||
CPSearchFieldClearRecentsMenuItemTag = 1002;
|
||||
CPSearchFieldNoRecentsMenuItemTag = 1003;
|
||||
CPSearchFieldSeparatorMenuItemTag = 1004;
|
||||
|
||||
var CPSearchFieldSearchImage = nil,
|
||||
CPSearchFieldFindImage = nil,
|
||||
CPSearchFieldCancelImage = nil,
|
||||
CPSearchFieldCancelPressedImage = nil;
|
||||
|
||||
var SEARCH_BUTTON_DEFAULT_WIDTH = 25.0,
|
||||
CANCEL_BUTTON_DEFAULT_WIDTH = 22.0,
|
||||
BUTTON_DEFAULT_HEIGHT = 22.0;
|
||||
|
||||
var RECENT_SEARCH_PREFIX = @" ";
|
||||
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPSearchField
|
||||
@@ -54,6 +63,7 @@ var CPSearchFieldSearchImage = nil,
|
||||
int _maximumRecents;
|
||||
BOOL _sendsWholeSearchString;
|
||||
BOOL _sendsSearchStringImmediately;
|
||||
BOOL _canResignFirstResponder;
|
||||
CPTimer _partialStringTimer;
|
||||
}
|
||||
|
||||
@@ -63,23 +73,22 @@ var CPSearchFieldSearchImage = nil,
|
||||
return;
|
||||
|
||||
var bundle = [CPBundle bundleForClass:self];
|
||||
CPSearchFieldSearchImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldSearch.png"] size:CGSizeMake(25, 22)];
|
||||
CPSearchFieldFindImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldFind.png"] size:CGSizeMake(25, 22)];
|
||||
CPSearchFieldCancelImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancel.png"] size:CGSizeMake(22, 22)];
|
||||
CPSearchFieldCancelPressedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancelPressed.png"] size:CGSizeMake(22, 22)];
|
||||
CPSearchFieldSearchImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldSearch.png"] size:_CGSizeMake(SEARCH_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)];
|
||||
CPSearchFieldFindImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldFind.png"] size:_CGSizeMake(SEARCH_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)];
|
||||
CPSearchFieldCancelImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancel.png"] size:_CGSizeMake(CANCEL_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)];
|
||||
CPSearchFieldCancelPressedImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldCancelPressed.png"] size:_CGSizeMake(CANCEL_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT)];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame
|
||||
{
|
||||
if (self = [super initWithFrame:frame])
|
||||
{
|
||||
_recentSearches = [CPArray array];
|
||||
_maximumRecents = 10;
|
||||
_sendsWholeSearchString = NO;
|
||||
_sendsSearchStringImmediately = NO;
|
||||
_recentsAutosaveName = nil;
|
||||
|
||||
[self _initWithFrame:frame];
|
||||
[self _init];
|
||||
#if PLATFORM(DOM)
|
||||
_cancelButton._DOMElement.style.cursor = "default";
|
||||
_searchButton._DOMElement.style.cursor = "default";
|
||||
@@ -89,23 +98,28 @@ var CPSearchFieldSearchImage = nil,
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)_initWithFrame:(CGRect)frame
|
||||
- (void)_init
|
||||
{
|
||||
_recentSearches = [CPArray array];
|
||||
|
||||
[self setBezeled:YES];
|
||||
[self setBezelStyle:CPTextFieldRoundedBezel];
|
||||
[self setBordered:YES];
|
||||
[self setEditable:YES];
|
||||
[self setDelegate:self];
|
||||
[self setContinuous:YES];
|
||||
|
||||
_cancelButton = [[CPButton alloc] initWithFrame:CGRectMake(frame.size.width - 27,(frame.size.height-22)/2,22,22)];
|
||||
var bounds = [self bounds],
|
||||
cancelButton = [[CPButton alloc] initWithFrame:[self cancelButtonRectForBounds:bounds]],
|
||||
searchButton = [[CPButton alloc] initWithFrame:[self searchButtonRectForBounds:bounds]];
|
||||
|
||||
[self setCancelButton:cancelButton];
|
||||
[self resetCancelButton];
|
||||
[_cancelButton setHidden:YES];
|
||||
[_cancelButton setAutoresizingMask:CPViewMinXMargin];
|
||||
[self addSubview:_cancelButton];
|
||||
|
||||
_searchButton = [[CPButton alloc] initWithFrame:CGRectMake(5,(frame.size.height-25)/2,25,25)];
|
||||
[self setSearchButton:searchButton];
|
||||
[self resetSearchButton];
|
||||
[self addSubview:_searchButton];
|
||||
|
||||
_canResignFirstResponder = YES;
|
||||
}
|
||||
|
||||
// Managing Buttons
|
||||
@@ -115,7 +129,15 @@ var CPSearchFieldSearchImage = nil,
|
||||
*/
|
||||
- (void)setSearchButton:(CPButton)button
|
||||
{
|
||||
_searchButton = button;
|
||||
if (button != _searchButton)
|
||||
{
|
||||
[_searchButton removeFromSuperview];
|
||||
_searchButton = button;
|
||||
|
||||
[_searchButton setFrame:[self searchButtonRectForBounds:[self bounds]]];
|
||||
[_searchButton setAutoresizingMask:CPViewMaxXMargin];
|
||||
[self addSubview:_searchButton];
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -133,30 +155,13 @@ var CPSearchFieldSearchImage = nil,
|
||||
*/
|
||||
- (void)resetSearchButton
|
||||
{
|
||||
var searchButtonImage,
|
||||
action,
|
||||
target,
|
||||
button = [self searchButton];
|
||||
|
||||
if (_searchMenuTemplate === nil)
|
||||
{
|
||||
searchButtonImage = CPSearchFieldSearchImage;
|
||||
action = @selector(_sendAction:);
|
||||
target = self;
|
||||
}
|
||||
else
|
||||
{
|
||||
searchButtonImage = CPSearchFieldFindImage;
|
||||
action = @selector(_showMenu:);
|
||||
target = self;
|
||||
}
|
||||
var button = [self searchButton],
|
||||
searchButtonImage = (_searchMenuTemplate === nil) ? CPSearchFieldSearchImage : CPSearchFieldFindImage;
|
||||
|
||||
[button setBordered:NO];
|
||||
[button setImageScaling:CPScaleToFit];
|
||||
[button setImage:searchButtonImage];
|
||||
[button setAutoresizingMask:CPViewMaxXMargin];
|
||||
[button setTarget:target];
|
||||
[button setAction:action];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -165,7 +170,18 @@ var CPSearchFieldSearchImage = nil,
|
||||
*/
|
||||
- (void)setCancelButton:(CPButton)button
|
||||
{
|
||||
_cancelButton = button;
|
||||
if (button != _cancelButton)
|
||||
{
|
||||
[_cancelButton removeFromSuperview];
|
||||
_cancelButton = button;
|
||||
|
||||
[_cancelButton setFrame:[self cancelButtonRectForBounds:[self bounds]]];
|
||||
[_cancelButton setAutoresizingMask:CPViewMinXMargin];
|
||||
[_cancelButton setTarget:self];
|
||||
[_cancelButton setAction:@selector(_searchFieldCancel:)];
|
||||
[self _updateCancelButtonVisibility];
|
||||
[self addSubview:_cancelButton];
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -200,23 +216,25 @@ var CPSearchFieldSearchImage = nil,
|
||||
@return The updated bounding rectangle to use for the search text field. The default value is the value passed into the rect parameter.
|
||||
Subclasses can override this method to return a new bounding rectangle for the text-field object. You might use this method to provide a custom layout for the search field control.
|
||||
*/
|
||||
- (CPRect)searchTextRectForBounds:(CPRect)rect
|
||||
- (CGRect)searchTextRectForBounds:(CGRect)rect
|
||||
{
|
||||
var leftOffset = 0, width = rect.size.width;
|
||||
var leftOffset = 0,
|
||||
width = _CGRectGetWidth(rect),
|
||||
bounds = [self bounds];
|
||||
|
||||
if (_searchButton)
|
||||
{
|
||||
var searchRect = [_searchButton frame];
|
||||
leftOffset = searchRect.origin.x + searchRect.size.width;
|
||||
var searchBounds = [self searchButtonRectForBounds:bounds];
|
||||
leftOffset = _CGRectGetMaxX(searchBounds) + 2;
|
||||
}
|
||||
|
||||
if (_cancelButton)
|
||||
{
|
||||
var cancelRect = [_cancelButton frame];
|
||||
width = cancelRect.origin.x - leftOffset;
|
||||
var cancelRect = [self cancelButtonRectForBounds:bounds];
|
||||
width = _CGRectGetMinX(cancelRect) - leftOffset;
|
||||
}
|
||||
|
||||
return CPMakeRect(leftOffset,rect.origin.y,width,rect.size.height);
|
||||
return _CGRectMake(leftOffset, _CGRectGetMinY(rect), width, _CGRectGetHeight(rect));
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -224,9 +242,9 @@ var CPSearchFieldSearchImage = nil,
|
||||
@param rect The current bounding rectangle for the search button.
|
||||
Subclasses can override this method to return a new bounding rectangle for the search button. You might use this method to provide a custom layout for the search field control.
|
||||
*/
|
||||
- (CPRect)searchButtonRectForBounds:(CPRect)rect
|
||||
- (CGRect)searchButtonRectForBounds:(CGRect)rect
|
||||
{
|
||||
return [_searchButton frame];
|
||||
return _CGRectMake(5, (_CGRectGetHeight(rect) - BUTTON_DEFAULT_HEIGHT) / 2, SEARCH_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -234,9 +252,9 @@ var CPSearchFieldSearchImage = nil,
|
||||
@param rect The updated bounding rectangle to use for the cancel button. The default value is the value passed into the rect parameter.
|
||||
Subclasses can override this method to return a new bounding rectangle for the cancel button. You might use this method to provide a custom layout for the search field control.
|
||||
*/
|
||||
- (CPRect)cancelButtonRectForBounds:(CPRect)rect
|
||||
{
|
||||
return [_cancelButton frame];
|
||||
- (CGRect)cancelButtonRectForBounds:(CGRect)rect
|
||||
{
|
||||
return _CGRectMake(_CGRectGetWidth(rect) - CANCEL_BUTTON_DEFAULT_WIDTH - 5, (_CGRectGetHeight(rect) - CANCEL_BUTTON_DEFAULT_WIDTH) / 2, BUTTON_DEFAULT_HEIGHT, BUTTON_DEFAULT_HEIGHT);
|
||||
}
|
||||
|
||||
// Managing Menu Templates
|
||||
@@ -254,9 +272,9 @@ var CPSearchFieldSearchImage = nil,
|
||||
@param menu The menu template to use.
|
||||
The receiver looks for the tag constants described in ŇMenu tagsÓ to determine how to populate the menu with items related to recent searches. See ŇConfiguring a Search MenuÓ for a sample of how you might set up the search menu template.
|
||||
*/
|
||||
- (void)setSearchMenuTemplate:(CPMenu)menu
|
||||
- (void)setSearchMenuTemplate:(CPMenu)aMenu
|
||||
{
|
||||
_searchMenuTemplate = menu;
|
||||
_searchMenuTemplate = aMenu;
|
||||
|
||||
[self resetSearchButton];
|
||||
[self _loadRecentSearchList];
|
||||
@@ -373,7 +391,7 @@ var CPSearchFieldSearchImage = nil,
|
||||
|
||||
// Private methods and subclassing
|
||||
|
||||
- (CPRect)contentRectForBounds:(CPRect)bounds
|
||||
- (CGRect)contentRectForBounds:(CGRect)bounds
|
||||
{
|
||||
var superbounds = [super contentRectForBounds:bounds];
|
||||
return [self searchTextRectForBounds:superbounds];
|
||||
@@ -447,37 +465,78 @@ var CPSearchFieldSearchImage = nil,
|
||||
[self _updateSearchMenu];
|
||||
}
|
||||
|
||||
- (BOOL)trackMouse:(CPEvent)event
|
||||
- (CPView)hitTest:(CGPoint)aPoint
|
||||
{
|
||||
var rect,
|
||||
point,
|
||||
location = [event locationInWindow];
|
||||
|
||||
point = [self convertPoint:location fromView:nil];
|
||||
|
||||
rect = [self searchButtonRectForBounds:[self frame]];
|
||||
if (CPRectContainsPoint(rect,point))
|
||||
{
|
||||
return [[self searchButton] trackMouse:event];
|
||||
}
|
||||
|
||||
rect = [self cancelButtonRectForBounds:[self frame]];
|
||||
if (CPRectContainsPoint(rect,point))
|
||||
{
|
||||
return [[self cancelButton] trackMouse:event];
|
||||
}
|
||||
|
||||
return [super trackMouse:event];
|
||||
// Make sure a hit anywhere within the search field returns the search field itself
|
||||
if (_CGRectContainsPoint([self frame], aPoint))
|
||||
return self;
|
||||
else
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (CPMenu)_defaultSearchMenuTemplate
|
||||
- (BOOL)resignFirstResponder
|
||||
{
|
||||
var template, item;
|
||||
return _canResignFirstResponder && [super resignFirstResponder];
|
||||
}
|
||||
|
||||
- (void)mouseDown:(CPEvent)anEvent
|
||||
{
|
||||
var location = [anEvent locationInWindow],
|
||||
point = [self convertPoint:location fromView:nil];
|
||||
|
||||
if (_CGRectContainsPoint([self searchButtonRectForBounds:[self bounds]], point))
|
||||
{
|
||||
if (_searchMenuTemplate == nil)
|
||||
[self _sendAction:self];
|
||||
else
|
||||
[self _showMenu];
|
||||
}
|
||||
else if (_CGRectContainsPoint([self cancelButtonRectForBounds:[self bounds]], point))
|
||||
[_cancelButton mouseDown:anEvent];
|
||||
else
|
||||
[super mouseDown:anEvent];
|
||||
}
|
||||
|
||||
/*!
|
||||
Provides the common case items for a recent searches menu. If there are not recent searches,
|
||||
displays a single disabled item:
|
||||
|
||||
template = [[CPMenu alloc] init];
|
||||
No Recent Searches
|
||||
|
||||
If there are 1 more recent searches, it displays:
|
||||
|
||||
item = [[CPMenuItem alloc] initWithTitle:@"Recent searches"
|
||||
action:NULL
|
||||
Recent Searches
|
||||
recent search 1
|
||||
recent search 2
|
||||
etc.
|
||||
---------------------
|
||||
Clear Recent Searches
|
||||
|
||||
If you wish to add items before or after the template, you can. If you put items
|
||||
before, a separator will automatically be placed before the default template item.
|
||||
If you add items after the default template, it is your responsibility to add a separator.
|
||||
|
||||
To add a custom item:
|
||||
|
||||
item = [[CPMenuItem alloc] initWithTitle:@"google"
|
||||
action:@selector(google:)
|
||||
keyEquivalent:@""];
|
||||
[item setTag:700];
|
||||
[item setTarget:self];
|
||||
[template addItem:item];
|
||||
|
||||
Be sure that your custom items do not use tags in the range 1000-1004 inclusive.
|
||||
If you wish to maintain state in custom menu items that you add, you will need to maintain
|
||||
the item state yourself, then in the action method of the custom items, modify the items
|
||||
in the search menu template and send [searchField setSearchMenuTemplate:template] to update the menu.
|
||||
*/
|
||||
- (CPMenu)defaultSearchMenuTemplate
|
||||
{
|
||||
var template = [[CPMenu alloc] init],
|
||||
item;
|
||||
|
||||
item = [[CPMenuItem alloc] initWithTitle:@"Recent Searches"
|
||||
action:nil
|
||||
keyEquivalent:@""];
|
||||
[item setTag:CPSearchFieldRecentsTitleMenuItemTag];
|
||||
[item setEnabled:NO];
|
||||
@@ -490,15 +549,15 @@ var CPSearchFieldSearchImage = nil,
|
||||
[item setTarget:self];
|
||||
[template addItem:item];
|
||||
|
||||
item = [[CPMenuItem alloc] initWithTitle:@"Clear recent searches"
|
||||
item = [[CPMenuItem alloc] initWithTitle:@"Clear Recent Searches"
|
||||
action:@selector(_searchFieldClearRecents:)
|
||||
keyEquivalent:@""];
|
||||
[item setTag:CPSearchFieldClearRecentsMenuItemTag];
|
||||
[item setTarget:self];
|
||||
[template addItem:item];
|
||||
|
||||
item = [[CPMenuItem alloc] initWithTitle:@"No recent searches"
|
||||
action:NULL
|
||||
item = [[CPMenuItem alloc] initWithTitle:@"No Recent Searches"
|
||||
action:nil
|
||||
keyEquivalent:@""];
|
||||
[item setTag:CPSearchFieldNoRecentsMenuItemTag];
|
||||
[item setEnabled:NO];
|
||||
@@ -512,61 +571,96 @@ var CPSearchFieldSearchImage = nil,
|
||||
if (_searchMenuTemplate === nil)
|
||||
return;
|
||||
|
||||
var i, menu = [[CPMenu alloc] init],
|
||||
var menu = [[CPMenu alloc] init],
|
||||
countOfRecents = [_recentSearches count],
|
||||
numberOfItems = [_searchMenuTemplate numberOfItems];
|
||||
|
||||
for (i = 0; i < numberOfItems; i++)
|
||||
for (var i = 0; i < numberOfItems; i++)
|
||||
{
|
||||
var item = [_searchMenuTemplate itemAtIndex:i],
|
||||
tag = [item tag];
|
||||
|
||||
if (!(tag === CPSearchFieldRecentsTitleMenuItemTag && countOfRecents === 0) &&
|
||||
!(tag === CPSearchFieldClearRecentsMenuItemTag && countOfRecents === 0) &&
|
||||
!(tag === CPSearchFieldNoRecentsMenuItemTag && countOfRecents != 0) &&
|
||||
!(tag === CPSearchFieldRecentsMenuItemTag))
|
||||
{
|
||||
var itemAction, itemTarget;
|
||||
switch (tag)
|
||||
{
|
||||
case CPSearchFieldRecentsTitleMenuItemTag : itemAction = NULL; itemTarget = NULL; break;
|
||||
case CPSearchFieldClearRecentsMenuItemTag : itemAction = @selector(_searchFieldClearRecents:); itemTarget = self; break;
|
||||
case CPSearchFieldNoRecentsMenuItemTag : itemAction = NULL; itemTarget = NULL; break;
|
||||
default: itemAction = [item action]; itemTarget = [item target]; break;
|
||||
}
|
||||
var item = [[_searchMenuTemplate itemAtIndex:i] copy];
|
||||
|
||||
if (tag === CPSearchFieldClearRecentsMenuItemTag || tag === CPSearchFieldRecentsTitleMenuItemTag)
|
||||
{
|
||||
var separator = [CPMenuItem separatorItem];
|
||||
[separator setEnabled:NO];
|
||||
[menu addItem:separator];
|
||||
}
|
||||
|
||||
var templateItem = [[CPMenuItem alloc] initWithTitle:[item title]
|
||||
action:itemAction
|
||||
keyEquivalent:[item keyEquivalent]];
|
||||
[templateItem setTarget:itemTarget];
|
||||
[templateItem setEnabled:([item isEnabled] && itemAction != NULL)];
|
||||
[templateItem setTag:tag];
|
||||
[menu addItem:templateItem];
|
||||
}
|
||||
else if (tag === CPSearchFieldRecentsMenuItemTag)
|
||||
switch ([item tag])
|
||||
{
|
||||
var j;
|
||||
for (j = 0; j < countOfRecents; j++)
|
||||
case CPSearchFieldRecentsTitleMenuItemTag:
|
||||
if (countOfRecents === 0)
|
||||
continue;
|
||||
|
||||
if ([menu numberOfItems] > 0)
|
||||
[self _addSeparatorToMenu:menu];
|
||||
break;
|
||||
|
||||
case CPSearchFieldRecentsMenuItemTag:
|
||||
{
|
||||
var rencentItem = [[CPMenuItem alloc] initWithTitle:[_recentSearches objectAtIndex:j]
|
||||
action:@selector(_searchFieldSearch:)
|
||||
keyEquivalent:[item keyEquivalent]];
|
||||
[rencentItem setTarget:self];
|
||||
[menu addItem:rencentItem];
|
||||
var itemAction = @selector(_searchFieldSearch:);
|
||||
|
||||
for (var recentIndex = 0; recentIndex < countOfRecents; ++recentIndex)
|
||||
{
|
||||
// RECENT_SEARCH_PREFIX is a hack until CPMenuItem -setIndentationLevel works
|
||||
var recentItem = [[CPMenuItem alloc] initWithTitle:RECENT_SEARCH_PREFIX + [_recentSearches objectAtIndex:recentIndex]
|
||||
action:itemAction
|
||||
keyEquivalent:[item keyEquivalent]];
|
||||
[item setTarget:self];
|
||||
[menu addItem:recentItem];
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
case CPSearchFieldClearRecentsMenuItemTag:
|
||||
if (countOfRecents === 0)
|
||||
continue;
|
||||
|
||||
if ([menu numberOfItems] > 0)
|
||||
[self _addSeparatorToMenu:menu];
|
||||
|
||||
[item setAction:@selector(_searchFieldClearRecents:)];
|
||||
[item setTarget:self];
|
||||
break;
|
||||
|
||||
case CPSearchFieldNoRecentsMenuItemTag:
|
||||
if (countOfRecents !== 0)
|
||||
continue;
|
||||
|
||||
if ([menu numberOfItems] > 0)
|
||||
[self _addSeparatorToMenu:menu];
|
||||
break;
|
||||
|
||||
case CPSearchFieldSeparatorMenuItemTag:
|
||||
item = [CPMenuItem separatorItem];
|
||||
[item setEnabled:NO];
|
||||
[menu addItem:item];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
[item setEnabled:([item isEnabled] && [item action] != nil && [item target] != nil)];
|
||||
[menu addItem:item];
|
||||
}
|
||||
|
||||
[menu setDelegate:self];
|
||||
|
||||
_searchMenu = menu;
|
||||
}
|
||||
|
||||
- (void)_showMenu:(id)sender
|
||||
- (void)_addSeparatorToMenu:(CPMenu)aMenu
|
||||
{
|
||||
var separator = [CPMenuItem separatorItem];
|
||||
[separator setEnabled:NO];
|
||||
[aMenu addItem:separator];
|
||||
}
|
||||
|
||||
- (void)menuWillOpen:(CPMenu)menu
|
||||
{
|
||||
_canResignFirstResponder = NO;
|
||||
}
|
||||
|
||||
- (void)menuDidClose:(CPMenu)menu
|
||||
{
|
||||
_canResignFirstResponder = YES;
|
||||
|
||||
[self becomeFirstResponder];
|
||||
}
|
||||
|
||||
- (void)_showMenu
|
||||
{
|
||||
if (_searchMenu === nil || [_searchMenu numberOfItems] === 0 || ![self isEnabled])
|
||||
return;
|
||||
@@ -576,12 +670,14 @@ var CPSearchFieldSearchImage = nil,
|
||||
|
||||
var anEvent = [CPEvent mouseEventWithType:CPRightMouseDown location:location modifierFlags:0 timestamp:[[CPApp currentEvent] timestamp] windowNumber:[[self window] windowNumber] context:nil eventNumber:1 clickCount:1 pressure:0];
|
||||
|
||||
[CPMenu popUpContextMenu:_searchMenu withEvent:anEvent forView:sender];
|
||||
[self selectAll:nil];
|
||||
[CPMenu popUpContextMenu:_searchMenu withEvent:anEvent forView:self];
|
||||
}
|
||||
|
||||
- (void)_sendPartialString
|
||||
{
|
||||
[self _sendAction:self];
|
||||
[super sendAction:[self action] to:[self target]];
|
||||
[_partialStringTimer invalidate];
|
||||
}
|
||||
|
||||
- (void)_searchFieldCancel:(id)sender
|
||||
@@ -593,14 +689,15 @@ var CPSearchFieldSearchImage = nil,
|
||||
|
||||
- (void)_searchFieldSearch:(id)sender
|
||||
{
|
||||
var searchString = [sender title];
|
||||
var searchString = [[sender title] substringFromIndex:[RECENT_SEARCH_PREFIX length]];
|
||||
|
||||
if ([sender tag] != CPSearchFieldRecentsMenuItemTag)
|
||||
[self _addStringToRecentSearches:searchString];
|
||||
|
||||
[self setObjectValue:searchString];
|
||||
[self _sendPartialString];
|
||||
|
||||
[self selectAll:nil];
|
||||
|
||||
[self _updateCancelButtonVisibility];
|
||||
}
|
||||
|
||||
@@ -608,6 +705,8 @@ var CPSearchFieldSearchImage = nil,
|
||||
{
|
||||
[self setRecentSearches:[CPArray array]];
|
||||
[self _updateSearchMenu];
|
||||
[self setStringValue:@""];
|
||||
[self _updateCancelButtonVisibility];
|
||||
}
|
||||
|
||||
- (void)_registerForAutosaveNotification
|
||||
@@ -668,7 +767,7 @@ var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
|
||||
CPSendsWholeSearchStringKey = @"CPSendsWholeSearchStringKey",
|
||||
CPSendsSearchStringImmediatelyKey = @"CPSendsSearchStringImmediatelyKey",
|
||||
CPMaximumRecentsKey = @"CPMaximumRecentsKey",
|
||||
CPSearchMenuTemplateKey = @"CPSearchMenuTemplateKey";
|
||||
CPSearchMenuTemplateKey = @"CPSearchMenuTemplateKey";
|
||||
|
||||
@implementation CPSearchField (CPCoding)
|
||||
|
||||
@@ -690,6 +789,7 @@ var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
|
||||
|
||||
if (_recentsAutosaveName)
|
||||
[coder encodeObject:_recentsAutosaveName forKey:CPRecentsAutosaveNameKey];
|
||||
|
||||
if (_searchMenuTemplate)
|
||||
[coder encodeObject:_searchMenuTemplate forKey:CPSearchMenuTemplateKey];
|
||||
}
|
||||
@@ -698,18 +798,17 @@ var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
|
||||
{
|
||||
if (self = [super initWithCoder:coder])
|
||||
{
|
||||
[self _initWithFrame:[self frame]];
|
||||
|
||||
_recentsAutosaveName = [coder decodeObjectForKey:CPRecentsAutosaveNameKey];
|
||||
_sendsWholeSearchString = [coder decodeBoolForKey:CPSendsWholeSearchStringKey];
|
||||
_sendsSearchStringImmediately = [coder decodeBoolForKey:CPSendsSearchStringImmediatelyKey];
|
||||
_maximumRecents = [coder decodeIntForKey:CPMaximumRecentsKey];
|
||||
|
||||
|
||||
var template = [coder decodeObjectForKey:CPSearchMenuTemplateKey];
|
||||
|
||||
if (template)
|
||||
[self setSearchMenuTemplate:template];
|
||||
|
||||
[self setDelegate:self];
|
||||
[self _init];
|
||||
}
|
||||
|
||||
return self;
|
||||
|
||||
@@ -82,7 +82,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (int)selectedTag
|
||||
{
|
||||
return _segments[_selectedSegment].tag;
|
||||
return [_segments[_selectedSegment] tag];
|
||||
}
|
||||
|
||||
// Specifying the number of segments
|
||||
@@ -183,7 +183,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
selected = NO;
|
||||
|
||||
for (; index < _segments.length; ++index)
|
||||
if (_segments[index].selected)
|
||||
if ([_segments[index] selected])
|
||||
if (selected)
|
||||
[self setSelected:NO forSegment:index];
|
||||
else
|
||||
@@ -195,7 +195,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
var index = 0;
|
||||
|
||||
for (; index < _segments.length; ++index)
|
||||
if (_segments[index].selected)
|
||||
if ([_segments[index] selected])
|
||||
[self setSelected:NO forSegment:index];
|
||||
}
|
||||
}
|
||||
@@ -217,7 +217,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (void)setWidth:(float)aWidth forSegment:(unsigned)aSegment
|
||||
{
|
||||
_segments[aSegment].width = aWidth;
|
||||
[_segments[aSegment] setWidth:aWidth];
|
||||
|
||||
[self tileWithChangedSegment:aSegment];
|
||||
}
|
||||
@@ -229,7 +229,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (float)widthForSegment:(unsigned)aSegment
|
||||
{
|
||||
return _segments[aSegment].width;
|
||||
return [_segments[aSegment] width];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -240,9 +240,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (void)setImage:(CPImage)anImage forSegment:(unsigned)aSegment
|
||||
{
|
||||
var segment = _segments[aSegment];
|
||||
|
||||
segment.image = anImage;
|
||||
[_segments[aSegment] setImage:anImage];
|
||||
|
||||
[self tileWithChangedSegment:aSegment];
|
||||
}
|
||||
@@ -254,7 +252,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (CPImage)imageForSegment:(unsigned)aSegment
|
||||
{
|
||||
return _segments[aSegment].image;
|
||||
return [_segments[aSegment] image];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -265,9 +263,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (void)setLabel:(CPString)aLabel forSegment:(unsigned)aSegment
|
||||
{
|
||||
var segment = _segments[aSegment];
|
||||
|
||||
_segments[aSegment].label = aLabel;
|
||||
[_segments[aSegment] setLabel:aLabel];
|
||||
|
||||
[self tileWithChangedSegment:aSegment];
|
||||
}
|
||||
@@ -279,7 +275,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (CPString)labelForSegment:(unsigned)aSegment
|
||||
{
|
||||
return _segments[aSegment].label;
|
||||
return [_segments[aSegment] label];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -290,7 +286,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (void)setMenu:(CPMenu)aMenu forSegment:(unsigned)aSegment
|
||||
{
|
||||
_segments[aSegment].menu = aMenu;
|
||||
[_segments[aSegment] setMenu:aMenu];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -300,7 +296,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (CPMenu)menuForSegment:(unsigned)aSegment
|
||||
{
|
||||
return _segments[aSegment].menu;
|
||||
return [_segments[aSegment] menu];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -315,10 +311,10 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
var segment = _segments[aSegment];
|
||||
|
||||
// If we're already in this state, bail.
|
||||
if (segment.selected == isSelected)
|
||||
if ([segment selected] == isSelected)
|
||||
return;
|
||||
|
||||
segment.selected = isSelected;
|
||||
[segment setSelected:isSelected];
|
||||
|
||||
_themeStates[aSegment] = isSelected ? CPThemeStateSelected : CPThemeStateNormal;
|
||||
|
||||
@@ -331,7 +327,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
|
||||
if (_trackingMode == CPSegmentSwitchTrackingSelectOne && oldSelectedSegment != aSegment && oldSelectedSegment != -1)
|
||||
{
|
||||
_segments[oldSelectedSegment].selected = NO;
|
||||
[_segments[oldSelectedSegment] setSelected:NO];
|
||||
_themeStates[oldSelectedSegment] = CPThemeStateNormal;
|
||||
|
||||
[self drawSegmentBezel:oldSelectedSegment highlight:NO];
|
||||
@@ -352,7 +348,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (BOOL)isSelectedForSegment:(unsigned)aSegment
|
||||
{
|
||||
return _segments[aSegment].selected;
|
||||
return [_segments[aSegment] selected];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -363,6 +359,8 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (void)setEnabled:(BOOL)isEnabled forSegment:(unsigned)aSegment
|
||||
{
|
||||
[_segments[aSegment] setEnabled:isEnabled];
|
||||
|
||||
if (isEnabled)
|
||||
_themeStates[aSegment] &= ~CPThemeStateDisabled;
|
||||
else
|
||||
@@ -379,7 +377,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (BOOL)isEnabledForSegment:(unsigned)aSegment
|
||||
{
|
||||
return !(_themeStates[aSegment] & CPThemeStateDisabled)
|
||||
return [_segments[aSegment] enabled];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -389,7 +387,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (void)setTag:(int)aTag forSegment:(unsigned)aSegment
|
||||
{
|
||||
_segments[aSegment].tag = aTag;
|
||||
[_segments[aSegment] setTag:aTag];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -398,7 +396,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
*/
|
||||
- (int)tagForSegment:(unsigned)aSegment
|
||||
{
|
||||
return _segments[aSegment].tag;
|
||||
return [_segments[aSegment] tag];
|
||||
}
|
||||
|
||||
// Drawings
|
||||
@@ -461,7 +459,7 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
else if (aName.indexOf("segment-bezel") === 0)
|
||||
{
|
||||
var segment = parseInt(aName.substring("segment-bezel-".length), 10),
|
||||
frame = CGRectCreateCopy(_segments[segment].frame);
|
||||
frame = CGRectCreateCopy([_segments[segment] frame]);
|
||||
|
||||
if (segment === 0)
|
||||
{
|
||||
@@ -556,8 +554,8 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
positioned:CPWindowAbove
|
||||
relativeToEphemeralSubviewNamed:@"segment-bezel-"+i];
|
||||
|
||||
[contentView setText:segment.label];
|
||||
[contentView setImage:segment.image];
|
||||
[contentView setText:[segment label]];
|
||||
[contentView setImage:[segment image]];
|
||||
|
||||
[contentView setFont:[self valueForThemeAttribute:@"font" inState:themeState]];
|
||||
[contentView setTextColor:[self valueForThemeAttribute:@"text-color" inState:themeState]];
|
||||
@@ -568,9 +566,9 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
[contentView setTextShadowOffset:[self valueForThemeAttribute:@"text-shadow-offset" inState:themeState]];
|
||||
[contentView setImageScaling:[self valueForThemeAttribute:@"image-scaling" inState:themeState]];
|
||||
|
||||
if (segment.image && segment.label)
|
||||
if ([segment image] && [segment label])
|
||||
[contentView setImagePosition:[self valueForThemeAttribute:@"image-position" inState:themeState]];
|
||||
else if (segment.image)
|
||||
else if ([segment image])
|
||||
[contentView setImagePosition:CPImageOnly];
|
||||
|
||||
if (i == count - 1)
|
||||
@@ -609,27 +607,32 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
return;
|
||||
|
||||
var segment = _segments[aSegment],
|
||||
segmentWidth = segment.width,
|
||||
segmentWidth = [segment width],
|
||||
themeState = _themeStates[aSegment] | (_themeState & CPThemeStateDisabled),
|
||||
contentInset = [self valueForThemeAttribute:@"content-inset" inState:themeState],
|
||||
font = [self valueForThemeAttribute:@"font" inState:themeState];
|
||||
|
||||
if (!segmentWidth)
|
||||
{
|
||||
if (segment.image && segment.label)
|
||||
segmentWidth = [segment.label sizeWithFont:font].width + [segment.image size].width + contentInset.left + contentInset.right;
|
||||
if ([segment image] && [segment label])
|
||||
segmentWidth = [[segment label] sizeWithFont:font].width + [[segment image] size].width + contentInset.left + contentInset.right;
|
||||
else if (segment.image)
|
||||
segmentWidth = [segment.image size].width + contentInset.left + contentInset.right;
|
||||
segmentWidth = [[segment image] size].width + contentInset.left + contentInset.right;
|
||||
else if (segment.label)
|
||||
segmentWidth = [segment.label sizeWithFont:font].width + contentInset.left + contentInset.right;
|
||||
segmentWidth = [[segment label] sizeWithFont:font].width + contentInset.left + contentInset.right;
|
||||
else
|
||||
segmentWidth = 0.0;
|
||||
}
|
||||
|
||||
var delta = segmentWidth - CGRectGetWidth(segment.frame);
|
||||
var delta = segmentWidth - CGRectGetWidth([segment frame]);
|
||||
|
||||
if (!delta)
|
||||
{
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Update Contorl Size
|
||||
var frame = [self frame];
|
||||
@@ -637,15 +640,15 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
[self setFrameSize:CGSizeMake(CGRectGetWidth(frame) + delta, CGRectGetHeight(frame))];
|
||||
|
||||
// Update Segment Width
|
||||
segment.width = segmentWidth;
|
||||
segment.frame = [self frameForSegment:aSegment];;
|
||||
[segment setWidth:segmentWidth];
|
||||
[segment setFrame:[self frameForSegment:aSegment]];
|
||||
|
||||
// Update Following Segments Widths
|
||||
var index = aSegment + 1;
|
||||
|
||||
for (; index < _segments.length; ++index)
|
||||
{
|
||||
_segments[index].frame.origin.x += delta;
|
||||
[_segments[index] frame].origin.x += delta;
|
||||
|
||||
[self drawSegmentBezel:index highlight:NO];
|
||||
[self drawSegment:index highlight:NO];
|
||||
@@ -698,12 +701,12 @@ CPSegmentSwitchTrackingMomentary = 2;
|
||||
count = _segments.length;
|
||||
|
||||
while (count--)
|
||||
if (CGRectContainsPoint(_segments[count].frame, aPoint))
|
||||
if (CGRectContainsPoint([_segments[count] frame], aPoint))
|
||||
return count;
|
||||
|
||||
if (_segments.length)
|
||||
{
|
||||
var adjustedLastFrame = CGRectCreateCopy(_segments[_segments.length - 1].frame);
|
||||
var adjustedLastFrame = CGRectCreateCopy([_segments[_segments.length - 1] frame]);
|
||||
adjustedLastFrame.size.width = CGRectGetWidth([self bounds]) - adjustedLastFrame.origin.x;
|
||||
|
||||
if (CGRectContainsPoint(adjustedLastFrame, aPoint))
|
||||
@@ -844,7 +847,7 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
|
||||
|
||||
for (var i = 0; i < _segments.length; i++)
|
||||
{
|
||||
_themeStates[i] = _segments[i].selected ? CPThemeStateSelected : CPThemeStateNormal;
|
||||
_themeStates[i] = [_segments[i] selected] ? CPThemeStateSelected : CPThemeStateNormal;
|
||||
[self tileWithChangedSegment:i];
|
||||
}
|
||||
|
||||
@@ -852,7 +855,7 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
|
||||
remainingWidth = FLOOR(difference / _segments.length);
|
||||
|
||||
for (var i=0; i < _segments.length; i++)
|
||||
[self setWidth:_segments[i].width + remainingWidth forSegment:i];
|
||||
[self setWidth:[_segments[i] width] + remainingWidth forSegment:i];
|
||||
|
||||
[self tileWithChangedSegment:0];
|
||||
}
|
||||
@@ -875,15 +878,15 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
|
||||
|
||||
@implementation _CPSegmentItem : CPObject
|
||||
{
|
||||
CPImage image;
|
||||
CPString label;
|
||||
CPMenu menu;
|
||||
BOOL selected;
|
||||
BOOL enabled;
|
||||
int tag;
|
||||
int width;
|
||||
CPImage image @accessors;
|
||||
CPString label @accessors;
|
||||
CPMenu menu @accessors;
|
||||
BOOL selected @accessors;
|
||||
BOOL enabled @accessors;
|
||||
int tag @accessors;
|
||||
int width @accessors;
|
||||
|
||||
CGRect frame;
|
||||
CGRect frame @accessors;
|
||||
}
|
||||
|
||||
- (id)init
|
||||
@@ -894,8 +897,8 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
|
||||
label = @"";
|
||||
menu = nil;
|
||||
selected = NO;
|
||||
enabled = NO;
|
||||
tag = 0;
|
||||
enabled = YES;
|
||||
tag = -1;
|
||||
width = 0;
|
||||
|
||||
frame = CGRectMakeZero();
|
||||
|
||||
@@ -35,12 +35,12 @@ CPHeavyShadow = 1;
|
||||
|
||||
var CPShadowViewLightBackgroundColor = nil,
|
||||
CPShadowViewHeavyBackgroundColor = nil;
|
||||
|
||||
|
||||
var LIGHT_LEFT_INSET = 3.0,
|
||||
LIGHT_RIGHT_INSET = 3.0,
|
||||
LIGHT_TOP_INSET = 3.0,
|
||||
LIGHT_BOTTOM_INSET = 5.0,
|
||||
|
||||
|
||||
HEAVY_LEFT_INSET = 7.0,
|
||||
HEAVY_RIGHT_INSET = 7.0,
|
||||
HEAVY_TOP_INSET = 5.0,
|
||||
@@ -61,51 +61,76 @@ var LIGHT_LEFT_INSET = 3.0,
|
||||
return;
|
||||
|
||||
var bundle = [CPBundle bundleForClass:[self class]];
|
||||
|
||||
|
||||
CPShadowViewLightBackgroundColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
|
||||
[
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightTopLeft.png"] size:CGSizeMake(9.0, 9.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightTop.png"] size:CGSizeMake(1.0, 9.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightTopRight.png"] size:CGSizeMake(9.0, 9.0)],
|
||||
|
||||
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightLeft.png"] size:CGSizeMake(9.0, 1.0)],
|
||||
nil,
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightRight.png"] size:CGSizeMake(9.0, 1.0)],
|
||||
|
||||
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightBottomLeft.png"] size:CGSizeMake(9.0, 9.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightBottom.png"] size:CGSizeMake(1.0, 9.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewLightBottomRight.png"] size:CGSizeMake(9.0, 9.0)]
|
||||
]]];
|
||||
|
||||
|
||||
CPShadowViewHeavyBackgroundColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
|
||||
[
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyTopLeft.png"] size:CGSizeMake(17.0, 17.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyTop.png"] size:CGSizeMake(1.0, 17.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyTopRight.png"] size:CGSizeMake(17.0, 17.0)],
|
||||
|
||||
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyLeft.png"] size:CGSizeMake(17.0, 1.0)],
|
||||
nil,
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyRight.png"] size:CGSizeMake(17.0, 1.0)],
|
||||
|
||||
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyBottomLeft.png"] size:CGSizeMake(17.0, 17.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyBottom.png"] size:CGSizeMake(1.0, 17.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPShadowView/CPShadowViewHeavyBottomRight.png"] size:CGSizeMake(17.0, 17.0)]
|
||||
]]];
|
||||
}
|
||||
|
||||
+ (id)shadowViewEnclosingView:(CPView)aView
|
||||
{
|
||||
return [self shadowViewEnclosingView:aView withWeight:CPLightShadow];
|
||||
}
|
||||
|
||||
+ (id)shadowViewEnclosingView:(CPView)aView withWeight:(CPShadowWeight)aWeight
|
||||
{
|
||||
var shadowView = [[CPShadowView alloc] initWithFrame:[aView frame]];
|
||||
[shadowView setWeight:aWeight];
|
||||
|
||||
var size = [shadowView frame].size,
|
||||
width = size.width - [shadowView leftInset] - [shadowView rightInset],
|
||||
height = size.height - [shadowView topInset] - [shadowView bottomInset],
|
||||
enclosingView = [aView superview];
|
||||
|
||||
[shadowView setHitTests:[aView hitTests]];
|
||||
[shadowView setAutoresizingMask:[aView autoresizingMask]];
|
||||
[aView removeFromSuperview];
|
||||
[shadowView addSubview:aView];
|
||||
[aView setFrame:CGRectMake([shadowView leftInset], [shadowView topInset], width, height)]
|
||||
[enclosingView addSubview:shadowView];
|
||||
|
||||
return shadowView;
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_weight = CPLightShadow;
|
||||
|
||||
|
||||
[self setBackgroundColor:CPShadowViewLightBackgroundColor];
|
||||
|
||||
|
||||
[self setHitTests:NO];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -113,9 +138,9 @@ var LIGHT_LEFT_INSET = 3.0,
|
||||
{
|
||||
if (_weight == aWeight)
|
||||
return;
|
||||
|
||||
|
||||
_weight = aWeight;
|
||||
|
||||
|
||||
if (_weight == CPLightShadow)
|
||||
[self setBackgroundColor:CPShadowViewLightBackgroundColor];
|
||||
|
||||
@@ -147,7 +172,7 @@ var LIGHT_LEFT_INSET = 3.0,
|
||||
{
|
||||
if (_weight == CPLightShadow)
|
||||
return LIGHT_LEFT_INSET + LIGHT_RIGHT_INSET;
|
||||
|
||||
|
||||
return HEAVY_LEFT_INSET + HEAVY_RIGHT_INSET;
|
||||
}
|
||||
|
||||
@@ -155,7 +180,7 @@ var LIGHT_LEFT_INSET = 3.0,
|
||||
{
|
||||
if (_weight == CPLightShadow)
|
||||
return LIGHT_TOP_INSET + LIGHT_BOTTOM_INSET;
|
||||
|
||||
|
||||
return HEAVY_TOP_INSET + HEAVY_BOTTOM_INSET;
|
||||
}
|
||||
|
||||
|
||||
@@ -198,7 +198,7 @@ CPCircularSlider = 1;
|
||||
else if ([self isVertical])
|
||||
{
|
||||
knobRect.origin.x = _CGRectGetMidX(trackRect) - knobSize.width / 2.0;
|
||||
knobRect.origin.y = (([self doubleValue] - _minValue) / (_maxValue - _minValue)) * (_CGRectGetHeight(trackRect) - knobSize.height);
|
||||
knobRect.origin.y = ((_maxValue - [self doubleValue]) / (_maxValue - _minValue)) * (_CGRectGetHeight(trackRect) - knobSize.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -320,7 +320,7 @@ CPCircularSlider = 1;
|
||||
|
||||
var minValue = [self minValue];
|
||||
|
||||
return MAX(0.0, MIN(1.0, (aPoint.y - _CGRectGetMinY(trackRect)) / _CGRectGetHeight(trackRect))) * ([self maxValue] - minValue) + minValue;
|
||||
return MAX(0.0, MIN(1.0, (_CGRectGetMaxY(trackRect) - aPoint.y) / _CGRectGetHeight(trackRect))) * ([self maxValue] - minValue) + minValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -47,16 +47,15 @@
|
||||
CPTextField _saturationLabel;
|
||||
CPTextField _brightnessLabel;
|
||||
CPTextField _hexLabel;
|
||||
CPTextField _hexValue;
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
DOMElement _redValue;
|
||||
DOMElement _greenValue;
|
||||
DOMElement _blueValue;
|
||||
DOMElement _hueValue;
|
||||
DOMElement _saturationValue;
|
||||
DOMElement _brightnessValue;
|
||||
DOMElement _hexValue;
|
||||
#endif
|
||||
CPTextField _hexValue;
|
||||
CPTextField _redValue;
|
||||
CPTextField _greenValue;
|
||||
CPTextField _blueValue;
|
||||
CPTextField _hueValue;
|
||||
CPTextField _saturationValue;
|
||||
CPTextField _brightnessValue;
|
||||
}
|
||||
|
||||
- (id)initWithPickerMask:(int)mask colorPanel:(CPColorPanel)owningColorPanel
|
||||
@@ -86,73 +85,13 @@
|
||||
[_redSlider setAction: @selector(sliderChanged:)];
|
||||
[_redSlider setAutoresizingMask: CPViewWidthSizable];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
var updateFunction = function(aDOMEvent)
|
||||
{
|
||||
if(isNaN(this.value))
|
||||
return;
|
||||
|
||||
switch(this)
|
||||
{
|
||||
case _redValue: [_redSlider setFloatValue:MAX(MIN(ROUND(this.value), 255) / 255.0, 0)];
|
||||
//[self sliderChanged: _redSlider];
|
||||
break;
|
||||
|
||||
case _greenValue: [_greenSlider setFloatValue:MAX(MIN(ROUND(this.value), 255) / 255.0, 0)];
|
||||
//[self sliderChanged: _greenSlider];
|
||||
break;
|
||||
|
||||
case _blueValue: [_blueSlider setFloatValue:MAX(MIN(ROUND(this.value), 255) / 255.0, 0)];
|
||||
//[self sliderChanged: _blueSlider];
|
||||
break;
|
||||
|
||||
case _hueValue: [_hueSlider setFloatValue:MAX(MIN(ROUND(this.value), 360), 0)];
|
||||
//[self sliderChanged: _hueSlider];
|
||||
break;
|
||||
|
||||
case _saturationValue: [_saturationSlider setFloatValue:MAX(MIN(ROUND(this.value), 100), 0)];
|
||||
//[self sliderChanged: _saturationSlider];
|
||||
break;
|
||||
|
||||
case _brightnessValue: [_brightnessSlider setFloatValue:MAX(MIN(ROUND(this.value), 100), 0)];
|
||||
//[self sliderChanged: _brightnessSlider];
|
||||
break;
|
||||
}
|
||||
|
||||
this.blur();
|
||||
};
|
||||
|
||||
var keypressFunction = function(aDOMEvent)
|
||||
{
|
||||
aDOMEvent = aDOMEvent || window.event;
|
||||
if (aDOMEvent.keyCode == 13)
|
||||
{
|
||||
updateFunction(aDOMEvent);
|
||||
|
||||
if(aDOMEvent.preventDefault)
|
||||
aDOMEvent.preventDefault();
|
||||
else if(aDOMEvent.stopPropagation)
|
||||
aDOMEvent.stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
//red value input box
|
||||
var redValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 35, 45, 20)];
|
||||
[redValue setAutoresizingMask: CPViewMinXMargin];
|
||||
|
||||
_redValue = document.createElement("input");
|
||||
_redValue.style.width = "40px";
|
||||
_redValue.style.backgroundColor = "transparent";
|
||||
_redValue.style.border = "1px solid black";
|
||||
_redValue.style.color = "black";
|
||||
_redValue.style.position = "absolute";
|
||||
_redValue.style.top = "0px";
|
||||
_redValue.style.left = "0px";
|
||||
_redValue.onchange = updateFunction;
|
||||
|
||||
redValue._DOMElement.appendChild(_redValue);
|
||||
[_contentView addSubview: redValue];
|
||||
#endif
|
||||
// red value input box
|
||||
_redValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 30, 45, 29)];
|
||||
[_redValue setAutoresizingMask: CPViewMinXMargin];
|
||||
[_redValue setEditable: YES];
|
||||
[_redValue setBezeled: YES];
|
||||
[_redValue setDelegate: self];
|
||||
[_contentView addSubview: _redValue];
|
||||
|
||||
_greenLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 58, 15, 20)];
|
||||
[_greenLabel setStringValue: "G"];
|
||||
@@ -165,17 +104,13 @@
|
||||
[_greenSlider setAction: @selector(sliderChanged:)];
|
||||
[_greenSlider setAutoresizingMask: CPViewWidthSizable];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
//green value input box
|
||||
var greenValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 58, 45, 20)];
|
||||
[greenValue setAutoresizingMask: CPViewMinXMargin];
|
||||
|
||||
_greenValue = _redValue.cloneNode(false);
|
||||
_greenValue.onchange = updateFunction;
|
||||
|
||||
greenValue._DOMElement.appendChild(_greenValue);
|
||||
[_contentView addSubview: greenValue];
|
||||
#endif
|
||||
// green value input box
|
||||
_greenValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 53, 45, 29)];
|
||||
[_greenValue setAutoresizingMask: CPViewMinXMargin];
|
||||
[_greenValue setEditable: YES];
|
||||
[_greenValue setBezeled: YES];
|
||||
[_greenValue setDelegate: self];
|
||||
[_contentView addSubview: _greenValue];
|
||||
|
||||
_blueLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 81, 15, 20)];
|
||||
[_blueLabel setStringValue: "B"];
|
||||
@@ -188,17 +123,14 @@
|
||||
[_blueSlider setAction: @selector(sliderChanged:)];
|
||||
[_blueSlider setAutoresizingMask: CPViewWidthSizable];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
//blue value input box
|
||||
var blueValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 81, 45, 20)];
|
||||
[blueValue setAutoresizingMask: CPViewMinXMargin];
|
||||
// blue value input box
|
||||
_blueValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 76, 45, 29)];
|
||||
[_blueValue setAutoresizingMask: CPViewMinXMargin];
|
||||
[_blueValue setEditable: YES];
|
||||
[_blueValue setBezeled: YES];
|
||||
[_blueValue setDelegate: self];
|
||||
[_contentView addSubview: _blueValue];
|
||||
|
||||
_blueValue = _redValue.cloneNode(false);
|
||||
_blueValue.onchange = updateFunction;
|
||||
|
||||
blueValue._DOMElement.appendChild(_blueValue);
|
||||
[_contentView addSubview: blueValue];
|
||||
#endif
|
||||
_hsbLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 120, 190, 20)];
|
||||
[_hsbLabel setStringValue: "Hue, Saturation, Brightness"];
|
||||
[_hsbLabel setTextColor:[CPColor blackColor]];
|
||||
@@ -214,17 +146,14 @@
|
||||
[_hueSlider setAction: @selector(sliderChanged:)];
|
||||
[_hueSlider setAutoresizingMask: CPViewWidthSizable];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
//red value input box
|
||||
var hueValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 145, 45, 20)];
|
||||
[hueValue setAutoresizingMask: CPViewMinXMargin];
|
||||
// hue value input box
|
||||
_hueValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 140, 45, 29)];
|
||||
[_hueValue setAutoresizingMask: CPViewMinXMargin];
|
||||
[_hueValue setEditable: YES];
|
||||
[_hueValue setBezeled: YES];
|
||||
[_hueValue setDelegate: self];
|
||||
[_contentView addSubview: _hueValue];
|
||||
|
||||
_hueValue = _redValue.cloneNode(false);
|
||||
_hueValue.onchange = updateFunction;
|
||||
|
||||
hueValue._DOMElement.appendChild(_hueValue);
|
||||
[_contentView addSubview: hueValue];
|
||||
#endif
|
||||
_saturationLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 168, 15, 20)];
|
||||
[_saturationLabel setStringValue: "S"];
|
||||
[_saturationLabel setTextColor:[CPColor blackColor]];
|
||||
@@ -236,17 +165,14 @@
|
||||
[_saturationSlider setAction: @selector(sliderChanged:)];
|
||||
[_saturationSlider setAutoresizingMask: CPViewWidthSizable];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
//green value input box
|
||||
var saturationValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 168, 45, 20)];
|
||||
[saturationValue setAutoresizingMask: CPViewMinXMargin];
|
||||
// saturation value input box
|
||||
_saturationValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 163, 45, 29)];
|
||||
[_saturationValue setAutoresizingMask: CPViewMinXMargin];
|
||||
[_saturationValue setEditable: YES];
|
||||
[_saturationValue setBezeled: YES];
|
||||
[_saturationValue setDelegate: self];
|
||||
[_contentView addSubview: _saturationValue];
|
||||
|
||||
_saturationValue = _redValue.cloneNode(false);
|
||||
_saturationValue.onchange = updateFunction;
|
||||
|
||||
saturationValue._DOMElement.appendChild(_saturationValue);
|
||||
[_contentView addSubview: saturationValue];
|
||||
#endif
|
||||
_brightnessLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 191, 15, 20)];
|
||||
[_brightnessLabel setStringValue: "B"];
|
||||
[_brightnessLabel setTextColor:[CPColor blackColor]];
|
||||
@@ -258,51 +184,24 @@
|
||||
[_brightnessSlider setAction: @selector(sliderChanged:)];
|
||||
[_brightnessSlider setAutoresizingMask: CPViewWidthSizable];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
//blue value input box
|
||||
var brightnessValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 191, 45, 20)];
|
||||
[brightnessValue setAutoresizingMask: CPViewMinXMargin];
|
||||
// brightness value input box
|
||||
_brightnessValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 186, 45, 29)];
|
||||
[_brightnessValue setAutoresizingMask: CPViewMinXMargin];
|
||||
[_brightnessValue setEditable: YES];
|
||||
[_brightnessValue setBezeled: YES];
|
||||
[_brightnessValue setDelegate: self];
|
||||
[_contentView addSubview: _brightnessValue];
|
||||
|
||||
_brightnessValue = _redValue.cloneNode(false);
|
||||
_brightnessValue.onchange = updateFunction;
|
||||
|
||||
brightnessValue._DOMElement.appendChild(_brightnessValue);
|
||||
[_contentView addSubview: brightnessValue];
|
||||
#endif
|
||||
_hexLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 230, 30, 20)];
|
||||
[_hexLabel setStringValue: "Hex"];
|
||||
[_hexLabel setTextColor:[CPColor blackColor]];
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
//hex input box
|
||||
_hexValue = _redValue.cloneNode(false);
|
||||
_hexValue.style.top = "228px";
|
||||
_hexValue.style.width = "80px";
|
||||
_hexValue.style.left = "35px";
|
||||
_hexValue.onkeypress = function(aDOMEvent)
|
||||
{
|
||||
aDOMEvent = aDOMEvent || window.event;
|
||||
if (aDOMEvent.keyCode == 13)
|
||||
{
|
||||
var newColor = [CPColor colorWithHexString: this.value];
|
||||
|
||||
if(newColor)
|
||||
{
|
||||
[self setColor: newColor];
|
||||
[[self colorPanel] setColor: newColor];
|
||||
}
|
||||
|
||||
if(aDOMEvent.preventDefault)
|
||||
aDOMEvent.preventDefault();
|
||||
else if(aDOMEvent.stopPropagation)
|
||||
aDOMEvent.stopPropagation();
|
||||
|
||||
this.blur();
|
||||
}
|
||||
};
|
||||
|
||||
_contentView._DOMElement.appendChild(_hexValue);
|
||||
#endif
|
||||
_hexValue = [[CPTextField alloc] initWithFrame: CGRectMake(32, 225, 80, 29)];
|
||||
[_hexValue setEditable: YES];
|
||||
[_hexValue setBezeled: YES];
|
||||
[_hexValue setDelegate: self];
|
||||
[_contentView addSubview: _hexValue];
|
||||
|
||||
[_contentView addSubview: _rgbLabel];
|
||||
[_contentView addSubview: _redLabel];
|
||||
@@ -394,9 +293,7 @@
|
||||
|
||||
- (void)updateHex:(CPColor)aColor
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
_hexValue.value = [aColor hexString];
|
||||
#endif
|
||||
[_hexValue setStringValue:[aColor hexString]];
|
||||
}
|
||||
|
||||
- (void)updateRGBSliders:(CPColor)aColor
|
||||
@@ -410,15 +307,13 @@
|
||||
|
||||
- (void)updateLabels
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
_hueValue.value = ROUND([_hueSlider floatValue]);
|
||||
_saturationValue.value = ROUND([_saturationSlider floatValue]);
|
||||
_brightnessValue.value = ROUND([_brightnessSlider floatValue]);
|
||||
[_hueValue setStringValue: ROUND([_hueSlider floatValue])];
|
||||
[_saturationValue setStringValue: ROUND([_saturationSlider floatValue])];
|
||||
[_brightnessValue setStringValue: ROUND([_brightnessSlider floatValue])];
|
||||
|
||||
_redValue.value = ROUND([_redSlider floatValue] * 255);
|
||||
_greenValue.value = ROUND([_greenSlider floatValue] * 255);
|
||||
_blueValue.value = ROUND([_blueSlider floatValue] * 255);
|
||||
#endif
|
||||
[_redValue setStringValue: ROUND([_redSlider floatValue] * 255)];
|
||||
[_greenValue setStringValue: ROUND([_greenSlider floatValue] * 255)];
|
||||
[_blueValue setStringValue: ROUND([_blueSlider floatValue] * 255)];
|
||||
}
|
||||
|
||||
- (CPImage)provideNewButtonImage
|
||||
@@ -431,4 +326,43 @@
|
||||
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:CPColorPicker] pathForResource:"slider_button_h.png"] size:CGSizeMake(32, 32)];
|
||||
}
|
||||
|
||||
- (void)controlTextDidEndEditing:(CPNotification)aNotification
|
||||
{
|
||||
var field = [aNotification object],
|
||||
value = [[field stringValue] stringByTrimmingWhitespace];
|
||||
if (field === _hexValue) {
|
||||
var newColor = [CPColor colorWithHexString: value];
|
||||
if (newColor) {
|
||||
[self setColor: newColor];
|
||||
[[self colorPanel] setColor: newColor];
|
||||
}
|
||||
} else {
|
||||
switch(field) {
|
||||
case _redValue: [_redSlider setFloatValue:MAX(MIN(ROUND(value), 255) / 255.0, 0)];
|
||||
[self sliderChanged: _redSlider];
|
||||
break;
|
||||
|
||||
case _greenValue: [_greenSlider setFloatValue:MAX(MIN(ROUND(value), 255) / 255.0, 0)];
|
||||
[self sliderChanged: _greenSlider];
|
||||
break;
|
||||
|
||||
case _blueValue: [_blueSlider setFloatValue:MAX(MIN(ROUND(value), 255) / 255.0, 0)];
|
||||
[self sliderChanged: _blueSlider];
|
||||
break;
|
||||
|
||||
case _hueValue: [_hueSlider setFloatValue:MAX(MIN(ROUND(value), 360), 0)];
|
||||
[self sliderChanged: _hueSlider];
|
||||
break;
|
||||
|
||||
case _saturationValue: [_saturationSlider setFloatValue:MAX(MIN(ROUND(value), 100), 0)];
|
||||
[self sliderChanged: _saturationSlider];
|
||||
break;
|
||||
|
||||
case _brightnessValue: [_brightnessSlider setFloatValue:MAX(MIN(ROUND(value), 100), 0)];
|
||||
[self sliderChanged: _brightnessSlider];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -47,6 +47,7 @@ var CPSplitViewHorizontalImage = nil,
|
||||
|
||||
int _currentDivider;
|
||||
float _initialOffset;
|
||||
float _preCollapsePosition;
|
||||
|
||||
CPString _originComponent;
|
||||
CPString _sizeComponent;
|
||||
@@ -60,6 +61,17 @@ var CPSplitViewHorizontalImage = nil,
|
||||
CPArray _buttonBars;
|
||||
}
|
||||
|
||||
+ (CPString)themeClass
|
||||
{
|
||||
return @"splitview";
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[10.0, 1.0]
|
||||
forKeys:[@"divider-thickness", @"pane-divider-thickness"]];
|
||||
}
|
||||
|
||||
/*
|
||||
@ignore
|
||||
*/
|
||||
@@ -90,7 +102,7 @@ var CPSplitViewHorizontalImage = nil,
|
||||
|
||||
- (float)dividerThickness
|
||||
{
|
||||
return _isPaneSplitter ? 1.0 : 10.0;
|
||||
return [self currentValueForThemeAttribute:[self isPaneSplitter] ? @"pane-divider-thickness" : @"divider-thickness"];
|
||||
}
|
||||
|
||||
- (BOOL)isVertical
|
||||
@@ -152,7 +164,7 @@ var CPSplitViewHorizontalImage = nil,
|
||||
_isPaneSplitter = shouldBePaneSplitter;
|
||||
|
||||
if(_DOMDividerElements[_drawingDivider])
|
||||
[self _setupDOMDivider]
|
||||
[self _setupDOMDivider];
|
||||
|
||||
// The divider changes size when pane splitter mode is toggled, so the
|
||||
// subviews need to change size too.
|
||||
@@ -293,7 +305,7 @@ var CPSplitViewHorizontalImage = nil,
|
||||
if ([_delegate respondsToSelector:@selector(splitView:additionalEffectiveRectOfDividerAtIndex:)])
|
||||
additionalRect = [_delegate splitView:self additionalEffectiveRectOfDividerAtIndex:anIndex];
|
||||
|
||||
return CGRectContainsPoint(effectiveRect, aPoint) ||
|
||||
return CGRectContainsPoint(effectiveRect, aPoint) ||
|
||||
(additionalRect && CGRectContainsPoint(additionalRect, aPoint)) ||
|
||||
(buttonBarRect && CGRectContainsPoint(buttonBarRect, aPoint));
|
||||
}
|
||||
@@ -358,14 +370,14 @@ var CPSplitViewHorizontalImage = nil,
|
||||
if ([_delegate splitView:self canCollapseSubview:_subviews[i]] && [_delegate splitView:self shouldCollapseSubview:_subviews[i] forDoubleClickOnDividerAtIndex:i])
|
||||
{
|
||||
if ([self isSubviewCollapsed:_subviews[i]])
|
||||
[self setPosition:(minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i];
|
||||
[self setPosition:_preCollapsePosition ? _preCollapsePosition : (minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i];
|
||||
else
|
||||
[self setPosition:minPosition ofDividerAtIndex:i];
|
||||
}
|
||||
else if ([_delegate splitView:self canCollapseSubview:_subviews[i+1]] && [_delegate splitView:self shouldCollapseSubview:_subviews[i+1] forDoubleClickOnDividerAtIndex:i])
|
||||
{
|
||||
if ([self isSubviewCollapsed:_subviews[i+1]])
|
||||
[self setPosition:(minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i];
|
||||
[self setPosition:_preCollapsePosition ? _preCollapsePosition : (minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i];
|
||||
else
|
||||
[self setPosition:maxPosition ofDividerAtIndex:i];
|
||||
}
|
||||
@@ -444,11 +456,19 @@ var CPSplitViewHorizontalImage = nil,
|
||||
if (_currentDivider === i || (_currentDivider == CPNotFound && [self cursorAtPoint:point hitDividerAtIndex:i]))
|
||||
{
|
||||
var frame = [_subviews[i] frame],
|
||||
startPosition = frame.origin[_originComponent] + frame.size[_sizeComponent],
|
||||
size = frame.size[_sizeComponent],
|
||||
startPosition = frame.origin[_originComponent] + size,
|
||||
canShrink = [self _realPositionForPosition:startPosition-1 ofDividerAtIndex:i] < startPosition,
|
||||
canGrow = [self _realPositionForPosition:startPosition+1 ofDividerAtIndex:i] > startPosition,
|
||||
cursor = [CPCursor arrowCursor];
|
||||
|
||||
if (size === 0)
|
||||
canGrow = YES; // Subview is collapsed.
|
||||
else if (!canShrink &&
|
||||
[_delegate respondsToSelector:@selector(splitView:canCollapseSubview:)] &&
|
||||
[_delegate splitView:self canCollapseSubview:_subviews[i]])
|
||||
canShrink = YES; // Subview is collapsible.
|
||||
|
||||
if (_isVertical && canShrink && canGrow)
|
||||
cursor = [CPCursor resizeLeftRightCursor];
|
||||
else if (_isVertical && canShrink)
|
||||
@@ -531,10 +551,18 @@ var CPSplitViewHorizontalImage = nil,
|
||||
viewB = _subviews[dividerIndex + 1],
|
||||
frameB = [viewB frame];
|
||||
|
||||
_preCollapsePosition = 0;
|
||||
|
||||
var preSize = frameA.size[_sizeComponent];
|
||||
frameA.size[_sizeComponent] = realPosition - frameA.origin[_originComponent];
|
||||
if (preSize !== 0 && frameA.size[_sizeComponent] === 0)
|
||||
_preCollapsePosition = preSize;
|
||||
[_subviews[dividerIndex] setFrame:frameA];
|
||||
|
||||
preSize = frameB.size[_sizeComponent];
|
||||
frameB.size[_sizeComponent] = frameB.origin[_originComponent] + frameB.size[_sizeComponent] - realPosition - [self dividerThickness];
|
||||
if (preSize !== 0 && frameB.size[_sizeComponent] === 0)
|
||||
_preCollapsePosition = preSize;
|
||||
frameB.origin[_originComponent] = realPosition + [self dividerThickness];
|
||||
[_subviews[dividerIndex + 1] setFrame:frameB];
|
||||
|
||||
@@ -641,14 +669,14 @@ var CPSplitViewHorizontalImage = nil,
|
||||
|
||||
/*!
|
||||
Set the button bar who's resize control should act as a control for this splitview.
|
||||
Each divider can have at most one button bar assigned to it, and that button bar must be
|
||||
Each divider can have at most one button bar assigned to it, and that button bar must be
|
||||
a subview of one of the split view's subviews.
|
||||
|
||||
Calling this method with nil as the button bar will remove any currently assigned button bar
|
||||
for the divider at that index. Indexes will not be adjusted as new subviews are added, so you
|
||||
should usually call this method after adding all the desired subviews to the split view.
|
||||
|
||||
This method will automatically configure the hasResizeControl and resizeControlIsLeftAligned
|
||||
This method will automatically configure the hasResizeControl and resizeControlIsLeftAligned
|
||||
parameters of the button bar, and will override any currently set values.
|
||||
*/
|
||||
- (void)setButtonBar:(CPButtonBar)aButtonBar forDividerAtIndex:(unsigned)dividerIndex
|
||||
@@ -669,7 +697,7 @@ var CPSplitViewHorizontalImage = nil,
|
||||
}
|
||||
|
||||
if (view !== self)
|
||||
[CPException raise:CPInvalidArgumentException
|
||||
[CPException raise:CPInvalidArgumentException
|
||||
reason:@"CPSplitView button bar must be a subview of the split view."];
|
||||
|
||||
var viewIndex = [[self subviews] indexOfObject:subview];
|
||||
@@ -677,7 +705,7 @@ var CPSplitViewHorizontalImage = nil,
|
||||
[aButtonBar setHasResizeControl:YES];
|
||||
[aButtonBar setResizeControlIsLeftAligned:dividerIndex < viewIndex];
|
||||
|
||||
_buttonBars[dividerIndex] = aButtonBar;
|
||||
_buttonBars[dividerIndex] = aButtonBar;
|
||||
}
|
||||
|
||||
- (void)_postNotificationWillResize
|
||||
@@ -714,7 +742,7 @@ var CPSplitViewDelegateKey = "CPSplitViewDelegateKey",
|
||||
_DOMDividerElements = [];
|
||||
|
||||
_buttonBars = [aCoder decodeObjectForKey:CPSplitViewButtonBarsKey] || [];
|
||||
|
||||
|
||||
_delegate = [aCoder decodeObjectForKey:CPSplitViewDelegateKey];
|
||||
|
||||
_isPaneSplitter = [aCoder decodeBoolForKey:CPSplitViewIsPaneSplitterKey];
|
||||
|
||||
@@ -27,6 +27,14 @@
|
||||
|
||||
@implementation CPString (CPStringDrawing)
|
||||
|
||||
/*!
|
||||
Returns a dictionary with the items "ascender", "descender", "lineHeight"
|
||||
*/
|
||||
+ (CPDictionary)metricsOfFont:(CPFont)aFont
|
||||
{
|
||||
return [CPPlatformString metricsOfFont:aFont];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the string
|
||||
*/
|
||||
|
||||
@@ -63,20 +63,20 @@ var CPTabViewBezelBorderLeftImage = nil,
|
||||
|
||||
var LEFT_INSET = 7.0,
|
||||
RIGHT_INSET = 7.0;
|
||||
|
||||
|
||||
var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
CPTabViewShouldSelectTabViewItemSelector = 2,
|
||||
CPTabViewWillSelectTabViewItemSelector = 4,
|
||||
CPTabViewDidChangeNumberOfTabViewItemsSelector = 8;
|
||||
|
||||
/*!
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPTabView
|
||||
|
||||
This class represents a view that has multiple subviews (CPTabViewItem) presented as individual tabs.
|
||||
Only one CPTabViewItem is shown at a time, and other CPTabViewItems can be made visible
|
||||
(one at a time) by clicking on the CPTabViewItem's tab at the top of the tab view.
|
||||
|
||||
|
||||
THe currently selected CPTabViewItem is the view that is displayed.
|
||||
*/
|
||||
@implementation CPTabView : CPView
|
||||
@@ -84,15 +84,15 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
CPView _labelsView;
|
||||
CPView _backgroundView;
|
||||
CPView _separatorView;
|
||||
|
||||
|
||||
CPView _auxiliaryView;
|
||||
CPView _contentView;
|
||||
|
||||
|
||||
CPArray _tabViewItems;
|
||||
CPTabViewItem _selectedTabViewItem;
|
||||
|
||||
CPTabViewType _tabViewType;
|
||||
|
||||
|
||||
id _delegate;
|
||||
unsigned _delegateSelectors;
|
||||
}
|
||||
@@ -104,20 +104,20 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
{
|
||||
if (self != CPTabView)
|
||||
return;
|
||||
|
||||
|
||||
var bundle = [CPBundle bundleForClass:self],
|
||||
|
||||
|
||||
emptyImage = [[CPImage alloc] initByReferencingFile:@"" size:CGSizeMake(7.0, 0.0)],
|
||||
backgroundImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/CPTabViewBezelBackgroundCenter.png"] size:CGSizeMake(1.0, 1.0)],
|
||||
|
||||
|
||||
bezelBorderLeftImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/CPTabViewBezelBorderLeft.png"] size:CGSizeMake(7.0, 1.0)],
|
||||
bezerBorderImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/CPTabViewBezelBorder.png"] size:CGSizeMake(1.0, 1.0)],
|
||||
bezelBorderRightImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/CPTabViewBezelBorderRight.png"] size:CGSizeMake(7.0, 1.0)];
|
||||
|
||||
|
||||
CPTabViewBezelBorderBackgroundColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
|
||||
[
|
||||
emptyImage,
|
||||
emptyImage,
|
||||
emptyImage,
|
||||
emptyImage,
|
||||
emptyImage,
|
||||
|
||||
bezelBorderLeftImage,
|
||||
@@ -128,7 +128,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
bezerBorderImage,
|
||||
bezelBorderRightImage
|
||||
]]];
|
||||
|
||||
|
||||
CPTabViewBezelBorderColor = [CPColor colorWithPatternImage:bezerBorderImage];
|
||||
}
|
||||
|
||||
@@ -143,13 +143,13 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_tabViewType = CPTopTabsBezelBorder;
|
||||
_tabViewItems = [];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
{
|
||||
if (_tabViewType != CPTopTabsBezelBorder || _labelsView)
|
||||
return;
|
||||
|
||||
|
||||
[self _createBezelBorder];
|
||||
[self layoutSubviews];
|
||||
}
|
||||
@@ -166,7 +166,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
- (void)_createBezelBorder
|
||||
{
|
||||
var bounds = [self bounds];
|
||||
|
||||
|
||||
_labelsView = [[_CPTabLabelsView alloc] initWithFrame:CGRectMake(0.0, 0.0, CGRectGetWidth(bounds), 0.0)];
|
||||
|
||||
[_labelsView setTabView:self];
|
||||
@@ -174,19 +174,19 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
|
||||
[self addSubview:_labelsView];
|
||||
|
||||
_backgroundView = [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
_backgroundView = [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[_backgroundView setBackgroundColor:CPTabViewBezelBorderBackgroundColor];
|
||||
|
||||
[_backgroundView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
|
||||
|
||||
[self addSubview:_backgroundView];
|
||||
|
||||
|
||||
_separatorView = [[CPView alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
[_separatorView setBackgroundColor:[[self class] bezelBorderColor]];
|
||||
[_separatorView setAutoresizingMask:CPViewWidthSizable | CPViewMaxYMargin];
|
||||
|
||||
|
||||
[self addSubview:_separatorView];
|
||||
}
|
||||
|
||||
@@ -200,21 +200,21 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
{
|
||||
var backgroundRect = [self bounds],
|
||||
labelsViewHeight = [_CPTabLabelsView height];
|
||||
|
||||
|
||||
backgroundRect.origin.y += labelsViewHeight;
|
||||
backgroundRect.size.height -= labelsViewHeight;
|
||||
|
||||
|
||||
[_backgroundView setFrame:backgroundRect];
|
||||
|
||||
|
||||
var auxiliaryViewHeight = 5.0;
|
||||
|
||||
|
||||
if (_auxiliaryView)
|
||||
{
|
||||
auxiliaryViewHeight = CGRectGetHeight([_auxiliaryView frame]);
|
||||
|
||||
|
||||
[_auxiliaryView setFrame:CGRectMake(LEFT_INSET, labelsViewHeight, CGRectGetWidth(backgroundRect) - LEFT_INSET - RIGHT_INSET, auxiliaryViewHeight)];
|
||||
}
|
||||
|
||||
|
||||
[_separatorView setFrame:CGRectMake(LEFT_INSET, labelsViewHeight + auxiliaryViewHeight, CGRectGetWidth(backgroundRect) - LEFT_INSET - RIGHT_INSET, 1.0)];
|
||||
}
|
||||
|
||||
@@ -240,15 +240,15 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
*/
|
||||
- (void)insertTabViewItem:(CPTabViewItem)aTabViewItem atIndex:(unsigned)anIndex
|
||||
{
|
||||
if (!_labelsView && _tabViewType == CPTopTabsBezelBorder)
|
||||
if (!_labelsView)
|
||||
[self _createBezelBorder];
|
||||
|
||||
|
||||
[_tabViewItems insertObject:aTabViewItem atIndex:anIndex];
|
||||
|
||||
|
||||
[_labelsView tabView:self didAddTabViewItem:aTabViewItem];
|
||||
|
||||
|
||||
[aTabViewItem _setTabView:self];
|
||||
|
||||
|
||||
if ([_tabViewItems count] == 1)
|
||||
[self selectFirstTabViewItem:self];
|
||||
|
||||
@@ -265,11 +265,11 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
var index = [self indexOfTabViewItem:aTabViewItem];
|
||||
|
||||
[_tabViewItems removeObjectIdenticalTo:aTabViewItem];
|
||||
|
||||
|
||||
[_labelsView tabView:self didRemoveTabViewItemAtIndex:index];
|
||||
|
||||
|
||||
[aTabViewItem _setTabView:nil];
|
||||
|
||||
|
||||
if (_delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
|
||||
[_delegate tabViewDidChangeNumberOfTabViewItems:self];
|
||||
}
|
||||
@@ -292,7 +292,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
{
|
||||
var index = 0,
|
||||
count = [_tabViewItems count];
|
||||
|
||||
|
||||
for (; index < count; ++index)
|
||||
if ([[_tabViewItems[index] identifier] isEqual:anIdentifier])
|
||||
return index;
|
||||
@@ -332,7 +332,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
- (void)selectFirstTabViewItem:(id)aSender
|
||||
{
|
||||
var count = [_tabViewItems count];
|
||||
|
||||
|
||||
if (count)
|
||||
[self selectTabViewItemAtIndex:0];
|
||||
}
|
||||
@@ -344,7 +344,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
- (void)selectLastTabViewItem:(id)aSender
|
||||
{
|
||||
var count = [_tabViewItems count];
|
||||
|
||||
|
||||
if (count)
|
||||
[self selectTabViewItemAtIndex:count - 1];
|
||||
}
|
||||
@@ -357,10 +357,10 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
{
|
||||
if (!_selectedTabViewItem)
|
||||
return;
|
||||
|
||||
|
||||
var index = [self indexOfTabViewItem:_selectedTabViewItem],
|
||||
count = [_tabViewItems count];
|
||||
|
||||
|
||||
[self selectTabViewItemAtIndex:index + 1 % count];
|
||||
}
|
||||
|
||||
@@ -372,10 +372,10 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
{
|
||||
if (!_selectedTabViewItem)
|
||||
return;
|
||||
|
||||
|
||||
var index = [self indexOfTabViewItem:_selectedTabViewItem],
|
||||
count = [_tabViewItems count];
|
||||
|
||||
|
||||
[self selectTabViewItemAtIndex:index == 0 ? count : index - 1];
|
||||
}
|
||||
|
||||
@@ -387,7 +387,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
{
|
||||
if ((_delegateSelectors & CPTabViewShouldSelectTabViewItemSelector) && ![_delegate tabView:self shouldSelectTabViewItem:aTabViewItem])
|
||||
return;
|
||||
|
||||
|
||||
if (_delegateSelectors & CPTabViewWillSelectTabViewItemSelector)
|
||||
[_delegate tabView:self willSelectTabViewItem:aTabViewItem];
|
||||
|
||||
@@ -395,29 +395,35 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
{
|
||||
_selectedTabViewItem._tabState = CPBackgroundTab;
|
||||
[_labelsView tabView:self didChangeStateOfTabViewItem:_selectedTabViewItem];
|
||||
|
||||
[_contentView removeFromSuperview];
|
||||
[_auxiliaryView removeFromSuperview];
|
||||
}
|
||||
_selectedTabViewItem = aTabViewItem;
|
||||
|
||||
_selectedTabViewItem._tabState = CPSelectedTab;
|
||||
|
||||
_contentView = [_selectedTabViewItem view];
|
||||
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
|
||||
_auxiliaryView = [_selectedTabViewItem auxiliaryView];
|
||||
[_auxiliaryView setAutoresizingMask:CPViewWidthSizable];
|
||||
|
||||
[self addSubview:_contentView];
|
||||
|
||||
if (_auxiliaryView)
|
||||
_selectedTabViewItem._tabState = CPSelectedTab;
|
||||
|
||||
var _previousContentView = _contentView;
|
||||
_contentView = [_selectedTabViewItem view];
|
||||
|
||||
if (_previousContentView !== _contentView)
|
||||
{
|
||||
[_previousContentView removeFromSuperview];
|
||||
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
|
||||
[self addSubview:_contentView];
|
||||
}
|
||||
|
||||
var _previousAuxiliaryView = _auxiliaryView;
|
||||
_auxiliaryView = [_selectedTabViewItem auxiliaryView];
|
||||
|
||||
if (_previousAuxiliaryView !== _auxiliaryView)
|
||||
{
|
||||
[_previousAuxiliaryView removeFromSuperview];
|
||||
[_auxiliaryView setAutoresizingMask:CPViewWidthSizable];
|
||||
[self addSubview:_auxiliaryView];
|
||||
|
||||
}
|
||||
|
||||
[_labelsView tabView:self didChangeStateOfTabViewItem:_selectedTabViewItem];
|
||||
|
||||
|
||||
[self layoutSubviews];
|
||||
|
||||
|
||||
if (_delegateSelectors & CPTabViewDidSelectTabViewItemSelector)
|
||||
[_delegate tabView:self didSelectTabViewItem:aTabViewItem];
|
||||
}
|
||||
@@ -439,7 +445,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
return _selectedTabViewItem;
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
/*!
|
||||
Sets the tab view type.
|
||||
@param aTabViewType the view type
|
||||
@@ -448,19 +454,19 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
{
|
||||
if (_tabViewType == aTabViewType)
|
||||
return;
|
||||
|
||||
|
||||
_tabViewType = aTabViewType;
|
||||
|
||||
|
||||
if (_tabViewType == CPNoTabsBezelBorder || _tabViewType == CPNoTabsLineBorder || _tabViewType == CPNoTabsNoBorder)
|
||||
[_labelsView removeFromSuperview];
|
||||
else if (![_labelsView superview])
|
||||
else if (_labelsView && ![_labelsView superview])
|
||||
[self addSubview:_labelsView];
|
||||
|
||||
|
||||
if (_tabViewType == CPNoTabsLineBorder || _tabViewType == CPNoTabsNoBorder)
|
||||
[_backgroundView removeFromSuperview];
|
||||
else if (![_backgroundView superview])
|
||||
else if (_backgroundView && ![_backgroundView superview])
|
||||
[self addSubview:_backgroundView];
|
||||
|
||||
|
||||
[self layoutSubviews];
|
||||
}
|
||||
|
||||
@@ -479,7 +485,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
- (CGRect)contentRect
|
||||
{
|
||||
var contentRect = CGRectMakeCopy([self bounds]);
|
||||
|
||||
|
||||
if (_tabViewType == CPTopTabsBezelBorder)
|
||||
{
|
||||
var labelsViewHeight = [_CPTabLabelsView height],
|
||||
@@ -488,7 +494,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
|
||||
contentRect.origin.y += labelsViewHeight + auxiliaryViewHeight + separatorViewHeight;
|
||||
contentRect.size.height -= labelsViewHeight + auxiliaryViewHeight + separatorViewHeight * 2.0; // 2 for the bottom border as well.
|
||||
|
||||
|
||||
contentRect.origin.x += LEFT_INSET;
|
||||
contentRect.size.width -= LEFT_INSET + RIGHT_INSET;
|
||||
}
|
||||
@@ -512,9 +518,9 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
{
|
||||
if (_delegate == aDelegate)
|
||||
return;
|
||||
|
||||
|
||||
_delegate = aDelegate;
|
||||
|
||||
|
||||
_delegateSelectors = 0;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(tabView:shouldSelectTabViewItem:)])
|
||||
@@ -527,7 +533,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
_delegateSelectors |= CPTabViewDidSelectTabViewItemSelector;
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(tabViewDidChangeNumberOfTabViewItems:)])
|
||||
_delegateSelectors |= CPTabViewDidChangeNumberOfTabViewItemsSelector;
|
||||
_delegateSelectors |= CPTabViewDidChangeNumberOfTabViewItemsSelector;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -536,7 +542,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
|
||||
{
|
||||
var location = [_labelsView convertPoint:[anEvent locationInWindow] fromView:nil],
|
||||
tabViewItem = [_labelsView representedTabViewItemAtPoint:location];
|
||||
|
||||
|
||||
if (tabViewItem)
|
||||
[self selectTabViewItem:tabViewItem];
|
||||
}
|
||||
@@ -556,18 +562,18 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
|
||||
{
|
||||
_tabViewType = [aCoder decodeIntForKey:CPTabViewTypeKey];
|
||||
_tabViewItems = [];
|
||||
|
||||
|
||||
// FIXME: this is somewhat hacky
|
||||
[self _createBezelBorder];
|
||||
|
||||
|
||||
var items = [aCoder decodeObjectForKey:CPTabViewItemsKey];
|
||||
for (var i = 0; items && i < items.length; i++)
|
||||
[self insertTabViewItem:items[i] atIndex:i];
|
||||
|
||||
|
||||
var selected = [aCoder decodeObjectForKey:CPTabViewSelectedItemKey];
|
||||
if (selected)
|
||||
[self selectTabViewItem:selected];
|
||||
|
||||
|
||||
[self setDelegate:[aCoder decodeObjectForKey:CPTabViewDelegateKey]];
|
||||
}
|
||||
|
||||
@@ -580,12 +586,12 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
|
||||
_subviews = [];
|
||||
[super encodeWithCoder:aCoder];
|
||||
_subviews = actualSubviews;
|
||||
|
||||
|
||||
[aCoder encodeObject:_tabViewItems forKey:CPTabViewItemsKey];;
|
||||
[aCoder encodeObject:_selectedTabViewItem forKey:CPTabViewSelectedItemKey];
|
||||
|
||||
|
||||
[aCoder encodeInt:_tabViewType forKey:CPTabViewTypeKey];
|
||||
|
||||
|
||||
[aCoder encodeConditionalObject:_delegate forKey:CPTabViewDelegateKey];
|
||||
}
|
||||
|
||||
@@ -609,7 +615,7 @@ var _CPTabLabelsViewBackgroundColor = nil,
|
||||
return;
|
||||
|
||||
var bundle = [CPBundle bundleForClass:self];
|
||||
|
||||
|
||||
_CPTabLabelsViewBackgroundColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
|
||||
[
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelsViewLeft.png"] size:CGSizeMake(12.0, 26.0)],
|
||||
@@ -626,16 +632,16 @@ var _CPTabLabelsViewBackgroundColor = nil,
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_tabLabels = [];
|
||||
|
||||
|
||||
[self setBackgroundColor:_CPTabLabelsViewBackgroundColor];
|
||||
|
||||
[self setFrameSize:CGSizeMake(CGRectGetWidth(aFrame), 26.0)];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -652,24 +658,24 @@ var _CPTabLabelsViewBackgroundColor = nil,
|
||||
- (void)tabView:(CPTabView)aTabView didAddTabViewItem:(CPTabViewItem)aTabViewItem
|
||||
{
|
||||
var label = [[_CPTabLabel alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
|
||||
[label setTabViewItem:aTabViewItem];
|
||||
|
||||
|
||||
_tabLabels.push(label);
|
||||
|
||||
|
||||
[self addSubview:label];
|
||||
|
||||
|
||||
[self layoutSubviews];
|
||||
}
|
||||
|
||||
- (void)tabView:(CPTabView)aTabView didRemoveTabViewItemAtIndex:(unsigned)index
|
||||
{
|
||||
var label = _tabLabels[index];
|
||||
|
||||
|
||||
[_tabLabels removeObjectAtIndex:index];
|
||||
|
||||
[label removeFromSuperview];
|
||||
|
||||
|
||||
[self layoutSubviews];
|
||||
}
|
||||
|
||||
@@ -682,11 +688,11 @@ var _CPTabLabelsViewBackgroundColor = nil,
|
||||
{
|
||||
var index = 0,
|
||||
count = _tabLabels.length;
|
||||
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var label = _tabLabels[index];
|
||||
|
||||
|
||||
if (CGRectContainsPoint([label frame], aPoint))
|
||||
return [label tabViewItem];
|
||||
}
|
||||
@@ -700,14 +706,14 @@ var _CPTabLabelsViewBackgroundColor = nil,
|
||||
count = _tabLabels.length,
|
||||
width = (_CGRectGetWidth([self bounds]) - (count - 1) * _CPTabLabelsViewInsideMargin - 2 * _CPTabLabelsViewOutsideMargin) / count,
|
||||
x = _CPTabLabelsViewOutsideMargin;
|
||||
|
||||
|
||||
for (; index < count; ++index)
|
||||
{
|
||||
var label = _tabLabels[index],
|
||||
frame = _CGRectMake(x, 8.0, width, 18.0);
|
||||
|
||||
|
||||
[label setFrame:frame];
|
||||
|
||||
|
||||
x = _CGRectGetMaxX(frame) + _CPTabLabelsViewInsideMargin;
|
||||
}
|
||||
}
|
||||
@@ -716,9 +722,9 @@ var _CPTabLabelsViewBackgroundColor = nil,
|
||||
{
|
||||
if (CGSizeEqualToSize([self frame].size, aSize))
|
||||
return;
|
||||
|
||||
|
||||
[super setFrameSize:aSize];
|
||||
|
||||
|
||||
[self layoutSubviews];
|
||||
}
|
||||
|
||||
@@ -740,14 +746,14 @@ var _CPTabLabelBackgroundColor = nil,
|
||||
return;
|
||||
|
||||
var bundle = [CPBundle bundleForClass:self];
|
||||
|
||||
|
||||
_CPTabLabelBackgroundColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
|
||||
[
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelBackgroundLeft.png"] size:CGSizeMake(6.0, 18.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelBackgroundCenter.png"] size:CGSizeMake(1.0, 18.0)],
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelBackgroundRight.png"] size:CGSizeMake(6.0, 18.0)]
|
||||
] isVertical:NO]];
|
||||
|
||||
|
||||
_CPTabLabelSelectedBackgroundColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
|
||||
[
|
||||
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPTabView/_CPTabLabelSelectedLeft.png"] size:CGSizeMake(3.0, 18.0)],
|
||||
@@ -759,21 +765,21 @@ var _CPTabLabelBackgroundColor = nil,
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
{
|
||||
self = [super initWithFrame:aFrame];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
{
|
||||
_labelField = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
|
||||
|
||||
|
||||
[_labelField setAlignment:CPCenterTextAlignment];
|
||||
[_labelField setFrame:CGRectMake(5.0, 0.0, CGRectGetWidth(aFrame) - 10.0, 20.0)];
|
||||
[_labelField setAutoresizingMask:CPViewWidthSizable];
|
||||
[_labelField setFont:[CPFont boldSystemFontOfSize:11.0]];
|
||||
|
||||
|
||||
[self addSubview:_labelField];
|
||||
|
||||
|
||||
[self setTabState:CPBackgroundTab];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -785,7 +791,7 @@ var _CPTabLabelBackgroundColor = nil,
|
||||
- (void)setTabViewItem:(CPTabViewItem)aTabViewItem
|
||||
{
|
||||
_tabViewItem = aTabViewItem;
|
||||
|
||||
|
||||
[self update];
|
||||
}
|
||||
|
||||
|
||||
@@ -78,18 +78,7 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
var header = [[_CPTableColumnHeaderView alloc] initWithFrame:CGRectMakeZero()];
|
||||
[self setHeaderView:header];
|
||||
|
||||
var textDataView = [CPTextField new];
|
||||
|
||||
[textDataView setValue:[CPColor colorWithRed:51.0 / 255.0 green:51.0 / 255.0 blue:51.0 / 255.0 alpha:1.0]
|
||||
forThemeAttribute:"text-color"];
|
||||
|
||||
[textDataView setValue:[CPColor whiteColor] forThemeAttribute:@"text-color" inState:CPThemeStateSelectedDataView];
|
||||
[textDataView setLineBreakMode:CPLineBreakByTruncatingTail];
|
||||
[textDataView setValue:[CPFont boldSystemFontOfSize:12.0] forThemeAttribute:@"font" inState:CPThemeStateSelectedDataView];
|
||||
[textDataView setValue:CPCenterVerticalTextAlignment forThemeAttribute:@"vertical-alignment"];
|
||||
[textDataView setValue:CGInsetMake(0.0, 0.0, 0.0, 5.0) forThemeAttribute:@"content-inset"];
|
||||
|
||||
[self setDataView:textDataView];
|
||||
[self setDataView:[CPTextField new]];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -237,12 +226,12 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
|
||||
/*!
|
||||
This method set's the "prototype" view which will be used to create all table cells in this column.
|
||||
|
||||
It creates a snapshot of aView, using keyed archiving, which is then copied over and over for each
|
||||
|
||||
It creates a snapshot of aView, using keyed archiving, which is then copied over and over for each
|
||||
individual cell that is shown. As a result, changes made after calling this method won't be reflected.
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
[tableColumn setDataView:someView]; // snapshot taken
|
||||
[[tableColumn dataView] setSomething:x]; //won't work
|
||||
|
||||
@@ -259,6 +248,8 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
if (_dataView)
|
||||
_dataViewData[[_dataView UID]] = nil;
|
||||
|
||||
[aView setThemeState:CPThemeStateTableDataView];
|
||||
|
||||
_dataView = aView;
|
||||
_dataViewData[[aView UID]] = [CPKeyedArchiver archivedDataWithRootObject:aView];
|
||||
}
|
||||
@@ -298,6 +289,9 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
var newDataView = [CPKeyedUnarchiver unarchiveObjectWithData:_dataViewData[dataViewUID]];
|
||||
newDataView.identifier = dataViewUID;
|
||||
|
||||
// make sure only we have control over the size and placement
|
||||
[newDataView setAutoresizingMask:CPViewNotSizable];
|
||||
|
||||
return newDataView;
|
||||
}
|
||||
|
||||
@@ -356,9 +350,9 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
shouldBeHidden = !!shouldBeHidden
|
||||
if (_isHidden === shouldBeHidden)
|
||||
return;
|
||||
|
||||
|
||||
_isHidden = shouldBeHidden;
|
||||
|
||||
|
||||
[[self headerView] setHidden:shouldBeHidden];
|
||||
[[self tableView] _tableColumnVisibilityDidChange:self];
|
||||
}
|
||||
@@ -413,7 +407,8 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
{
|
||||
var bindingName = keys[i],
|
||||
bindingPath = [aDataView _replacementKeyPathForBinding:bindingName],
|
||||
bindingInfo = [bindingsDictionary objectForKey:bindingName]._info,
|
||||
binding = [bindingsDictionary objectForKey:bindingName],
|
||||
bindingInfo = binding._info,
|
||||
destination = [bindingInfo objectForKey:CPObservedObjectKey],
|
||||
keyPath = [bindingInfo objectForKey:CPObservedKeyPathKey],
|
||||
dotIndex = keyPath.lastIndexOf("."),
|
||||
@@ -444,6 +439,8 @@ CPTableColumnUserResizingMask = 1 << 1;
|
||||
value = [[firstValue valueForKeyPath:secondPart] objectAtIndex:aRow];
|
||||
}
|
||||
|
||||
value = [binding transformValue:value withOptions:[bindingInfo objectForKey:CPOptionsKey]];
|
||||
|
||||
// console.log(bindingName+" : "+keyPath+" : "+aRow+" : "+[[destination valueForKeyPath:keyPath] objectAtIndex:aRow]);
|
||||
[aDataView setValue:value forKey:bindingPath];
|
||||
}
|
||||
@@ -468,9 +465,9 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
|
||||
CPTableColumnMinWidthKey = @"CPTableColumnMinWidthKey",
|
||||
CPTableColumnMaxWidthKey = @"CPTableColumnMaxWidthKey",
|
||||
CPTableColumnResizingMaskKey = @"CPTableColumnResizingMaskKey",
|
||||
CPTableColumnIsHiddenkey = @"CPTableColumnIsHiddenKey",
|
||||
CPSortDescriptorPrototypeKey = @"CPSortDescriptorPrototypeKey";
|
||||
CPTableColumnIsHiddenkey = @"CPTableColumnIsHiddenKey";
|
||||
CPTableColumnIsHiddenKey = @"CPTableColumnIsHiddenKey",
|
||||
CPSortDescriptorPrototypeKey = @"CPSortDescriptorPrototypeKey",
|
||||
CPTableColumnIsEditableKey = @"CPTableColumnIsEditableKey";
|
||||
|
||||
@implementation CPTableColumn (CPCoding)
|
||||
|
||||
@@ -491,9 +488,10 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
|
||||
[self setDataView:[aCoder decodeObjectForKey:CPTableColumnDataViewKey]];
|
||||
[self setHeaderView:[aCoder decodeObjectForKey:CPTableColumnHeaderViewKey]];
|
||||
|
||||
_resizingMask = [aCoder decodeBoolForKey:CPTableColumnResizingMaskKey];
|
||||
_isHidden = [aCoder decodeBoolForKey:CPTableColumnIsHiddenkey];
|
||||
|
||||
_resizingMask = [aCoder decodeIntForKey:CPTableColumnResizingMaskKey];
|
||||
_isHidden = [aCoder decodeBoolForKey:CPTableColumnIsHiddenKey];
|
||||
_isEditable = [aCoder decodeBoolForKey:CPTableColumnIsEditableKey];
|
||||
|
||||
_sortDescriptorPrototype = [aCoder decodeObjectForKey:CPSortDescriptorPrototypeKey];
|
||||
}
|
||||
|
||||
@@ -512,8 +510,9 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
|
||||
[aCoder encodeObject:_dataView forKey:CPTableColumnDataViewKey];
|
||||
|
||||
[aCoder encodeObject:_resizingMask forKey:CPTableColumnResizingMaskKey];
|
||||
[aCoder encodeBool:_isHidden forKey:CPTableColumnIsHiddenkey];
|
||||
|
||||
[aCoder encodeBool:_isHidden forKey:CPTableColumnIsHiddenKey];
|
||||
[aCoder encodeBool:_isEditable forKey:CPTableColumnIsEditableKey];
|
||||
|
||||
[aCoder encodeObject:_sortDescriptorPrototype forKey:CPSortDescriptorPrototypeKey];
|
||||
}
|
||||
|
||||
|
||||
@@ -23,53 +23,60 @@
|
||||
@import "CPTableColumn.j"
|
||||
@import "CPTableView.j"
|
||||
@import "CPView.j"
|
||||
|
||||
|
||||
#include "CoreGraphics/CGGeometry.h"
|
||||
|
||||
@implementation _CPTableColumnHeaderView : CPView
|
||||
{
|
||||
_CPImageAndTextView _textField;
|
||||
}
|
||||
|
||||
+ (CPString)themeClass
|
||||
{
|
||||
return @"columnHeader";
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[[CPNull null], [CPNull null], CGInsetMakeZero(), [CPNull null], [CPNull null], [CPNull null], CGSizeMakeZero()]
|
||||
forKeys:[@"background-color", @"text-alignment", @"text-inset", @"text-color", @"text-font", @"text-shadow-color", @"text-shadow-offset"]];
|
||||
}
|
||||
|
||||
- (void)initWithFrame:(CGRect)frame
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
if (self)
|
||||
{
|
||||
[self _init];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)_init
|
||||
{
|
||||
_textField = [[_CPImageAndTextView alloc] initWithFrame:
|
||||
CGRectMake(5.0, 0.0, CGRectGetWidth([self bounds]) - 10.0, CGRectGetHeight([self bounds]))];
|
||||
|
||||
_textField = [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
|
||||
[_textField setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
|
||||
|
||||
[_textField setLineBreakMode:CPLineBreakByTruncatingTail];
|
||||
[_textField setTextColor:[CPColor colorWithRed:51.0 / 255.0 green:51.0 / 255.0 blue:51.0 / 255.0 alpha:1.0]];
|
||||
[_textField setFont:[CPFont boldSystemFontOfSize:12.0]];
|
||||
[_textField setAlignment:CPLeftTextAlignment];
|
||||
[_textField setVerticalAlignment:CPCenterVerticalTextAlignment];
|
||||
[_textField setTextShadowColor:[CPColor whiteColor]];
|
||||
[_textField setTextShadowOffset:CGSizeMake(0,1)];
|
||||
|
||||
[self addSubview:_textField];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
var themeState = [self themeState];
|
||||
[self setBackgroundColor:[self currentValueForThemeAttribute:@"background-color"]];
|
||||
|
||||
if(themeState & CPThemeStateSelected && themeState & CPThemeStateHighlighted)
|
||||
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-highlighted-pressed.png", CGSizeMake(1.0, 23.0))]];
|
||||
else if (themeState & CPThemeStateSelected)
|
||||
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-highlighted.png", CGSizeMake(1.0, 23.0))]];
|
||||
else if (themeState & CPThemeStateHighlighted)
|
||||
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-pressed.png", CGSizeMake(1.0, 23.0))]];
|
||||
else
|
||||
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview.png", CGSizeMake(1.0, 23.0))]];
|
||||
var inset = [self currentValueForThemeAttribute:@"text-inset"],
|
||||
bounds = [self bounds];
|
||||
|
||||
[_textField setFrame:_CGRectMake(inset.right, inset.top, bounds.size.width - inset.right - inset.left, bounds.size.height - inset.top - inset.bottom)];
|
||||
[_textField setTextColor:[self currentValueForThemeAttribute:@"text-color"]];
|
||||
[_textField setFont:[self currentValueForThemeAttribute:@"text-font"]];
|
||||
[_textField setTextShadowColor:[self currentValueForThemeAttribute:@"text-shadow-color"]];
|
||||
[_textField setTextShadowOffset:[self currentValueForThemeAttribute:@"text-shadow-offset"]];
|
||||
[_textField setAlignment:[self currentValueForThemeAttribute:@"text-alignment"]];
|
||||
}
|
||||
|
||||
- (void)setStringValue:(CPString)string
|
||||
@@ -97,11 +104,6 @@
|
||||
[_textField setFont:aFont];
|
||||
}
|
||||
|
||||
- (void)setValue:(id)aValue forThemeAttribute:(id)aKey
|
||||
{
|
||||
[_textField setValue:aValue forThemeAttribute:aKey];
|
||||
}
|
||||
|
||||
- (void)_setIndicatorImage:(CPImage)anImage
|
||||
{
|
||||
if (anImage)
|
||||
@@ -149,34 +151,47 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
|
||||
@implementation CPTableHeaderView : CPView
|
||||
{
|
||||
CPPoint _mouseDownLocation;
|
||||
CPPoint _previousTrackingLocation;
|
||||
CGPoint _mouseDownLocation;
|
||||
CGPoint _previousTrackingLocation;
|
||||
int _activeColumn;
|
||||
int _pressedColumn;
|
||||
|
||||
BOOL _isResizing;
|
||||
BOOL _isDragging;
|
||||
BOOL _isTrackingColumn;
|
||||
BOOL _drawsColumnLines;
|
||||
|
||||
float _columnOldWidth;
|
||||
|
||||
CPTableView _tableView @accessors(property=tableView);
|
||||
}
|
||||
|
||||
+ (CPString)themeClass
|
||||
{
|
||||
return @"tableHeaderRow";
|
||||
}
|
||||
|
||||
+ (id)themeAttributes
|
||||
{
|
||||
return [CPDictionary dictionaryWithObjects:[[CPNull null], [CPColor grayColor]]
|
||||
forKeys:[@"background-color", @"divider-color"]];
|
||||
}
|
||||
|
||||
- (void)_init
|
||||
{
|
||||
_mouseDownLocation = CPPointMakeZero();
|
||||
_previousTrackingLocation = CPPointMakeZero();
|
||||
_mouseDownLocation = _CGPointMakeZero();
|
||||
_previousTrackingLocation = _CGPointMakeZero();
|
||||
_activeColumn = -1;
|
||||
_pressedColumn = -1;
|
||||
|
||||
_isResizing = NO;
|
||||
_isDragging = NO;
|
||||
_isTrackingColumn = NO;
|
||||
_drawsColumnLines = YES;
|
||||
|
||||
_columnOldWidth = 0.0;
|
||||
|
||||
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview.png", CGSizeMake(1.0, 23.0))]];
|
||||
[self setBackgroundColor:[self currentValueForThemeAttribute:@"background-color"]];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)aFrame
|
||||
@@ -199,23 +214,33 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
var headerRect = [self bounds],
|
||||
columnRect = [_tableView rectOfColumn:aColumnIndex];
|
||||
|
||||
headerRect.origin.x = CPRectGetMinX(columnRect);
|
||||
headerRect.size.width = CPRectGetWidth(columnRect);
|
||||
headerRect.origin.x = _CGRectGetMinX(columnRect);
|
||||
headerRect.size.width = _CGRectGetWidth(columnRect);
|
||||
|
||||
return headerRect;
|
||||
}
|
||||
|
||||
- (void)setDrawsColumnLines:(BOOL)aFlag
|
||||
{
|
||||
_drawsColumnLines = aFlag;
|
||||
}
|
||||
|
||||
- (BOOL)drawsColumnLines
|
||||
{
|
||||
return _drawsColumnLines;
|
||||
}
|
||||
|
||||
- (CGRect)_cursorRectForColumn:(int)column
|
||||
{
|
||||
if (column == -1 || !([_tableView._tableColumns[column] resizingMask] & CPTableColumnUserResizingMask))
|
||||
return CGRectMakeZero();
|
||||
return _CGRectMakeZero();
|
||||
|
||||
var rect = [self headerRectOfColumn:column];
|
||||
|
||||
rect.origin.x = CGRectGetMaxX(rect) - 5;
|
||||
rect.origin.x = _CGRectGetMaxX(rect) - 5;
|
||||
rect.size.width = 20;
|
||||
|
||||
return rect;
|
||||
return rect;
|
||||
}
|
||||
|
||||
- (void)_setPressedColumn:(CPInteger)column
|
||||
@@ -224,7 +249,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
{
|
||||
var headerView = [_tableView._tableColumns[_pressedColumn] headerView];
|
||||
[headerView unsetThemeState:CPThemeStateHighlighted];
|
||||
}
|
||||
}
|
||||
|
||||
if (column != -1)
|
||||
{
|
||||
@@ -249,7 +274,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
currentLocation.x -= 5.0;
|
||||
|
||||
var columnIndex = [self columnAtPoint:currentLocation],
|
||||
shouldResize = [self shouldResizeTableColumn:columnIndex at:CPPointMake(currentLocation.x + 5.0, currentLocation.y)];
|
||||
shouldResize = [self shouldResizeTableColumn:columnIndex at:_CGPointMake(currentLocation.x + 5.0, currentLocation.y)];
|
||||
|
||||
if (type === CPLeftMouseUp)
|
||||
{
|
||||
@@ -293,7 +318,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
[self continueResizingTableColumn:_activeColumn at:currentLocation];
|
||||
else
|
||||
{
|
||||
if (_activeColumn === columnIndex && CPRectContainsPoint([self headerRectOfColumn:columnIndex], currentLocation))
|
||||
if (_activeColumn === columnIndex && _CGRectContainsPoint([self headerRectOfColumn:columnIndex], currentLocation))
|
||||
{
|
||||
if (_isTrackingColumn && _pressedColumn !== -1)
|
||||
{
|
||||
@@ -311,24 +336,24 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
[CPApp setTarget:self selector:@selector(trackMouse:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
|
||||
}
|
||||
|
||||
- (void)startTrackingTableColumn:(int)aColumnIndex at:(CPPoint)aPoint
|
||||
- (void)startTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
|
||||
{
|
||||
[self _setPressedColumn:aColumnIndex];
|
||||
}
|
||||
|
||||
- (BOOL)continueTrackingTableColumn:(int)aColumnIndex at:(CPPoint)aPoint
|
||||
- (BOOL)continueTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
|
||||
{
|
||||
if ([self _shouldDragTableColumn:aColumnIndex at:aPoint])
|
||||
{
|
||||
var columnRect = [self headerRectOfColumn:aColumnIndex],
|
||||
offset = CPPointMakeZero(),
|
||||
offset = _CGPointMakeZero(),
|
||||
view = [_tableView _dragViewForColumn:aColumnIndex event:[CPApp currentEvent] offset:offset],
|
||||
viewLocation = CPPointMakeZero();
|
||||
viewLocation = _CGPointMakeZero();
|
||||
|
||||
viewLocation.x = ( CPRectGetMinX(columnRect) + offset.x ) + ( aPoint.x - _mouseDownLocation.x );
|
||||
viewLocation.y = CPRectGetMinY(columnRect) + offset.y;
|
||||
viewLocation.x = ( _CGRectGetMinX(columnRect) + offset.x ) + ( aPoint.x - _mouseDownLocation.x );
|
||||
viewLocation.y = _CGRectGetMinY(columnRect) + offset.y;
|
||||
|
||||
[self dragView:view at:viewLocation offset:CPSizeMakeZero() event:[CPApp currentEvent]
|
||||
[self dragView:view at:viewLocation offset:_CGSizeMakeZero() event:[CPApp currentEvent]
|
||||
pasteboard:[CPPasteboard pasteboardWithName:CPDragPboard] source:self slideBack:YES];
|
||||
|
||||
return NO;
|
||||
@@ -337,24 +362,24 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)_shouldStopTrackingTableColumn:(int)aColumnIndex at:(CPPoint)aPoint
|
||||
- (BOOL)_shouldStopTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
|
||||
{
|
||||
return _isTrackingColumn && _activeColumn === aColumnIndex &&
|
||||
CPRectContainsPoint([self headerRectOfColumn:aColumnIndex], aPoint);
|
||||
return _isTrackingColumn && _activeColumn === aColumnIndex &&
|
||||
_CGRectContainsPoint([self headerRectOfColumn:aColumnIndex], aPoint);
|
||||
}
|
||||
|
||||
- (void)stopTrackingTableColumn:(int)aColumnIndex at:(CPPoint)aPoint
|
||||
- (void)stopTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
|
||||
{
|
||||
[self _setPressedColumn:CPNotFound];
|
||||
[self _updateResizeCursor:[CPApp currentEvent]];
|
||||
}
|
||||
|
||||
- (BOOL)_shouldDragTableColumn:(int)aColumnIndex at:(CPPoint)aPoint
|
||||
- (BOOL)_shouldDragTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
|
||||
{
|
||||
return [_tableView allowsColumnReordering] && ABS(aPoint.x - _mouseDownLocation.x) >= 10.0;
|
||||
}
|
||||
|
||||
- (CPRect)_headerRectOfLastVisibleColumn
|
||||
- (CGRect)_headerRectOfLastVisibleColumn
|
||||
{
|
||||
var tableColumns = [_tableView tableColumns],
|
||||
columnIndex = [tableColumns count];
|
||||
@@ -370,11 +395,11 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)_constrainDragView:(CPView)theDragView at:(CPPoint)aPoint
|
||||
- (void)_constrainDragView:(CPView)theDragView at:(CGPoint)aPoint
|
||||
{
|
||||
var tableColumns = [_tableView tableColumns],
|
||||
lastColumnRect = [self _headerRectOfLastVisibleColumn];
|
||||
activeColumnRect = [self headerRectOfColumn:_activeColumn];
|
||||
lastColumnRect = [self _headerRectOfLastVisibleColumn],
|
||||
activeColumnRect = [self headerRectOfColumn:_activeColumn],
|
||||
dragWindow = [theDragView window],
|
||||
frame = [dragWindow frame];
|
||||
|
||||
@@ -384,10 +409,10 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
frame.origin = [self convertPoint:frame.origin fromView:nil];
|
||||
|
||||
// This effectively clamps the value between the minimum and maximum
|
||||
frame.origin.x = MAX(0.0, MIN(CGRectGetMinX(frame), CGRectGetMaxX(lastColumnRect) - CGRectGetWidth(activeColumnRect)));
|
||||
frame.origin.x = MAX(0.0, MIN(_CGRectGetMinX(frame), _CGRectGetMaxX(lastColumnRect) - _CGRectGetWidth(activeColumnRect)));
|
||||
|
||||
// Make sure the column cannot move vertically
|
||||
frame.origin.y = CPRectGetMinY(lastColumnRect);
|
||||
frame.origin.y = _CGRectGetMinY(lastColumnRect);
|
||||
|
||||
// Convert the calculated origin back to the window coordinate system
|
||||
frame.origin = [self convertPoint:frame.origin toView:nil];
|
||||
@@ -402,21 +427,21 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
[_tableView moveColumn:aFromIndex toColumn:aToIndex];
|
||||
_activeColumn = aToIndex;
|
||||
_pressedColumn = _activeColumn;
|
||||
|
||||
[_tableView _setDraggedColumn:_activeColumn];
|
||||
}
|
||||
|
||||
- (void)draggedView:(CPView)aView beganAt:(CPPoint)aPoint
|
||||
- (void)draggedView:(CPView)aView beganAt:(CGPoint)aPoint
|
||||
{
|
||||
_isDragging = YES;
|
||||
|
||||
[[[[_tableView tableColumns] objectAtIndex:_activeColumn] headerView] setHidden:YES];
|
||||
[_tableView _setDraggedColumn:_activeColumn];
|
||||
var column = [[_tableView tableColumns] objectAtIndex:_activeColumn];
|
||||
|
||||
[[column headerView] setHidden:YES];
|
||||
[_tableView _setDraggedColumn:column];
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (void)draggedView:(CPView)aView movedTo:(CPPoint)aPoint
|
||||
- (void)draggedView:(CPView)aView movedTo:(CGPoint)aPoint
|
||||
{
|
||||
[self _constrainDragView:aView at:aPoint];
|
||||
|
||||
@@ -426,9 +451,9 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
var hoverPoint = CGPointCreateCopy(aPoint);
|
||||
|
||||
if (aPoint.x < _previousTrackingLocation.x)
|
||||
hoverPoint = CGPointMake(CGRectGetMinX(dragWindowFrame), CGRectGetMinY(dragWindowFrame));
|
||||
hoverPoint = _CGPointMake(_CGRectGetMinX(dragWindowFrame), _CGRectGetMinY(dragWindowFrame));
|
||||
else if (aPoint.x > _previousTrackingLocation.x)
|
||||
hoverPoint = CGPointMake(CGRectGetMaxX(dragWindowFrame), CGRectGetMinY(dragWindowFrame));
|
||||
hoverPoint = _CGPointMake(_CGRectGetMaxX(dragWindowFrame), _CGRectGetMinY(dragWindowFrame));
|
||||
|
||||
// Convert the hover point from the global coordinate system to windows' coordinate system
|
||||
hoverPoint = [[self window] convertGlobalToBase:hoverPoint];
|
||||
@@ -440,7 +465,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
if (hoveredColumn !== -1)
|
||||
{
|
||||
var columnRect = [self headerRectOfColumn:hoveredColumn],
|
||||
columnCenterPoint = [self convertPoint:CGPointMake(CGRectGetMidX(columnRect), CGRectGetMidY(columnRect)) fromView:self];
|
||||
columnCenterPoint = [self convertPoint:CGPointMake(_CGRectGetMidX(columnRect), _CGRectGetMidY(columnRect)) fromView:self];
|
||||
if (hoveredColumn < _activeColumn && hoverPoint.x < columnCenterPoint.x)
|
||||
[self _moveColumn:_activeColumn toColumn:hoveredColumn];
|
||||
else if (hoveredColumn > _activeColumn && hoverPoint.x > columnCenterPoint.x)
|
||||
@@ -455,14 +480,14 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
_isDragging = NO;
|
||||
_isTrackingColumn = NO; // We need to do this explicitly because the mouse up section of trackMouse is never reached
|
||||
|
||||
[_tableView _setDraggedColumn:-1];
|
||||
[_tableView _setDraggedColumn:nil];
|
||||
[[[[_tableView tableColumns] objectAtIndex:_activeColumn] headerView] setHidden:NO];
|
||||
[self stopTrackingTableColumn:_activeColumn at:aLocation];
|
||||
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (BOOL)shouldResizeTableColumn:(int)aColumnIndex at:(CPPoint)aPoint
|
||||
- (BOOL)shouldResizeTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
|
||||
{
|
||||
if (_isResizing)
|
||||
return YES;
|
||||
@@ -470,10 +495,10 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
if (_isTrackingColumn)
|
||||
return NO;
|
||||
|
||||
return [_tableView allowsColumnResizing] && CPRectContainsPoint([self _cursorRectForColumn:aColumnIndex], aPoint);
|
||||
return [_tableView allowsColumnResizing] && _CGRectContainsPoint([self _cursorRectForColumn:aColumnIndex], aPoint);
|
||||
}
|
||||
|
||||
- (void)startResizingTableColumn:(int)aColumnIndex at:(CPPoint)aPoint
|
||||
- (void)startResizingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
|
||||
{
|
||||
_isResizing = YES;
|
||||
|
||||
@@ -483,7 +508,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
[_tableView setDisableAutomaticResizing:YES];
|
||||
}
|
||||
|
||||
- (void)continueResizingTableColumn:(int)aColumnIndex at:(CPPoint)aPoint
|
||||
- (void)continueResizingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
|
||||
{
|
||||
var tableColumn = [[_tableView tableColumns] objectAtIndex:aColumnIndex],
|
||||
newWidth = [tableColumn width] + aPoint.x - _previousTrackingLocation.x;
|
||||
@@ -503,7 +528,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
}
|
||||
}
|
||||
|
||||
- (void)stopResizingTableColumn:(int)aColumnIndex at:(CPPoint)aPoint
|
||||
- (void)stopResizingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
|
||||
{
|
||||
var tableColumn = [[_tableView tableColumns] objectAtIndex:aColumnIndex];
|
||||
[tableColumn _postDidResizeNotificationWithOldWidth:_columnOldWidth];
|
||||
@@ -522,11 +547,11 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
return;
|
||||
}
|
||||
|
||||
var mouseLocation = [self convertPoint:[theEvent locationInWindow] fromView:nil],
|
||||
var mouseLocation = [self convertPoint:[theEvent locationInWindow] fromView:nil],
|
||||
mouseOverLocation = CGPointMake(mouseLocation.x - 5, mouseLocation.y),
|
||||
overColumn = [self columnAtPoint:mouseOverLocation];
|
||||
|
||||
if (overColumn >= 0 && CGRectContainsPoint([self _cursorRectForColumn:overColumn], mouseLocation))
|
||||
if (overColumn >= 0 && _CGRectContainsPoint([self _cursorRectForColumn:overColumn], mouseLocation))
|
||||
{
|
||||
var tableColumn = [[_tableView tableColumns] objectAtIndex:overColumn],
|
||||
width = [tableColumn width];
|
||||
@@ -543,7 +568,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
}
|
||||
|
||||
- (void)mouseEntered:(CPEvent)theEvent
|
||||
{
|
||||
{
|
||||
[self _updateResizeCursor:theEvent];
|
||||
}
|
||||
|
||||
@@ -561,16 +586,16 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
var tableColumns = [_tableView tableColumns],
|
||||
count = [tableColumns count];
|
||||
count = [tableColumns count];
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var column = [tableColumns objectAtIndex:i],
|
||||
headerView = [column headerView];
|
||||
|
||||
var frame = [self headerRectOfColumn:i];
|
||||
frame.size.height -= 0.5;
|
||||
if (i > 0)
|
||||
if (i > 0)
|
||||
{
|
||||
frame.origin.x += 0.5;
|
||||
frame.size.width -= 1;
|
||||
@@ -581,11 +606,13 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
if([headerView superview] != self)
|
||||
[self addSubview:headerView];
|
||||
}
|
||||
|
||||
[self setBackgroundColor:[self currentValueForThemeAttribute:@"background-color"]];
|
||||
}
|
||||
|
||||
- (void)drawRect:(CGRect)aRect
|
||||
{
|
||||
if (!_tableView)
|
||||
if (!_tableView || ![self drawsColumnLines])
|
||||
return;
|
||||
|
||||
var context = [[CPGraphicsContext currentContext] graphicsPort],
|
||||
@@ -597,7 +624,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
exposedRange = CPMakeRange(firstIndex, [exposedTableColumns lastIndex] - firstIndex + 1);
|
||||
|
||||
CGContextSetLineWidth(context, 1);
|
||||
CGContextSetStrokeColor(context, [_tableView gridColor]);
|
||||
CGContextSetStrokeColor(context, [self currentValueForThemeAttribute:@"divider-color"]);
|
||||
|
||||
[exposedColumnIndexes getIndexes:columnsArray maxCount:-1 inIndexRange:exposedRange];
|
||||
|
||||
@@ -612,25 +639,26 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
|
||||
var columnIndex = columnsArray[columnArrayIndex],
|
||||
columnToStroke = [self headerRectOfColumn:columnIndex];
|
||||
|
||||
columnMaxX = CGRectGetMaxX(columnToStroke);
|
||||
columnMaxX = _CGRectGetMaxX(columnToStroke);
|
||||
|
||||
CGContextMoveToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(CGRectGetMinY(columnToStroke)));
|
||||
CGContextAddLineToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(CGRectGetMaxY(columnToStroke)));
|
||||
CGContextMoveToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(_CGRectGetMinY(columnToStroke)));
|
||||
CGContextAddLineToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(_CGRectGetMaxY(columnToStroke)));
|
||||
}
|
||||
|
||||
CGContextClosePath(context);
|
||||
CGContextStrokePath(context);
|
||||
|
||||
if (_isDragging)
|
||||
/*if (_isDragging)
|
||||
{
|
||||
CGContextSetFillColor(context, [CPColor grayColor]);
|
||||
CGContextFillRect(context, [self headerRectOfColumn:_activeColumn])
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey";
|
||||
var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey",
|
||||
CPTableHeaderViewDrawsColumnLines = @"CPTableHeaderViewDrawsColumnLines";
|
||||
|
||||
@implementation CPTableHeaderView (CPCoding)
|
||||
|
||||
@@ -640,6 +668,7 @@ var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey";
|
||||
{
|
||||
[self _init];
|
||||
_tableView = [aCoder decodeObjectForKey:CPTableHeaderViewTableViewKey];
|
||||
_drawsColumnLines = [aCoder decodeBoolForKey:CPTableHeaderViewDrawsColumnLines];
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -649,6 +678,7 @@ var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey";
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
[aCoder encodeObject:_tableView forKey:CPTableHeaderViewTableViewKey];
|
||||
[aCoder encodeBool:_drawsColumnLines forKey:CPTableHeaderViewDrawsColumnLines];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -22,19 +22,11 @@
|
||||
|
||||
@import "CPView.j"
|
||||
|
||||
CPTabCharacter = "\u0009";
|
||||
CPFormFeedCharacter = "\u000c";
|
||||
CPNewlineCharacter = "\u000a";
|
||||
CPCarriageReturnCharacter = "\u000d";
|
||||
CPEnterCharacter = "\u0003";
|
||||
CPBackspaceCharacter = "\u0008";
|
||||
CPTabCharacter = "\u0009";
|
||||
CPNewlineCharacter = "\u000a";
|
||||
CPFormFeedCharacter = "\u000c";
|
||||
CPCarriageReturnCharacter = "\u000d";
|
||||
CPBackTabCharacter = "\u0019";
|
||||
CPDeleteCharacter = "\u007f";
|
||||
|
||||
@implementation CPText : CPView
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ var CPTextFieldDOMInputElement = nil,
|
||||
CPTextFieldCachedSelectStartFunction = nil,
|
||||
CPTextFieldCachedDragFunction = nil,
|
||||
CPTextFieldBlurFunction = nil;
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
var CPSecureTextFieldCharacter = "\u2022";
|
||||
@@ -82,13 +82,13 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
BOOL _isSecure;
|
||||
|
||||
BOOL _drawsBackground;
|
||||
|
||||
|
||||
CPColor _textFieldBackgroundColor;
|
||||
|
||||
|
||||
id _placeholderString;
|
||||
|
||||
|
||||
id _delegate;
|
||||
|
||||
|
||||
CPString _textDidChangeValue;
|
||||
|
||||
// NS-style Display Properties
|
||||
@@ -199,7 +199,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
}
|
||||
|
||||
CPTextFieldHandleBlur = function(anEvent)
|
||||
{
|
||||
{
|
||||
CPTextFieldInputOwner = nil;
|
||||
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
@@ -207,10 +207,10 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
//FIXME make this not onblur
|
||||
CPTextFieldDOMInputElement.onblur = CPTextFieldBlurFunction;
|
||||
|
||||
|
||||
CPTextFieldDOMStandardInputElement = CPTextFieldDOMInputElement;
|
||||
}
|
||||
|
||||
|
||||
if (CPFeatureIsCompatible(CPInputTypeCanBeChangedFeature))
|
||||
{
|
||||
if ([self isSecure])
|
||||
@@ -237,14 +237,14 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
CPTextFieldDOMPasswordInputElement.onblur = CPTextFieldBlurFunction;
|
||||
}
|
||||
|
||||
|
||||
CPTextFieldDOMInputElement = CPTextFieldDOMPasswordInputElement;
|
||||
}
|
||||
else
|
||||
{
|
||||
CPTextFieldDOMInputElement = CPTextFieldDOMStandardInputElement;
|
||||
}
|
||||
|
||||
|
||||
return CPTextFieldDOMInputElement;
|
||||
}
|
||||
#endif
|
||||
@@ -262,18 +262,29 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
[self setValue:CPLeftTextAlignment forThemeAttribute:@"alignment"];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark Controlling Editability and Selectability
|
||||
|
||||
/*!
|
||||
Sets whether or not the receiver text field can be edited
|
||||
/*!
|
||||
Sets whether or not the receiver text field can be edited. If NO, any
|
||||
ongoing edit is ended.
|
||||
*/
|
||||
- (void)setEditable:(BOOL)shouldBeEditable
|
||||
{
|
||||
if (_isEditable === shouldBeEditable)
|
||||
return;
|
||||
|
||||
_isEditable = shouldBeEditable;
|
||||
|
||||
if(shouldBeEditable)
|
||||
_isSelectable = YES;
|
||||
|
||||
// We only allow first responder status if the field is editable and enabled.
|
||||
if (!shouldBeEditable && [[self window] firstResponder] === self)
|
||||
[[self window] makeFirstResponder:nil];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -284,6 +295,19 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
return _isEditable;
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets whether the field reacts to events. If NO, any ongoing edit is
|
||||
ended.
|
||||
*/
|
||||
- (void)setEnabled:(BOOL)shouldBeEnabled
|
||||
{
|
||||
[super setEnabled:shouldBeEnabled];
|
||||
|
||||
// We only allow first responder status if the field is editable and enabled.
|
||||
if (!shouldBeEnabled && [[self window] firstResponder] === self)
|
||||
[[self window] makeFirstResponder:nil];
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets whether the field's text is selectable by the user.
|
||||
@param aFlag \c YES makes the text selectable
|
||||
@@ -346,7 +370,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
- (void)setBezelStyle:(CPTextFieldBezelStyle)aBezelStyle
|
||||
{
|
||||
var shouldBeRounded = aBezelStyle === CPTextFieldRoundedBezel;
|
||||
|
||||
|
||||
if (shouldBeRounded)
|
||||
[self setThemeState:CPTextFieldStateRounded];
|
||||
else
|
||||
@@ -392,9 +416,9 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
{
|
||||
if (_drawsBackground == shouldDrawBackground)
|
||||
return;
|
||||
|
||||
|
||||
_drawsBackground = shouldDrawBackground;
|
||||
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
@@ -415,9 +439,9 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
{
|
||||
if (_textFieldBackgroundColor == aColor)
|
||||
return;
|
||||
|
||||
|
||||
_textFieldBackgroundColor = aColor;
|
||||
|
||||
|
||||
[self setNeedsLayout];
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
@@ -480,24 +504,24 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
_DOMElement.appendChild(element);
|
||||
|
||||
window.setTimeout(function()
|
||||
{
|
||||
window.setTimeout(function()
|
||||
{
|
||||
element.focus();
|
||||
[self textDidFocus:[CPNotification notificationWithName:CPTextFieldDidFocusNotification object:self userInfo:nil]];
|
||||
CPTextFieldInputOwner = self;
|
||||
}, 0.0);
|
||||
|
||||
|
||||
element.value = [self stringValue];
|
||||
|
||||
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
|
||||
|
||||
|
||||
CPTextFieldInputIsActive = YES;
|
||||
|
||||
if (document.attachEvent)
|
||||
{
|
||||
CPTextFieldCachedSelectStartFunction = [[self window] platformWindow]._DOMBodyElement.onselectstart;
|
||||
CPTextFieldCachedDragFunction = [[self window] platformWindow]._DOMBodyElement.ondrag;
|
||||
|
||||
|
||||
[[self window] platformWindow]._DOMBodyElement.ondrag = function () {};
|
||||
[[self window] platformWindow]._DOMBodyElement.onselectstart = function () {};
|
||||
}
|
||||
@@ -523,10 +547,10 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
CPTextFieldInputResigning = YES;
|
||||
element.blur();
|
||||
|
||||
|
||||
if (!CPTextFieldInputDidBlur)
|
||||
CPTextFieldBlurFunction();
|
||||
|
||||
|
||||
CPTextFieldInputDidBlur = NO;
|
||||
CPTextFieldInputResigning = NO;
|
||||
|
||||
@@ -536,14 +560,14 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
CPTextFieldInputIsActive = NO;
|
||||
|
||||
if (document.attachEvent)
|
||||
{
|
||||
{
|
||||
[[self window] platformWindow]._DOMBodyElement.ondrag = CPTextFieldCachedDragFunction;
|
||||
[[self window] platformWindow]._DOMBodyElement.onselectstart = CPTextFieldCachedSelectStartFunction;
|
||||
|
||||
CPTextFieldCachedSelectStartFunction = nil;
|
||||
CPTextFieldCachedDragFunction = nil;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
//post CPControlTextDidEndEditingNotification
|
||||
@@ -580,7 +604,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
{
|
||||
CPTextFieldCachedSelectStartFunction = [[self window] platformWindow]._DOMBodyElement.onselectstart;
|
||||
CPTextFieldCachedDragFunction = [[self window] platformWindow]._DOMBodyElement.ondrag;
|
||||
|
||||
|
||||
[[self window] platformWindow]._DOMBodyElement.ondrag = function () {};
|
||||
[[self window] platformWindow]._DOMBodyElement.onselectstart = function () {};
|
||||
}
|
||||
@@ -599,7 +623,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
if (document.attachEvent)
|
||||
{
|
||||
[[self window] platformWindow]._DOMBodyElement.ondrag = CPTextFieldCachedDragFunction;
|
||||
[[self window] platformWindow]._DOMBodyElement.onselectstart = CPTextFieldCachedSelectStartFunction;
|
||||
[[self window] platformWindow]._DOMBodyElement.onselectstart = CPTextFieldCachedSelectStartFunction;
|
||||
|
||||
CPTextFieldCachedSelectStartFunction = nil
|
||||
CPTextFieldCachedDragFunction = nil;
|
||||
@@ -709,7 +733,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
- (void)setObjectValue:(id)aValue
|
||||
{
|
||||
[super setObjectValue:aValue];
|
||||
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
|
||||
if (CPTextFieldInputOwner === self || [[self window] firstResponder] === self)
|
||||
@@ -737,7 +761,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
{
|
||||
if (_placeholderString === aStringValue)
|
||||
return;
|
||||
|
||||
|
||||
_placeholderString = aStringValue;
|
||||
|
||||
// Only update things if we need to show the placeholder
|
||||
@@ -758,17 +782,17 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
/*!
|
||||
Size to fit has two behavior, depending on if the receiver is an editable text field or not.
|
||||
|
||||
For non-editable text fields (typically, a label), sizeToFit will change the frame of the
|
||||
|
||||
For non-editable text fields (typically, a label), sizeToFit will change the frame of the
|
||||
receiver to perfectly fit the current text in stringValue in the current font, and respecting
|
||||
the current theme values for content-inset, min-size, and max-size.
|
||||
|
||||
For editable text fields, sizeToFit will ONLY change the HEIGHT of the text field. It will not
|
||||
change the width of the text field. You can use setFrameSize: with the current height to set the
|
||||
width, and you can get the size of a string with [CPString sizeWithFont:].
|
||||
|
||||
|
||||
For editable text fields, sizeToFit will ONLY change the HEIGHT of the text field. It will not
|
||||
change the width of the text field. You can use setFrameSize: with the current height to set the
|
||||
width, and you can get the size of a string with [CPString sizeWithFont:].
|
||||
|
||||
The logic behind this decision is that most of the time you do not know what content will be placed
|
||||
in an editable text field, so you want to just choose a fixed width and leave it at that size.
|
||||
in an editable text field, so you want to just choose a fixed width and leave it at that size.
|
||||
However, since you don't know how tall it needs to be if you change the font, sizeToFit will still be
|
||||
useful for making the textfield an appropriate height.
|
||||
*/
|
||||
@@ -802,16 +826,13 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
{
|
||||
#if PLATFORM(DOM)
|
||||
var element = [self _inputElement];
|
||||
|
||||
|
||||
if (([self isEditable] || [self isSelectable]))
|
||||
{
|
||||
if ([[self window] firstResponder] === self)
|
||||
window.setTimeout(function() { element.select(); }, 0);
|
||||
else
|
||||
{
|
||||
[[self window] makeFirstResponder:self];
|
||||
else if ([self window] !== nil && [[self window] makeFirstResponder:self])
|
||||
window.setTimeout(function() {[self selectText:sender];}, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -870,14 +891,14 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
return CPMakeRange(0, 0);
|
||||
|
||||
// we wrap this in try catch because firefox will throw an exception in certain instances
|
||||
try
|
||||
try
|
||||
{
|
||||
var inputElement = [self _inputElement],
|
||||
selectionStart = inputElement.selectionStart,
|
||||
selectionEnd = inputElement.selectionEnd;
|
||||
|
||||
if ([selectionStart isKindOfClass:CPNumber])
|
||||
return CPMakeRange(selectionStart, selectionEnd - selectionStart);
|
||||
return CPMakeRange(selectionStart, selectionEnd - selectionStart);
|
||||
|
||||
// browsers which don't support selectionStart/selectionEnd (aka IE).
|
||||
var theDocument = inputElement.ownerDocument || inputElement.document,
|
||||
@@ -889,8 +910,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
range.setEndPoint('EndToStart', selectionRange);
|
||||
return CPMakeRange(range.text.length, selectionRange.text.length);
|
||||
}
|
||||
}
|
||||
catch (e)
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
// fall through to the return
|
||||
}
|
||||
@@ -905,7 +926,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
var inputElement = [self _inputElement];
|
||||
|
||||
try
|
||||
try
|
||||
{
|
||||
if ([inputElement.selectionStart isKindOfClass:CPNumber])
|
||||
{
|
||||
@@ -918,7 +939,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
var theDocument = inputElement.ownerDocument || inputElement.document,
|
||||
existingRange = theDocument.selection.createRange(),
|
||||
range = inputElement.createTextRange();
|
||||
|
||||
|
||||
if (range.inRange(existingRange))
|
||||
{
|
||||
range.collapse(true);
|
||||
@@ -953,7 +974,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
- (void)setDelegate:(id)aDelegate
|
||||
{
|
||||
var defaultCenter = [CPNotificationCenter defaultCenter];
|
||||
|
||||
|
||||
//unsubscribe the existing delegate if it exists
|
||||
if (_delegate)
|
||||
{
|
||||
@@ -963,24 +984,24 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
[defaultCenter removeObserver:_delegate name:CPTextFieldDidFocusNotification object:self];
|
||||
[defaultCenter removeObserver:_delegate name:CPTextFieldDidBlurNotification object:self];
|
||||
}
|
||||
|
||||
|
||||
_delegate = aDelegate;
|
||||
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(controlTextDidBeginEditing:)])
|
||||
[defaultCenter
|
||||
addObserver:_delegate
|
||||
selector:@selector(controlTextDidBeginEditing:)
|
||||
name:CPControlTextDidBeginEditingNotification
|
||||
object:self];
|
||||
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(controlTextDidChange:)])
|
||||
[defaultCenter
|
||||
addObserver:_delegate
|
||||
selector:@selector(controlTextDidChange:)
|
||||
name:CPControlTextDidChangeNotification
|
||||
object:self];
|
||||
|
||||
|
||||
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(controlTextDidEndEditing:)])
|
||||
[defaultCenter
|
||||
addObserver:_delegate
|
||||
@@ -1011,15 +1032,15 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
- (CGRect)contentRectForBounds:(CGRect)bounds
|
||||
{
|
||||
var contentInset = [self currentValueForThemeAttribute:@"content-inset"];
|
||||
|
||||
|
||||
if (!contentInset)
|
||||
return bounds;
|
||||
|
||||
|
||||
bounds.origin.x += contentInset.left;
|
||||
bounds.origin.y += contentInset.top;
|
||||
bounds.size.width -= contentInset.left + contentInset.right;
|
||||
bounds.size.height -= contentInset.top + contentInset.bottom;
|
||||
|
||||
|
||||
return bounds;
|
||||
}
|
||||
|
||||
@@ -1029,12 +1050,12 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
|
||||
if (_CGInsetIsEmpty(bezelInset))
|
||||
return bounds;
|
||||
|
||||
|
||||
bounds.origin.x += bezelInset.left;
|
||||
bounds.origin.y += bezelInset.top;
|
||||
bounds.size.width -= bezelInset.left + bezelInset.right;
|
||||
bounds.size.height -= bezelInset.top + bezelInset.bottom;
|
||||
|
||||
|
||||
return bounds;
|
||||
}
|
||||
|
||||
@@ -1042,10 +1063,10 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
{
|
||||
if (aName === "bezel-view")
|
||||
return [self bezelRectForBounds:[self bounds]];
|
||||
|
||||
|
||||
else if (aName === "content-view")
|
||||
return [self contentRectForBounds:[self bounds]];
|
||||
|
||||
|
||||
return [super rectForEphemeralSubviewNamed:aName];
|
||||
}
|
||||
|
||||
@@ -1056,19 +1077,19 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
|
||||
[view setHitTests:NO];
|
||||
|
||||
|
||||
return view;
|
||||
}
|
||||
else
|
||||
{
|
||||
var view = [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
|
||||
//[view setImagePosition:CPNoImage];
|
||||
|
||||
|
||||
[view setHitTests:NO];
|
||||
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
|
||||
return [super createEphemeralSubviewNamed:aName];
|
||||
}
|
||||
|
||||
@@ -1077,10 +1098,10 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
var bezelView = [self layoutEphemeralSubviewNamed:@"bezel-view"
|
||||
positioned:CPWindowBelow
|
||||
relativeToEphemeralSubviewNamed:@"content-view"];
|
||||
|
||||
|
||||
if (bezelView)
|
||||
[bezelView setBackgroundColor:[self currentValueForThemeAttribute:@"bezel-color"]];
|
||||
|
||||
|
||||
var contentView = [self layoutEphemeralSubviewNamed:@"content-view"
|
||||
positioned:CPWindowAbove
|
||||
relativeToEphemeralSubviewNamed:@"bezel-view"];
|
||||
@@ -1090,7 +1111,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
|
||||
[contentView setHidden:[self hasThemeState:CPThemeStateEditing]];
|
||||
|
||||
var string = "";
|
||||
|
||||
|
||||
if ([self hasThemeState:CPTextFieldStatePlaceholder])
|
||||
string = [self placeholderString];
|
||||
else
|
||||
@@ -1148,6 +1169,7 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
|
||||
CPTextFieldBezelStyleKey = "CPTextFieldBezelStyleKey",
|
||||
CPTextFieldDrawsBackgroundKey = "CPTextFieldDrawsBackgroundKey",
|
||||
CPTextFieldLineBreakModeKey = "CPTextFieldLineBreakModeKey",
|
||||
CPTextFieldAlignmentKey = "CPTextFieldAlignmentKey",
|
||||
CPTextFieldBackgroundColorKey = "CPTextFieldBackgroundColorKey",
|
||||
CPTextFieldPlaceholderStringKey = "CPTextFieldPlaceholderStringKey";
|
||||
|
||||
@@ -1161,7 +1183,7 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
[self setEditable:[aCoder decodeBoolForKey:CPTextFieldIsEditableKey]];
|
||||
@@ -1171,9 +1193,12 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
|
||||
|
||||
[self setTextFieldBackgroundColor:[aCoder decodeObjectForKey:CPTextFieldBackgroundColorKey]];
|
||||
|
||||
[self setLineBreakMode:[aCoder decodeIntForKey:CPTextFieldLineBreakModeKey]];
|
||||
[self setAlignment:[aCoder decodeIntForKey:CPTextFieldAlignmentKey]];
|
||||
|
||||
[self setPlaceholderString:[aCoder decodeObjectForKey:CPTextFieldPlaceholderStringKey]];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -1184,14 +1209,17 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
|
||||
- (void)encodeWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
[super encodeWithCoder:aCoder];
|
||||
|
||||
|
||||
[aCoder encodeBool:_isEditable forKey:CPTextFieldIsEditableKey];
|
||||
[aCoder encodeBool:_isSelectable forKey:CPTextFieldIsSelectableKey];
|
||||
|
||||
|
||||
[aCoder encodeBool:_drawsBackground forKey:CPTextFieldDrawsBackgroundKey];
|
||||
|
||||
|
||||
[aCoder encodeObject:_textFieldBackgroundColor forKey:CPTextFieldBackgroundColorKey];
|
||||
|
||||
|
||||
[aCoder encodeInt:[self lineBreakMode] forKey:CPTextFieldLineBreakModeKey];
|
||||
[aCoder encodeInt:[self alignment] forKey:CPTextFieldAlignmentKey];
|
||||
|
||||
[aCoder encodeObject:_placeholderString forKey:CPTextFieldPlaceholderStringKey];
|
||||
}
|
||||
|
||||
|
||||
@@ -24,8 +24,9 @@
|
||||
@import <Foundation/CPString.j>
|
||||
@import <Foundation/CPKeyedUnarchiver.j>
|
||||
|
||||
var CPThemesByName = { },
|
||||
CPThemeDefaultTheme = nil;
|
||||
var CPThemesByName = { },
|
||||
CPThemeDefaultTheme = nil,
|
||||
CPThemeDefaultHudTheme = nil;
|
||||
|
||||
|
||||
/*!
|
||||
@@ -48,6 +49,27 @@ var CPThemesByName = { },
|
||||
return CPThemeDefaultTheme;
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the default HUD theme. If set to nil, the default described in defaultHudTheme
|
||||
will be used.
|
||||
*/
|
||||
+ (void)setDefaultHudTheme:(CPTheme)aTheme
|
||||
{
|
||||
CPThemeDefaultHudTheme = aTheme;
|
||||
}
|
||||
|
||||
/*!
|
||||
The default HUD theme is (sometimes) used for windows with the CPHUDBackgroundWindowMask
|
||||
style mask. The default is theme with the name of the default theme with -HUD appended
|
||||
at the end.
|
||||
*/
|
||||
+ (CPTheme)defaultHudTheme
|
||||
{
|
||||
if (!CPThemeDefaultHudTheme)
|
||||
CPThemeDefaultHudTheme = [CPTheme themeNamed:[[self defaultTheme] name] + "-HUD"];
|
||||
return CPThemeDefaultHudTheme;
|
||||
}
|
||||
|
||||
+ (CPTheme)themeNamed:(CPString)aName
|
||||
{
|
||||
return CPThemesByName[aName];
|
||||
@@ -73,9 +95,105 @@ var CPThemesByName = { },
|
||||
return _name;
|
||||
}
|
||||
|
||||
- (_CPThemeAttribute)_attributeWithName:(CPString)aName forClass:(CPString)aClass
|
||||
/*!
|
||||
Returns an array of names of themed classes defined in this theme, as found in its
|
||||
ThemeDescriptors.j file.
|
||||
|
||||
NOTE: The names are not class names (such as "CPButton"), but the names returned
|
||||
by the class' +themeClass method. For example, the name for CPCheckBox is "check-box",
|
||||
as defined in CPCheckBox::themeClass.
|
||||
*/
|
||||
- (CPArray)classNames
|
||||
{
|
||||
var attributes = [_attributes objectForKey:aClass];
|
||||
return [_attributes allKeys];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a dictionary of all theme attributes defined for the given class, as found in the
|
||||
theme's ThemeDescriptors.j file. The keys of the dictionary are attribute names, and the values
|
||||
are instances of _CPThemeAttribute.
|
||||
|
||||
For a description of valid values for \c aClass, see \ref attributeNamesForClass:.
|
||||
|
||||
@param aClass The themed class whose attributes you want to retrieve
|
||||
@return A dictionary of attributes or nil
|
||||
*/
|
||||
- (CPDictionary)attributesForClass:(id)aClass
|
||||
{
|
||||
if (!aClass)
|
||||
return nil;
|
||||
|
||||
var className = nil;
|
||||
|
||||
if ([aClass isKindOfClass:[CPString class]])
|
||||
{
|
||||
// See if it is a class name
|
||||
var theClass = CPClassFromString(aClass);
|
||||
|
||||
if (theClass)
|
||||
aClass = theClass;
|
||||
else
|
||||
className = aClass;
|
||||
}
|
||||
|
||||
if (!className)
|
||||
{
|
||||
if ([aClass isKindOfClass:[CPView class]])
|
||||
{
|
||||
if ([aClass respondsToSelector:@selector(themeClass)])
|
||||
className = [aClass themeClass];
|
||||
else
|
||||
return nil;
|
||||
}
|
||||
else
|
||||
[CPException raise:CPInvalidArgumentException reason:@"aClass must be a class object or a string."];
|
||||
}
|
||||
|
||||
return [_attributes objectForKey:className];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns an array of names of all theme attributes defined for the given class, as found in the
|
||||
theme's ThemeDescriptors.j file.
|
||||
|
||||
The \c aClass parameter can be one of the following:
|
||||
|
||||
- A class instance, for example the result of [CPCheckBox class]. The class must be a subclass
|
||||
of CPView.
|
||||
- A class name, for example "CPCheckBox".
|
||||
- A themed class name, for example "check-box".
|
||||
|
||||
If \c aClass does not refer to a themed class in this theme, nil is returned.
|
||||
|
||||
@param aClass The themed class whose attributes you want to retrieve
|
||||
@return An array of attribute names or nil
|
||||
*/
|
||||
- (CPDictionary)attributeNamesForClass:(id)aClass
|
||||
{
|
||||
var attributes = [self attributesForClass:aClass];
|
||||
|
||||
if (attributes)
|
||||
return [attributes allKeys];
|
||||
else
|
||||
return [CPArray array];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a theme attribute defined for the given class, as found in the
|
||||
theme's ThemeDescriptors.j file.
|
||||
|
||||
\c aName should be the attribute name as you would pass to the method
|
||||
CPView::valueForThemeAttribute:.
|
||||
|
||||
For a description of valid values for \c aClass, see \ref attributeNamesForClass:.
|
||||
|
||||
@param aName The name of the attribute you want to retrieve
|
||||
@param aClass The themed class in which to look for the attribute
|
||||
@return An instance of _CPThemeAttribute or nil
|
||||
*/
|
||||
- (_CPThemeAttribute)attributeWithName:(CPString)aName forClass:(id)aClass
|
||||
{
|
||||
var attributes = [self attributesForClass:aClass];
|
||||
|
||||
if (!attributes)
|
||||
return nil;
|
||||
@@ -83,6 +201,47 @@ var CPThemesByName = { },
|
||||
return [attributes objectForKey:aName];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the value for a theme attribute in its normal state, as defined for the given class
|
||||
in the theme's ThemeDescriptors.j file.
|
||||
|
||||
\c aName should be the attribute name as you would pass to the method
|
||||
CPView::valueForThemeAttribute:.
|
||||
|
||||
For a description of valid values for \c aClass, see \ref attributeNamesForClass:.
|
||||
|
||||
@param aName The name of the attribute whose value you want to retrieve
|
||||
@param aClass The themed class in which to look for the attribute
|
||||
@return A value or nil
|
||||
*/
|
||||
- (id)valueForAttributeWithName:(CPString)aName forClass:(id)aClass
|
||||
{
|
||||
return [self valueForAttributeWithName:aName inState:CPThemeStateNormal forClass:aClass];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the value for a theme attribute in a given state, as defined for the given class
|
||||
in the theme's ThemeDescriptors.j file. This is the equivalent of the method
|
||||
CPView::valueForThemeAttribute:inState:, but retrieves the value from the theme definition as
|
||||
opposed to a single view's current theme state.
|
||||
|
||||
For a description of valid values for \c aClass, see \ref attributeNamesForClass:.
|
||||
|
||||
@param aName The name of the attribute whose value you want to retrieve
|
||||
@param aState The state qualifier for the attribute
|
||||
@param aClass The themed class in which to look for the attribute
|
||||
@return A value or nil
|
||||
*/
|
||||
- (id)valueForAttributeWithName:(CPString)aName inState:(CPThemeState)aState forClass:(id)aClass
|
||||
{
|
||||
var attribute = [self attributeWithName:aName forClass:aClass];
|
||||
|
||||
if (!attribute)
|
||||
return nil;
|
||||
|
||||
return [attribute valueForState:aState];
|
||||
}
|
||||
|
||||
- (void)takeThemeFromObject:(id)anObject
|
||||
{
|
||||
var attributes = [anObject _themeAttributeDictionary],
|
||||
@@ -242,7 +401,8 @@ CPThemeStateNormal = CPThemeStates["normal"] = 0;
|
||||
CPThemeStateDisabled = CPThemeState("disabled");
|
||||
CPThemeStateHighlighted = CPThemeState("highlighted");
|
||||
CPThemeStateSelected = CPThemeState("selected");
|
||||
CPThemeStateSelectedDataView = CPThemeState("selectedDataView");
|
||||
CPThemeStateTableDataView = CPThemeState("tableDataView");
|
||||
CPThemeStateSelectedDataView = CPThemeStateSelectedTableDataView = CPThemeState("selectedTableDataView");
|
||||
CPThemeStateBezeled = CPThemeState("bezeled");
|
||||
CPThemeStateBordered = CPThemeState("bordered");
|
||||
CPThemeStateEditable = CPThemeState("editable");
|
||||
@@ -255,10 +415,10 @@ CPThemeStateCircular = CPThemeState("circular");
|
||||
{
|
||||
CPString _name;
|
||||
id _defaultValue;
|
||||
CPDictionary _values;
|
||||
CPDictionary _values @accessors(readonly, getter=values);
|
||||
|
||||
JSObject _cache;
|
||||
CPThemeAttribute _parentAttribute;
|
||||
_CPThemeAttribute _parentAttribute;
|
||||
}
|
||||
|
||||
- (id)initWithName:(CPString)aName defaultValue:(id)aDefaultValue
|
||||
@@ -379,7 +539,7 @@ CPThemeStateCircular = CPThemeState("circular");
|
||||
return value;
|
||||
}
|
||||
|
||||
- (void)setParentAttribute:(CPThemeAttribute)anAttribute
|
||||
- (void)setParentAttribute:(_CPThemeAttribute)anAttribute
|
||||
{
|
||||
if (_parentAttribute === anAttribute)
|
||||
return;
|
||||
@@ -388,7 +548,7 @@ CPThemeStateCircular = CPThemeState("circular");
|
||||
_parentAttribute = anAttribute;
|
||||
}
|
||||
|
||||
- (CPThemeAttribute)attributeMergedWithAttribute:(_CPThemeAttribute)anAttribute
|
||||
- (_CPThemeAttribute)attributeMergedWithAttribute:(_CPThemeAttribute)anAttribute
|
||||
{
|
||||
var mergedAttribute = [[_CPThemeAttribute alloc] initWithName:_name defaultValue:_defaultValue];
|
||||
|
||||
@@ -473,15 +633,15 @@ CPThemeStateCircular = CPThemeState("circular");
|
||||
|
||||
@end
|
||||
|
||||
var cachedNumberOfOnes = [ 0 /*000000*/, 1 /*000001*/, 1 /*000010*/, 2 /*000011*/, 1 /*000100*/, 2 /*000101*/, 2 /*000110*/,
|
||||
3 /*000111*/, 1 /*001000*/, 2 /*001001*/, 2 /*001010*/, 3 /*001011*/, 2 /*001100*/, 3 /*001101*/,
|
||||
3 /*001110*/, 4 /*001111*/, 1 /*010000*/, 2 /*010001*/, 2 /*010010*/, 3 /*010011*/, 2 /*010100*/,
|
||||
3 /*010101*/, 3 /*010110*/, 4 /*010111*/, 2 /*011000*/, 3 /*011001*/, 3 /*011010*/, 4 /*011011*/,
|
||||
3 /*011100*/, 4 /*011101*/, 4 /*011110*/, 5 /*011111*/, 1 /*100000*/, 2 /*100001*/, 2 /*100010*/,
|
||||
3 /*100011*/, 2 /*100100*/, 3 /*100101*/, 3 /*100110*/, 4 /*100111*/, 2 /*101000*/, 3 /*101001*/,
|
||||
3 /*101010*/, 4 /*101011*/, 3 /*101100*/, 4 /*101101*/, 4 /*101110*/, 5 /*101111*/, 2 /*110000*/,
|
||||
3 /*110001*/, 3 /*110010*/, 4 /*110011*/, 3 /*110100*/, 4 /*110101*/, 4 /*110110*/, 5 /*110111*/,
|
||||
3 /*111000*/, 4 /*111001*/, 4 /*111010*/, 5 /*111011*/, 4 /*111100*/, 5 /*111101*/, 5 /*111110*/,
|
||||
var cachedNumberOfOnes = [ 0 /*000000*/, 1 /*000001*/, 1 /*000010*/, 2 /*000011*/, 1 /*000100*/, 2 /*000101*/, 2 /*000110*/,
|
||||
3 /*000111*/, 1 /*001000*/, 2 /*001001*/, 2 /*001010*/, 3 /*001011*/, 2 /*001100*/, 3 /*001101*/,
|
||||
3 /*001110*/, 4 /*001111*/, 1 /*010000*/, 2 /*010001*/, 2 /*010010*/, 3 /*010011*/, 2 /*010100*/,
|
||||
3 /*010101*/, 3 /*010110*/, 4 /*010111*/, 2 /*011000*/, 3 /*011001*/, 3 /*011010*/, 4 /*011011*/,
|
||||
3 /*011100*/, 4 /*011101*/, 4 /*011110*/, 5 /*011111*/, 1 /*100000*/, 2 /*100001*/, 2 /*100010*/,
|
||||
3 /*100011*/, 2 /*100100*/, 3 /*100101*/, 3 /*100110*/, 4 /*100111*/, 2 /*101000*/, 3 /*101001*/,
|
||||
3 /*101010*/, 4 /*101011*/, 3 /*101100*/, 4 /*101101*/, 4 /*101110*/, 5 /*101111*/, 2 /*110000*/,
|
||||
3 /*110001*/, 3 /*110010*/, 4 /*110011*/, 3 /*110100*/, 4 /*110101*/, 4 /*110110*/, 5 /*110111*/,
|
||||
3 /*111000*/, 4 /*111001*/, 4 /*111010*/, 5 /*111011*/, 4 /*111100*/, 5 /*111101*/, 5 /*111110*/,
|
||||
6 /*111111*/ ];
|
||||
|
||||
var numberOfOnes = function(aNumber)
|
||||
@@ -552,7 +712,7 @@ function CPThemeAttributeDecode(aCoder, anAttributeName, aDefaultValue, aTheme,
|
||||
}
|
||||
|
||||
if (aTheme && aClass)
|
||||
[attribute setParentAttribute:[aTheme _attributeWithName:anAttributeName forClass:aClass]];
|
||||
[attribute setParentAttribute:[aTheme attributeWithName:anAttributeName forClass:aClass]];
|
||||
|
||||
return attribute;
|
||||
}
|
||||
@@ -586,4 +746,4 @@ for (i = 0;i < Math.pow(2,6);++i)
|
||||
}
|
||||
print(str+']');
|
||||
|
||||
*/
|
||||
*/
|
||||
|
||||
@@ -33,37 +33,60 @@
|
||||
@implementation CPThemeBlend : CPObject
|
||||
{
|
||||
CPBundle _bundle;
|
||||
CPArray _themes @accessors(readonly, getter=themes);
|
||||
CPArray _themes;
|
||||
id _loadDelegate;
|
||||
}
|
||||
|
||||
- (id)initWithContentsOfURL:(CPURL)aURL
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
_bundle = [[CPBundle alloc] initWithPath:aURL];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns an array of names of the keyed theme archives that make up this blend.
|
||||
Each item in the array will have the extension ".keyedtheme".
|
||||
*/
|
||||
- (CPArray)themes
|
||||
{
|
||||
return _themes;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns an array of names of the themes that make up this blend.
|
||||
*/
|
||||
- (CPArray)themeNames
|
||||
{
|
||||
var names = [];
|
||||
|
||||
for (var i = 0; i < _themes.length; ++i)
|
||||
names.push(_themes[i].substring(0, _themes[i].indexOf(".keyedtheme")));
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
- (void)loadWithDelegate:(id)aDelegate
|
||||
{
|
||||
_loadDelegate = aDelegate;
|
||||
|
||||
|
||||
[_bundle loadWithDelegate:self];
|
||||
}
|
||||
|
||||
- (void)bundleDidFinishLoading:(CPBundle)aBundle
|
||||
{
|
||||
var themes = [_bundle objectForInfoDictionaryKey:@"CPKeyedThemes"],
|
||||
count = themes.length;
|
||||
_themes = [_bundle objectForInfoDictionaryKey:@"CPKeyedThemes"];
|
||||
|
||||
var count = _themes.length;
|
||||
|
||||
while (count--)
|
||||
{
|
||||
var path = [aBundle pathForResource:themes[count]],
|
||||
var path = [aBundle pathForResource:_themes[count]],
|
||||
unarchiver = [[_CPThemeKeyedUnarchiver alloc]
|
||||
initForReadingWithData:[[CPURL URLWithString:path] staticResourceData]
|
||||
bundle:_bundle];
|
||||
|
||||
@@ -563,6 +563,7 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
||||
|
||||
[_additionalItemsButton setImagePosition:CPImageOnly];
|
||||
[[_additionalItemsButton menu] setShowsStateColumn:NO];
|
||||
[[_additionalItemsButton menu] setAutoenablesItems:NO];
|
||||
|
||||
[_additionalItemsButton setAlternateImage:_CPToolbarViewExtraItemsAlternateImage];
|
||||
}
|
||||
@@ -793,14 +794,13 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
|
||||
|
||||
hasNonSeparatorItem = YES;
|
||||
|
||||
[_additionalItemsButton addItemWithTitle:[item label]];
|
||||
|
||||
var menuItem = [_additionalItemsButton itemArray][index + 1];
|
||||
var menuItem = [[CPMenuItem alloc] initWithTitle:[item label] action:[item action] keyEquivalent:nil];
|
||||
|
||||
[menuItem setImage:[item image]];
|
||||
|
||||
[menuItem setTarget:[item target]];
|
||||
[menuItem setAction:[item action]];
|
||||
[menuItem setEnabled:[item isEnabled]];
|
||||
|
||||
[_additionalItemsButton addItem:menuItem];
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1055,6 +1055,8 @@ var TOP_MARGIN = 5.0,
|
||||
[_imageView setAlphaValue:0.5];
|
||||
[_labelField setAlphaValue:0.5];
|
||||
}
|
||||
|
||||
[_toolbar tile];
|
||||
}
|
||||
|
||||
- (CPColor)FIXME_labelColor
|
||||
|
||||
@@ -79,9 +79,9 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut";
|
||||
while (animationIndex--)
|
||||
{
|
||||
var dictionary = [_viewAnimations objectAtIndex:animationIndex],
|
||||
view = [self _targetView:dictionary]
|
||||
startFrame = [self _startFrame:dictionary]
|
||||
endFrame = [self _endFrame:dictionary]
|
||||
view = [self _targetView:dictionary],
|
||||
startFrame = [self _startFrame:dictionary],
|
||||
endFrame = [self _endFrame:dictionary],
|
||||
differenceFrame = _CGRectMakeZero();
|
||||
|
||||
differenceFrame.origin.x = endFrame.origin.x - startFrame.origin.x;
|
||||
|
||||
@@ -47,7 +47,8 @@ var CPViewControllerCachedCibs;
|
||||
*/
|
||||
@implementation CPViewController : CPResponder
|
||||
{
|
||||
CPView _view;
|
||||
CPView _view @accessors(property=view);
|
||||
BOOL _isLoading;
|
||||
|
||||
id _representedObject @accessors(property=representedObject);
|
||||
CPString _title @accessors(property=title);
|
||||
@@ -99,6 +100,8 @@ var CPViewControllerCachedCibs;
|
||||
_cibName = aCibNameOrNil;
|
||||
_cibBundle = aCibBundleOrNil || [CPBundle mainBundle];
|
||||
_cibExternalNameTable = anExternalNameTable || [CPDictionary dictionaryWithObject:self forKey:CPCibOwner];
|
||||
|
||||
_isLoading = NO;
|
||||
}
|
||||
|
||||
return self;
|
||||
@@ -111,16 +114,16 @@ var CPViewControllerCachedCibs;
|
||||
If you create your views manually, you must override this method and use it to create your view and assign it to the view property.
|
||||
The default implementation for programmatic views is to create a plain view. You can invoke super to utilize this view.
|
||||
|
||||
If you use Interface Builder to create your views and initialize the view controllerŃthat is, you initialize the view using the
|
||||
initWithCibName:bundle: methodŃthen you must not override this method. The consequences risk shattering the space-time continuum.
|
||||
If you use Interface Builder to create your views, you initialize the view using the
|
||||
initWithCibName:bundle: method then you must not override this method. The consequences risk shattering the space-time continuum.
|
||||
|
||||
Note: The cib loading system is currently asynchronous.
|
||||
Note: The cib loading system is currently synchronous.
|
||||
*/
|
||||
- (void)loadView
|
||||
{
|
||||
if (_view)
|
||||
return;
|
||||
|
||||
|
||||
// check if a cib is already cached for the current _cibName
|
||||
var cib = [CPViewControllerCachedCibs objectForKey:_cibName];
|
||||
|
||||
@@ -143,6 +146,8 @@ var CPViewControllerCachedCibs;
|
||||
{
|
||||
if (!_view)
|
||||
{
|
||||
_isLoading = YES;
|
||||
|
||||
var cibOwner = [_cibExternalNameTable objectForKey:CPCibOwner];
|
||||
|
||||
if ([cibOwner respondsToSelector:@selector(viewControllerWillLoadCib:)])
|
||||
@@ -163,6 +168,7 @@ var CPViewControllerCachedCibs;
|
||||
if ([cibOwner respondsToSelector:@selector(viewControllerDidLoadCib:)])
|
||||
[cibOwner viewControllerDidLoadCib:self];
|
||||
|
||||
_isLoading = NO;
|
||||
[self viewDidLoad];
|
||||
}
|
||||
|
||||
@@ -173,7 +179,7 @@ var CPViewControllerCachedCibs;
|
||||
/*!
|
||||
This method is called after the view controller has loaded its associated views into memory.
|
||||
This method is called regardless of whether the views were stored in a nib file or created programmatically in the loadView method.
|
||||
This method is most commonly used to perform additional initialization steps on views that are loaded from nib files.
|
||||
This method is most commonly used to perform additional initialization steps on views that are loaded from cib files.
|
||||
*/
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
@@ -189,7 +195,13 @@ var CPViewControllerCachedCibs;
|
||||
*/
|
||||
- (void)setView:(CPView)aView
|
||||
{
|
||||
var viewWasLoaded = !_view;
|
||||
|
||||
_view = aView;
|
||||
|
||||
// Make sure the viewDidLoad method is called if the view is set directly
|
||||
if (!_isLoading && viewWasLoaded)
|
||||
[self viewDidLoad];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -50,23 +50,23 @@ CPWebViewScrollNative = 2;
|
||||
{
|
||||
CPScrollView _scrollView;
|
||||
CPView _frameView;
|
||||
|
||||
|
||||
IFrame _iframe;
|
||||
CPString _mainFrameURL;
|
||||
CPArray _backwardStack;
|
||||
CPArray _forwardStack;
|
||||
|
||||
|
||||
BOOL _ignoreLoadStart;
|
||||
BOOL _ignoreLoadEnd;
|
||||
|
||||
|
||||
id _downloadDelegate;
|
||||
id _frameLoadDelegate;
|
||||
id _policyDelegate;
|
||||
id _resourceLoadDelegate;
|
||||
id _UIDelegate;
|
||||
|
||||
|
||||
CPWebScriptObject _wso;
|
||||
|
||||
|
||||
CPString _url;
|
||||
CPString _html;
|
||||
|
||||
@@ -95,10 +95,10 @@ CPWebViewScrollNative = 2;
|
||||
_backwardStack = [];
|
||||
_forwardStack = [];
|
||||
_scrollMode = CPWebViewScrollNative;
|
||||
|
||||
|
||||
[self _initDOMWithFrame:aFrame];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -106,52 +106,52 @@ CPWebViewScrollNative = 2;
|
||||
{
|
||||
_ignoreLoadStart = YES;
|
||||
_ignoreLoadEnd = YES;
|
||||
|
||||
|
||||
_iframe = document.createElement("iframe");
|
||||
_iframe.name = "iframe_" + Math.floor(Math.random()*10000);
|
||||
_iframe.style.width = "100%";
|
||||
_iframe.style.height = "100%";
|
||||
_iframe.style.borderWidth = "0px";
|
||||
_iframe.frameBorder = "0";
|
||||
|
||||
|
||||
[self setDrawsBackground:YES];
|
||||
|
||||
|
||||
_loadCallback = function() {
|
||||
// HACK: this block handles the case where we don't know about loads initiated by the user clicking a link
|
||||
if (!_ignoreLoadStart)
|
||||
{
|
||||
// post the start load notification
|
||||
[self _startedLoading];
|
||||
|
||||
|
||||
if (_mainFrameURL)
|
||||
[_backwardStack addObject:_mainFrameURL];
|
||||
|
||||
|
||||
// FIXME: this doesn't actually get the right URL for different domains. Not possible due to browser security restrictions.
|
||||
_mainFrameURL = _iframe.src;
|
||||
_mainFrameURL = _iframe.src;
|
||||
|
||||
|
||||
// clear the forward
|
||||
[_forwardStack removeAllObjects];
|
||||
}
|
||||
else
|
||||
_ignoreLoadStart = NO;
|
||||
|
||||
|
||||
if (!_ignoreLoadEnd)
|
||||
{
|
||||
[self _finishedLoading];
|
||||
}
|
||||
else
|
||||
_ignoreLoadEnd = NO;
|
||||
|
||||
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
}
|
||||
|
||||
|
||||
if (_iframe.addEventListener)
|
||||
_iframe.addEventListener("load", _loadCallback, false);
|
||||
else if (_iframe.attachEvent)
|
||||
_iframe.attachEvent("onload", _loadCallback);
|
||||
|
||||
|
||||
|
||||
|
||||
_frameView = [[CPView alloc] initWithFrame:[self bounds]];
|
||||
[_frameView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
|
||||
|
||||
@@ -159,9 +159,9 @@ CPWebViewScrollNative = 2;
|
||||
[_scrollView setAutohidesScrollers:YES];
|
||||
[_scrollView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
|
||||
[_scrollView setDocumentView:_frameView];
|
||||
|
||||
|
||||
_frameView._DOMElement.appendChild(_iframe);
|
||||
|
||||
|
||||
[self _setScrollMode:_scrollMode];
|
||||
|
||||
[self addSubview:_scrollView];
|
||||
@@ -169,7 +169,7 @@ CPWebViewScrollNative = 2;
|
||||
|
||||
|
||||
- (void)setFrameSize:(CPSize)aSize
|
||||
{
|
||||
{
|
||||
[super setFrameSize:aSize];
|
||||
[self _resizeWebFrame];
|
||||
}
|
||||
@@ -211,7 +211,7 @@ CPWebViewScrollNative = 2;
|
||||
{
|
||||
var visibleRect = [_frameView visibleRect];
|
||||
[_frameView setFrameSize:CGSizeMake(CGRectGetMaxX(visibleRect), CGRectGetMaxY(visibleRect))];
|
||||
|
||||
|
||||
// try to get the document size so we can correctly set the frame
|
||||
var win = null;
|
||||
try { win = [self DOMWindow]; } catch (e) {}
|
||||
@@ -229,7 +229,7 @@ CPWebViewScrollNative = 2;
|
||||
else
|
||||
{
|
||||
CPLog.warn("using default size 800*1600");
|
||||
|
||||
|
||||
[_frameView setFrameSize:CGSizeMake(800, 1600)];
|
||||
}
|
||||
|
||||
@@ -242,7 +242,7 @@ CPWebViewScrollNative = 2;
|
||||
{
|
||||
if (_scrollMode == aScrollMode)
|
||||
return;
|
||||
|
||||
|
||||
[self _setScrollMode:aScrollMode];
|
||||
}
|
||||
|
||||
@@ -252,7 +252,7 @@ CPWebViewScrollNative = 2;
|
||||
_scrollMode = CPWebViewScrollNative;
|
||||
else
|
||||
_scrollMode = aScrollMode;
|
||||
|
||||
|
||||
_ignoreLoadStart = YES;
|
||||
_ignoreLoadEnd = YES;
|
||||
|
||||
@@ -263,16 +263,16 @@ CPWebViewScrollNative = 2;
|
||||
{
|
||||
[_scrollView setHasHorizontalScroller:YES];
|
||||
[_scrollView setHasVerticalScroller:YES];
|
||||
|
||||
|
||||
_iframe.setAttribute("scrolling", "no");
|
||||
}
|
||||
else
|
||||
{
|
||||
[_scrollView setHasHorizontalScroller:NO];
|
||||
[_scrollView setHasVerticalScroller:NO];
|
||||
|
||||
|
||||
_iframe.setAttribute("scrolling", "auto");
|
||||
|
||||
|
||||
[_frameView setFrameSize:[_scrollView bounds].size];
|
||||
}
|
||||
|
||||
@@ -293,13 +293,13 @@ CPWebViewScrollNative = 2;
|
||||
[_frameView setFrameSize:[_scrollView contentSize]];
|
||||
|
||||
[self _startedLoading];
|
||||
|
||||
|
||||
_ignoreLoadStart = YES;
|
||||
_ignoreLoadEnd = NO;
|
||||
|
||||
|
||||
_url = null;
|
||||
_html = aString;
|
||||
|
||||
|
||||
[self _load];
|
||||
}
|
||||
|
||||
@@ -308,13 +308,13 @@ CPWebViewScrollNative = 2;
|
||||
[self _setScrollMode:CPWebViewScrollNative];
|
||||
|
||||
[self _startedLoading];
|
||||
|
||||
|
||||
_ignoreLoadStart = YES;
|
||||
_ignoreLoadEnd = NO;
|
||||
|
||||
|
||||
_url = _mainFrameURL;
|
||||
_html = null;
|
||||
|
||||
|
||||
[self _load];
|
||||
}
|
||||
|
||||
@@ -335,12 +335,13 @@ CPWebViewScrollNative = 2;
|
||||
_loadHTMLStringTimer = nil;
|
||||
}
|
||||
|
||||
// need to give the browser a chance to reset iframe, otherwise we'll be document.write()-ing the previous document
|
||||
// need to give the browser a chance to reset iframe, otherwise we'll be document.write()-ing the previous document
|
||||
_loadHTMLStringTimer = window.setTimeout(function()
|
||||
{
|
||||
var win = [self DOMWindow];
|
||||
|
||||
win.document.write(_html);
|
||||
|
||||
if (win)
|
||||
win.document.write(_html);
|
||||
|
||||
window.setTimeout(_loadCallback, 1);
|
||||
}, 0);
|
||||
@@ -372,7 +373,7 @@ CPWebViewScrollNative = 2;
|
||||
}
|
||||
|
||||
- (void)setMainFrameURL:(CPString)URLString
|
||||
{
|
||||
{
|
||||
if (_mainFrameURL)
|
||||
[_backwardStack addObject:_mainFrameURL];
|
||||
_mainFrameURL = URLString;
|
||||
@@ -389,9 +390,9 @@ CPWebViewScrollNative = 2;
|
||||
[_forwardStack addObject:_mainFrameURL];
|
||||
_mainFrameURL = [_backwardStack lastObject];
|
||||
[_backwardStack removeLastObject];
|
||||
|
||||
|
||||
[self _loadMainFrameURL];
|
||||
|
||||
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
@@ -405,9 +406,9 @@ CPWebViewScrollNative = 2;
|
||||
[_backwardStack addObject:_mainFrameURL];
|
||||
_mainFrameURL = [_forwardStack lastObject];
|
||||
[_forwardStack removeLastObject];
|
||||
|
||||
|
||||
[self _loadMainFrameURL];
|
||||
|
||||
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
@@ -630,7 +631,7 @@ CPWebViewScrollNative = 2;
|
||||
- (id)initWithCoder:(CPCoder)aCoder
|
||||
{
|
||||
self = [super initWithCoder:aCoder];
|
||||
|
||||
|
||||
if (self)
|
||||
{
|
||||
// FIXME: encode/decode these?
|
||||
@@ -638,14 +639,14 @@ CPWebViewScrollNative = 2;
|
||||
_backwardStack = [];
|
||||
_forwardStack = [];
|
||||
_scrollMode = CPWebViewScrollNative;
|
||||
|
||||
|
||||
#if PLATFORM(DOM)
|
||||
[self _initDOMWithFrame:[self frame]];
|
||||
#endif
|
||||
|
||||
[self setBackgroundColor:[CPColor whiteColor]];
|
||||
}
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
@@ -200,6 +200,8 @@ var SHADOW_MARGIN_LEFT = 20.0,
|
||||
var CPWindowSaveImage = nil,
|
||||
CPWindowSavingImage = nil;
|
||||
|
||||
var CPWindowResizeTime = 0.2;
|
||||
|
||||
/*!
|
||||
@ingroup appkit
|
||||
@class CPWindow
|
||||
@@ -320,6 +322,8 @@ var CPWindowSaveImage = nil,
|
||||
CPDictionary _sheetContext;
|
||||
CPWindow _parentView;
|
||||
BOOL _isSheet;
|
||||
|
||||
_CPWindowFrameAnimation _frameAnimation;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -659,9 +663,10 @@ CPTexturedBackgroundWindowMask
|
||||
|
||||
if (shouldAnimate)
|
||||
{
|
||||
var animation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame];
|
||||
[_frameAnimation stopAnimation];
|
||||
_frameAnimation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame];
|
||||
|
||||
[animation startAnimation];
|
||||
[_frameAnimation startAnimation];
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1359,10 +1364,21 @@ CPTexturedBackgroundWindowMask
|
||||
*/
|
||||
- (void)center
|
||||
{
|
||||
if (_isFullPlatformWindow)
|
||||
return;
|
||||
|
||||
var size = [self frame].size,
|
||||
containerSize = [CPPlatform isBrowser] ? [_platformWindow contentBounds].size : [[self screen] visibleFrame].size;
|
||||
|
||||
[self setFrameOrigin:CGPointMake((containerSize.width - size.width) / 2.0, (containerSize.height - size.height) / 2.0)];
|
||||
var origin = CGPointMake((containerSize.width - size.width) / 2.0, (containerSize.height - size.height) / 2.0);
|
||||
|
||||
if (origin.x < 0.0)
|
||||
origin.x = 0.0;
|
||||
|
||||
if (origin.y < 0.0)
|
||||
origin.y = 0.0;
|
||||
|
||||
[self setFrameOrigin:origin];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -1376,8 +1392,18 @@ CPTexturedBackgroundWindowMask
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case CPFlagsChanged: return [[self firstResponder] flagsChanged:anEvent];
|
||||
|
||||
case CPKeyUp: return [[self firstResponder] keyUp:anEvent];
|
||||
case CPKeyDown: return [[self firstResponder] keyDown:anEvent];
|
||||
|
||||
case CPKeyDown: [[self firstResponder] keyDown:anEvent];
|
||||
|
||||
// Trigger the default button if needed
|
||||
if (![self disableKeyEquivalentForDefaultButton])
|
||||
if ([anEvent _triggersKeyEquivalent:[[self defaultButton] keyEquivalent] withModifierMask:[[self defaultButton] keyEquivalentModifierMask]])
|
||||
[[self defaultButton] performClick:self];
|
||||
|
||||
return;
|
||||
|
||||
case CPScrollWheel: return [[_windowView hitTest:point] scrollWheel:anEvent];
|
||||
|
||||
@@ -1600,7 +1626,7 @@ CPTexturedBackgroundWindowMask
|
||||
if (!pasteboardTypes)
|
||||
return;
|
||||
|
||||
[_inclusiveRegisteredDraggedTypes minusSet:pasteboardTypes]
|
||||
[_inclusiveRegisteredDraggedTypes minusSet:pasteboardTypes];
|
||||
|
||||
if ([_inclusiveRegisteredDraggedTypes count] === 0)
|
||||
_inclusiveRegisteredDraggedTypes = nil;
|
||||
@@ -1631,7 +1657,7 @@ CPTexturedBackgroundWindowMask
|
||||
return;
|
||||
|
||||
[self _noteUnregisteredDraggedTypes:_registeredDraggedTypes];
|
||||
[_registeredDraggedTypes addObjectsFromArray:pasteboardTypes]
|
||||
[_registeredDraggedTypes addObjectsFromArray:pasteboardTypes];
|
||||
[self _noteRegisteredDraggedTypes:_registeredDraggedTypes];
|
||||
|
||||
_registeredDraggedTypesArray = nil;
|
||||
@@ -1644,7 +1670,7 @@ CPTexturedBackgroundWindowMask
|
||||
- (CPArray)registeredDraggedTypes
|
||||
{
|
||||
if (!_registeredDraggedTypesArray)
|
||||
_registeredDraggedTypesArray = [_registeredDraggedTypes allObjects]
|
||||
_registeredDraggedTypesArray = [_registeredDraggedTypes allObjects];
|
||||
|
||||
return _registeredDraggedTypesArray;
|
||||
}
|
||||
@@ -1942,10 +1968,16 @@ CPTexturedBackgroundWindowMask
|
||||
else
|
||||
{
|
||||
var mainMenu = [CPApp mainMenu],
|
||||
menuWindow = mainMenu ? mainMenu._menuWindow : nil;
|
||||
menuBarClass = objj_getClass("_CPMenuBarWindow"),
|
||||
menuWindow;
|
||||
|
||||
for (var i = 0; i < windowCount; i++)
|
||||
{
|
||||
var currentWindow = allWindows[i];
|
||||
|
||||
if ([currentWindow isKindOfClass:menuBarClass])
|
||||
menuWindow = currentWindow;
|
||||
|
||||
if (currentWindow === self || currentWindow === menuWindow)
|
||||
continue;
|
||||
|
||||
@@ -1971,10 +2003,16 @@ CPTexturedBackgroundWindowMask
|
||||
else
|
||||
{
|
||||
var mainMenu = [CPApp mainMenu],
|
||||
menuWindow = mainMenu ? mainMenu._menuWindow : nil;
|
||||
menuBarClass = objj_getClass("_CPMenuBarWindow"),
|
||||
menuWindow;
|
||||
|
||||
for (var i = 0; i < windowCount; i++)
|
||||
{
|
||||
var currentWindow = allWindows[i];
|
||||
|
||||
if ([currentWindow isKindOfClass:menuBarClass])
|
||||
menuWindow = currentWindow;
|
||||
|
||||
if (currentWindow === self || currentWindow === menuWindow)
|
||||
continue;
|
||||
|
||||
@@ -2054,11 +2092,17 @@ CPTexturedBackgroundWindowMask
|
||||
|
||||
- (void)_setFrame:(CGRect)aFrame delegate:(id)delegate duration:(int)duration curve:(CPAnimationCurve)curve
|
||||
{
|
||||
var animation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame];
|
||||
[animation setDelegate:delegate];
|
||||
[animation setAnimationCurve:curve];
|
||||
[animation setDuration:duration];
|
||||
[animation startAnimation];
|
||||
[_frameAnimation stopAnimation];
|
||||
_frameAnimation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame];
|
||||
[_frameAnimation setDelegate:delegate];
|
||||
[_frameAnimation setAnimationCurve:curve];
|
||||
[_frameAnimation setDuration:duration];
|
||||
[_frameAnimation startAnimation];
|
||||
}
|
||||
|
||||
- (CPTimeInterval)animationResizeTime:(CGRect)newWindowFrame
|
||||
{
|
||||
return CPWindowResizeTime;
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
@@ -2109,7 +2153,7 @@ CPTexturedBackgroundWindowMask
|
||||
[aSheet setFrame:startFrame display:YES animate:NO];
|
||||
_sheetContext["opened"] = YES;
|
||||
|
||||
[aSheet _setFrame:endFrame delegate:self duration:0.2 curve:CPAnimationEaseOut];
|
||||
[aSheet _setFrame:endFrame delegate:self duration:[self animationResizeTime:endFrame] curve:CPAnimationEaseOut];
|
||||
|
||||
// Should run the main loop here until _isAnimating = FALSE
|
||||
[aSheet becomeKeyWindow];
|
||||
@@ -2130,7 +2174,7 @@ CPTexturedBackgroundWindowMask
|
||||
[self _setUpMasksForView:sheetContent];
|
||||
|
||||
_sheetContext["opened"] = NO;
|
||||
[sheet _setFrame:endFrame delegate:self duration:0.2 curve:CPAnimationEaseIn];
|
||||
[sheet _setFrame:endFrame delegate:self duration:[self animationResizeTime:endFrame] curve:CPAnimationEaseIn];
|
||||
}
|
||||
|
||||
/* @ignore */
|
||||
@@ -2159,13 +2203,15 @@ CPTexturedBackgroundWindowMask
|
||||
[self _restoreMasksForView:sheetContent];
|
||||
|
||||
var delegate = _sheetContext["modalDelegate"],
|
||||
endSelector = _sheetContext["endSelector"];
|
||||
|
||||
if (delegate != nil && endSelector != nil)
|
||||
objj_msgSend(delegate, endSelector, sheet, _sheetContext["returnCode"], _sheetContext["contextInfo"]);
|
||||
endSelector = _sheetContext["endSelector"],
|
||||
returnCode = _sheetContext["returnCode"],
|
||||
contextInfo = _sheetContext["contextInfo"];
|
||||
|
||||
_sheetContext = nil;
|
||||
sheet._parentView = nil;
|
||||
|
||||
if (delegate != nil && endSelector != nil)
|
||||
objj_msgSend(delegate, endSelector, sheet, returnCode, contextInfo);
|
||||
}
|
||||
|
||||
- (void)_setUpMasksForView:(CPView)aView
|
||||
@@ -2238,7 +2284,7 @@ CPTexturedBackgroundWindowMask
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)performKeyEquivalent:(CPEvent)anEvent
|
||||
- (BOOL)performKeyEquivalent:(CPEvent)anEvent
|
||||
{
|
||||
// FIXME: should we be starting at the root, in other words _windowView?
|
||||
// The evidence seems to point to no...
|
||||
@@ -2249,14 +2295,11 @@ CPTexturedBackgroundWindowMask
|
||||
{
|
||||
// It's not clear why we do performKeyEquivalent again here...
|
||||
// Perhaps to allow something to happen between sendEvent: and keyDown:?
|
||||
if (![anEvent _couldBeKeyEquivalent] || ![self performKeyEquivalent:anEvent])
|
||||
[self interpretKeyEvents:[anEvent]];
|
||||
}
|
||||
if ([anEvent _couldBeKeyEquivalent] && [self performKeyEquivalent:anEvent])
|
||||
return;
|
||||
|
||||
- (void)insertNewline:(id)sender
|
||||
{
|
||||
if (_defaultButton && _defaultButtonEnabled)
|
||||
[_defaultButton performClick:nil];
|
||||
// Interpret the key events
|
||||
[self interpretKeyEvents:[anEvent]];
|
||||
}
|
||||
|
||||
- (void)insertTab:(id)sender
|
||||
@@ -2369,11 +2412,16 @@ CPTexturedBackgroundWindowMask
|
||||
|
||||
- (void)setDefaultButton:(CPButton)aButton
|
||||
{
|
||||
[_defaultButton setDefaultButton:NO];
|
||||
if (_defaultButton === aButton)
|
||||
return;
|
||||
|
||||
if ([_defaultButton keyEquivalent] === CPCarriageReturnCharacter)
|
||||
[_defaultButton setKeyEquivalent:nil];
|
||||
|
||||
_defaultButton = aButton;
|
||||
|
||||
[_defaultButton setDefaultButton:YES];
|
||||
if ([_defaultButton keyEquivalent] !== CPCarriageReturnCharacter)
|
||||
[_defaultButton setKeyEquivalent:CPCarriageReturnCharacter];
|
||||
}
|
||||
|
||||
- (CPButton)defaultButton
|
||||
@@ -2634,7 +2682,7 @@ var interpolate = function(fromValue, toValue, progress)
|
||||
|
||||
- (id)initWithWindow:(CPWindow)aWindow targetFrame:(CGRect)aTargetFrame
|
||||
{
|
||||
self = [super initWithDuration:0.2 animationCurve:CPAnimationLinear];
|
||||
self = [super initWithDuration:[aWindow animationResizeTime:aTargetFrame] animationCurve:CPAnimationLinear];
|
||||
|
||||
if (self)
|
||||
{
|
||||
|
||||
@@ -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];
|
||||
|
||||
|
||||
@@ -133,7 +133,7 @@
|
||||
if (_window)
|
||||
return;
|
||||
|
||||
[[CPBundle bundleForClass:[_cibOwner class]] loadCibFile:[self windowCibPath] externalNameTable:[CPDictionary dictionaryWithObject:_cibOwner forKey:CPCibOwner]];
|
||||
[[CPBundle mainBundle] loadCibFile:[self windowCibPath] externalNameTable:[CPDictionary dictionaryWithObject:_cibOwner forKey:CPCibOwner]];
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -424,7 +424,7 @@
|
||||
if (_windowCibPath)
|
||||
return _windowCibPath;
|
||||
|
||||
return [[CPBundle bundleForClass:[_cibOwner class]] pathForResource:_windowCibName + @".cib"];
|
||||
return [[CPBundle mainBundle] pathForResource:_windowCibName + @".cib"];
|
||||
}
|
||||
|
||||
// Setting and Getting Window Attributes
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -69,6 +69,12 @@ _function(CGInsetMake(top, right, bottom, left))
|
||||
_function(CGInsetMakeZero())
|
||||
_function(CGInsetMakeCopy(anInset))
|
||||
_function(CGInsetIsEmpty(anInset))
|
||||
_function(CGInsetEqualToInset(lhsInset, rhsInset))
|
||||
|
||||
CGMinXEdge = 0;
|
||||
CGMinYEdge = 1;
|
||||
CGMaxXEdge = 2;
|
||||
CGMaxYEdge = 3;
|
||||
|
||||
CGRectNull = _CGRectMake(Infinity, Infinity, 0.0, 0.0);
|
||||
|
||||
@@ -77,6 +83,50 @@ CGRectNull = _CGRectMake(Infinity, Infinity, 0.0, 0.0);
|
||||
@{
|
||||
*/
|
||||
|
||||
/*!
|
||||
Creates two rectangles -- slice and rem -- from inRect, by dividing inRect
|
||||
with a line that's parallel to the side of inRect specified by edge.
|
||||
The size of slice is determined by amount, which specifies the distance from edge.
|
||||
|
||||
slice and rem must not be NULL, must not be the same object, and must not be the
|
||||
same object as inRect.
|
||||
|
||||
@group CGRect
|
||||
*/
|
||||
function CGRectDivide(inRect, slice, rem, amount, edge)
|
||||
{
|
||||
slice.origin = _CGPointMakeCopy(inRect.origin);
|
||||
slice.size = _CGSizeMakeCopy(inRect.size);
|
||||
rem.origin = _CGPointMakeCopy(inRect.origin);
|
||||
rem.size = _CGSizeMakeCopy(inRect.size);
|
||||
|
||||
switch (edge)
|
||||
{
|
||||
case CGMinXEdge:
|
||||
slice.size.width = amount;
|
||||
rem.origin.x += amount;
|
||||
rem.size.width -= amount;
|
||||
break;
|
||||
|
||||
case CGMaxXEdge:
|
||||
slice.origin.x = _CGRectGetMaxX(slice) - amount;
|
||||
slice.size.width = amount;
|
||||
rem.size.width -= amount;
|
||||
break;
|
||||
|
||||
case CGMinYEdge:
|
||||
slice.size.height = amount;
|
||||
rem.origin.y += amount;
|
||||
rem.size.height -= amount;
|
||||
break;
|
||||
|
||||
case CGMaxYEdge:
|
||||
slice.origin.y = _CGRectGetMaxY(slice) - amount;
|
||||
slice.size.height = amount;
|
||||
rem.size.height -= amount;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a \c BOOL indicating whether CGRect \c lhsRect
|
||||
contains CGRect \c rhsRect.
|
||||
@@ -88,7 +138,7 @@ CGRectNull = _CGRectMake(Infinity, Infinity, 0.0, 0.0);
|
||||
function CGRectContainsRect(lhsRect, rhsRect)
|
||||
{
|
||||
var union = CGRectUnion(lhsRect, rhsRect);
|
||||
|
||||
|
||||
return _CGRectEqualToRect(union, lhsRect);
|
||||
}
|
||||
|
||||
@@ -102,12 +152,12 @@ function CGRectContainsRect(lhsRect, rhsRect)
|
||||
function CGRectIntersectsRect(lhsRect, rhsRect)
|
||||
{
|
||||
var intersection = CGRectIntersection(lhsRect, rhsRect);
|
||||
|
||||
|
||||
return !_CGRectIsEmpty(intersection);
|
||||
}
|
||||
|
||||
/*!
|
||||
Makes the origin and size of a CGRect all integers. Specifically, by making
|
||||
Makes the origin and size of a CGRect all integers. Specifically, by making
|
||||
the southwest corner the origin (rounded down), and the northeast corner a CGSize (rounded up).
|
||||
@param aRect the rectangle to operate on
|
||||
@return CGRect the modified rectangle (same as the input)
|
||||
@@ -120,7 +170,7 @@ function CGRectIntegral(aRect)
|
||||
// Store these out separately, if not the GetMaxes will return incorrect values.
|
||||
var x = FLOOR(_CGRectGetMinX(aRect)),
|
||||
y = FLOOR(_CGRectGetMinY(aRect));
|
||||
|
||||
|
||||
aRect.size.width = CEIL(_CGRectGetMaxX(aRect)) - x;
|
||||
aRect.size.height = CEIL(_CGRectGetMaxY(aRect)) - y;
|
||||
|
||||
@@ -140,18 +190,18 @@ function CGRectIntegral(aRect)
|
||||
function CGRectIntersection(lhsRect, rhsRect)
|
||||
{
|
||||
var intersection = _CGRectMake(
|
||||
MAX(_CGRectGetMinX(lhsRect), _CGRectGetMinX(rhsRect)),
|
||||
MAX(_CGRectGetMinY(lhsRect), _CGRectGetMinY(rhsRect)),
|
||||
MAX(_CGRectGetMinX(lhsRect), _CGRectGetMinX(rhsRect)),
|
||||
MAX(_CGRectGetMinY(lhsRect), _CGRectGetMinY(rhsRect)),
|
||||
0, 0);
|
||||
|
||||
|
||||
intersection.size.width = MIN(_CGRectGetMaxX(lhsRect), _CGRectGetMaxX(rhsRect)) - _CGRectGetMinX(intersection);
|
||||
intersection.size.height = MIN(_CGRectGetMaxY(lhsRect), _CGRectGetMaxY(rhsRect)) - _CGRectGetMinY(intersection);
|
||||
|
||||
|
||||
return _CGRectIsEmpty(intersection) ? _CGRectMakeZero() : intersection;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
|
||||
*/
|
||||
function CGRectStandardize(aRect)
|
||||
{
|
||||
@@ -189,28 +239,28 @@ function CGRectUnion(lhsRect, rhsRect)
|
||||
minY = MIN(_CGRectGetMinY(lhsRect), _CGRectGetMinY(rhsRect)),
|
||||
maxX = MAX(_CGRectGetMaxX(lhsRect), _CGRectGetMaxX(rhsRect)),
|
||||
maxY = MAX(_CGRectGetMaxY(lhsRect), _CGRectGetMaxY(rhsRect));
|
||||
|
||||
|
||||
return _CGRectMake(minX, minY, maxX - minX, maxY - minY);
|
||||
}
|
||||
|
||||
function CGPointFromString(aString)
|
||||
{
|
||||
var comma = aString.indexOf(',');
|
||||
|
||||
|
||||
return { x:parseInt(aString.substr(1, comma - 1)), y:parseInt(aString.substring(comma + 1, aString.length)) };
|
||||
}
|
||||
|
||||
function CGSizeFromString(aString)
|
||||
{
|
||||
var comma = aString.indexOf(',');
|
||||
|
||||
|
||||
return { width:parseInt(aString.substr(1, comma - 1)), height:parseInt(aString.substring(comma + 1, aString.length)) };
|
||||
}
|
||||
|
||||
function CGRectFromString(aString)
|
||||
{
|
||||
var comma = aString.indexOf(',', aString.indexOf(',') + 1);
|
||||
|
||||
|
||||
return { origin:CGPointFromString(aString.substr(1, comma - 1)), size:CGSizeFromString(aString.substring(comma + 2, aString.length)) };
|
||||
}
|
||||
|
||||
@@ -233,6 +283,6 @@ function CPStringFromCGInset(anInset)
|
||||
return '{' + anInset.top + ", " + anInset.left + ", " + anInset.bottom + ", " + anInset.right + '}';
|
||||
}
|
||||
|
||||
/*!
|
||||
@}
|
||||
/*!
|
||||
@}
|
||||
*/
|
||||
|
||||
@@ -42,6 +42,8 @@ var PrimaryPlatformWindow = NULL;
|
||||
DOMElement _DOMBodyElement;
|
||||
DOMElement _DOMFocusElement;
|
||||
DOMElement _DOMEventGuard;
|
||||
DOMElement _DOMScrollingElement;
|
||||
id _hideDOMScrollingElementTimeout;
|
||||
|
||||
CPArray _windowLevels;
|
||||
CPDictionary _windowLayers;
|
||||
|
||||
@@ -24,7 +24,11 @@
|
||||
|
||||
var DOMFixedWidthSpanElement = nil,
|
||||
DOMFlexibleWidthSpanElement = nil,
|
||||
DOMMetricsDivElement = nil,
|
||||
DOMMetricsTextSpanElement = nil,
|
||||
DOMMetricsImgElement = nil,
|
||||
DOMIFrameElement = nil,
|
||||
DOMIFrameDocument = nil,
|
||||
DefaultFont = nil;
|
||||
|
||||
@implementation CPPlatformString : CPBasePlatformString
|
||||
@@ -59,7 +63,7 @@ var DOMFixedWidthSpanElement = nil,
|
||||
|
||||
bodyElement.appendChild(DOMIFrameElement);
|
||||
|
||||
var DOMIFrameDocument = (DOMIFrameElement.contentDocument || DOMIFrameElement.contentWindow.document);
|
||||
DOMIFrameDocument = (DOMIFrameElement.contentDocument || DOMIFrameElement.contentWindow.document);
|
||||
DOMIFrameDocument.write('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'+
|
||||
'<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head></head><body></body></html>');
|
||||
DOMIFrameDocument.close();
|
||||
@@ -88,6 +92,7 @@ var DOMFixedWidthSpanElement = nil,
|
||||
style.margin = "0px";
|
||||
style.width = "1px";
|
||||
style.wordWrap = "break-word";
|
||||
|
||||
try
|
||||
{
|
||||
style.whiteSpace = "pre";
|
||||
@@ -106,6 +111,46 @@ var DOMFixedWidthSpanElement = nil,
|
||||
DOMDivElement.appendChild(DOMFixedWidthSpanElement);
|
||||
}
|
||||
|
||||
+ (void)createDOMMetricsElements
|
||||
{
|
||||
if (!DOMIFrameElement)
|
||||
[self createDOMElements];
|
||||
|
||||
var style;
|
||||
|
||||
DOMMetricsDivElement = DOMIFrameDocument.createElement("div");
|
||||
DOMMetricsDivElement.style.position = "absolute";
|
||||
DOMMetricsDivElement.style.width = "100000px";
|
||||
|
||||
DOMIFrameDocument.body.appendChild(DOMMetricsDivElement);
|
||||
|
||||
DOMMetricsTextSpanElement = DOMIFrameDocument.createElement("span");
|
||||
DOMMetricsTextSpanElement.innerHTML = "x";
|
||||
style = DOMMetricsTextSpanElement.style;
|
||||
style.position = "absolute";
|
||||
style.visibility = "visible";
|
||||
style.padding = "0px";
|
||||
style.margin = "0px";
|
||||
style.whiteSpace = "pre";
|
||||
|
||||
var imgPath = [[CPBundle bundleForClass:[CPView class]] pathForResource:@"empty.png"];
|
||||
|
||||
DOMMetricsImgElement = DOMIFrameDocument.createElement("img");
|
||||
DOMMetricsImgElement.setAttribute("src", imgPath);
|
||||
DOMMetricsImgElement.setAttribute("width", "1");
|
||||
DOMMetricsImgElement.setAttribute("height", "1");
|
||||
DOMMetricsImgElement.setAttribute("alt", "");
|
||||
style = DOMMetricsImgElement.style;
|
||||
style.visibility = "visible";
|
||||
style.padding = "0px";
|
||||
style.margin = "0px";
|
||||
style.border = "none";
|
||||
style.verticalAlign = "baseline";
|
||||
|
||||
DOMMetricsDivElement.appendChild(DOMMetricsTextSpanElement);
|
||||
DOMMetricsDivElement.appendChild(DOMMetricsImgElement);
|
||||
}
|
||||
|
||||
+ (CGSize)sizeOfString:(CPString)aString withFont:(CPFont)aFont forWidth:(float)aWidth
|
||||
{
|
||||
if (!aFont)
|
||||
@@ -120,6 +165,7 @@ var DOMFixedWidthSpanElement = nil,
|
||||
[self createDOMElements];
|
||||
|
||||
var span;
|
||||
|
||||
if (!aWidth)
|
||||
span = DOMFlexibleWidthSpanElement;
|
||||
else
|
||||
@@ -138,4 +184,26 @@ var DOMFixedWidthSpanElement = nil,
|
||||
return _CGSizeMake(span.clientWidth, span.clientHeight);
|
||||
}
|
||||
|
||||
+ (CPDictionary)metricsOfFont:(CPFont)aFont
|
||||
{
|
||||
if (!aFont)
|
||||
{
|
||||
if (!DefaultFont)
|
||||
DefaultFont = [CPFont systemFontOfSize:12.0];
|
||||
|
||||
aFont = DefaultFont;
|
||||
}
|
||||
|
||||
if (!DOMMetricsDivElement)
|
||||
[self createDOMMetricsElements];
|
||||
|
||||
DOMMetricsDivElement.style.font = [aFont cssString];
|
||||
|
||||
var baseline = DOMMetricsImgElement.offsetTop - DOMMetricsTextSpanElement.offsetTop + DOMMetricsImgElement.offsetHeight,
|
||||
descender = baseline - DOMMetricsTextSpanElement.offsetHeight,
|
||||
lineHeight = DOMMetricsTextSpanElement.offsetHeight;
|
||||
|
||||
return [CPDictionary dictionaryWithObjectsAndKeys:baseline, @"ascender", descender, @"descender", lineHeight, @"lineHeight"];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -136,25 +136,58 @@ var CPDOMEventGetClickCount,
|
||||
//might be mac only, we should investigate futher later.
|
||||
var KeyCodesToPrevent = {},
|
||||
CharacterKeysToPrevent = {},
|
||||
KeyCodesToAllow = {},
|
||||
MozKeyCodeToKeyCodeMap = {
|
||||
61: 187, // =, equals
|
||||
59: 186 // ;, semicolon
|
||||
},
|
||||
KeyCodesToFunctionUnicodeMap = {};
|
||||
KeyCodesToUnicodeMap = {};
|
||||
|
||||
KeyCodesToPrevent[CPKeyCodes.A] = YES;
|
||||
|
||||
KeyCodesToFunctionUnicodeMap[CPKeyCodes.BACKSPACE] = CPBackspaceCharacter;
|
||||
KeyCodesToFunctionUnicodeMap[CPKeyCodes.DELETE] = CPDeleteCharacter;
|
||||
KeyCodesToFunctionUnicodeMap[CPKeyCodes.TAB] = CPTabCharacter;
|
||||
KeyCodesToFunctionUnicodeMap[CPKeyCodes.ENTER] = CPCarriageReturnCharacter;
|
||||
KeyCodesToFunctionUnicodeMap[CPKeyCodes.ESC] = CPEscapeFunctionKey;
|
||||
KeyCodesToFunctionUnicodeMap[CPKeyCodes.PAGE_UP] = CPPageUpFunctionKey;
|
||||
KeyCodesToFunctionUnicodeMap[CPKeyCodes.PAGE_DOWN] = CPPageDownFunctionKey;
|
||||
KeyCodesToFunctionUnicodeMap[CPKeyCodes.LEFT] = CPLeftArrowFunctionKey;
|
||||
KeyCodesToFunctionUnicodeMap[CPKeyCodes.UP] = CPUpArrowFunctionKey;
|
||||
KeyCodesToFunctionUnicodeMap[CPKeyCodes.RIGHT] = CPRightArrowFunctionKey;
|
||||
KeyCodesToFunctionUnicodeMap[CPKeyCodes.DOWN] = CPDownArrowFunctionKey;
|
||||
KeyCodesToAllow[CPKeyCodes.F1] = YES;
|
||||
KeyCodesToAllow[CPKeyCodes.F2] = YES;
|
||||
KeyCodesToAllow[CPKeyCodes.F3] = YES;
|
||||
KeyCodesToAllow[CPKeyCodes.F4] = YES;
|
||||
KeyCodesToAllow[CPKeyCodes.F5] = YES;
|
||||
KeyCodesToAllow[CPKeyCodes.F6] = YES;
|
||||
KeyCodesToAllow[CPKeyCodes.F7] = YES;
|
||||
KeyCodesToAllow[CPKeyCodes.F8] = YES;
|
||||
KeyCodesToAllow[CPKeyCodes.F9] = YES;
|
||||
KeyCodesToAllow[CPKeyCodes.F10] = YES;
|
||||
KeyCodesToAllow[CPKeyCodes.F11] = YES;
|
||||
KeyCodesToAllow[CPKeyCodes.F12] = YES;
|
||||
|
||||
KeyCodesToUnicodeMap[CPKeyCodes.BACKSPACE] = CPDeleteCharacter;
|
||||
KeyCodesToUnicodeMap[CPKeyCodes.DELETE] = CPDeleteFunctionKey;
|
||||
KeyCodesToUnicodeMap[CPKeyCodes.TAB] = CPTabCharacter;
|
||||
KeyCodesToUnicodeMap[CPKeyCodes.ENTER] = CPCarriageReturnCharacter;
|
||||
KeyCodesToUnicodeMap[CPKeyCodes.ESC] = CPEscapeFunctionKey;
|
||||
KeyCodesToUnicodeMap[CPKeyCodes.PAGE_UP] = CPPageUpFunctionKey;
|
||||
KeyCodesToUnicodeMap[CPKeyCodes.PAGE_DOWN] = CPPageDownFunctionKey;
|
||||
KeyCodesToUnicodeMap[CPKeyCodes.LEFT] = CPLeftArrowFunctionKey;
|
||||
KeyCodesToUnicodeMap[CPKeyCodes.UP] = CPUpArrowFunctionKey;
|
||||
KeyCodesToUnicodeMap[CPKeyCodes.RIGHT] = CPRightArrowFunctionKey;
|
||||
KeyCodesToUnicodeMap[CPKeyCodes.DOWN] = CPDownArrowFunctionKey;
|
||||
KeyCodesToUnicodeMap[CPKeyCodes.SEMICOLON] = ";";
|
||||
KeyCodesToUnicodeMap[CPKeyCodes.DASH] = "-";
|
||||
KeyCodesToUnicodeMap[CPKeyCodes.EQUALS] = "=";
|
||||
KeyCodesToUnicodeMap[CPKeyCodes.COMMA] = ",";
|
||||
KeyCodesToUnicodeMap[CPKeyCodes.PERIOD] = ".";
|
||||
KeyCodesToUnicodeMap[CPKeyCodes.SLASH] = "/";
|
||||
KeyCodesToUnicodeMap[CPKeyCodes.APOSTROPHE] = "`";
|
||||
KeyCodesToUnicodeMap[CPKeyCodes.SINGLE_QUOTE] = "'";
|
||||
KeyCodesToUnicodeMap[CPKeyCodes.OPEN_SQUARE_BRACKET] = "[";
|
||||
KeyCodesToUnicodeMap[CPKeyCodes.BACKSLASH] = "\\";
|
||||
KeyCodesToUnicodeMap[CPKeyCodes.CLOSE_SQUARE_BRACKET] = "]";
|
||||
|
||||
var ModifierKeyCodes = [
|
||||
CPKeyCodes.META,
|
||||
CPKeyCodes.MAC_FF_META,
|
||||
CPKeyCodes.CTRL,
|
||||
CPKeyCodes.ALT,
|
||||
CPKeyCodes.SHIFT
|
||||
];
|
||||
|
||||
var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
|
||||
@@ -283,6 +316,29 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
_DOMEventGuard.style.display = "none";
|
||||
_DOMEventGuard.className = "cpdontremove";
|
||||
_DOMBodyElement.appendChild(_DOMEventGuard);
|
||||
|
||||
// We get scrolling deltas from this element
|
||||
_DOMScrollingElement = theDocument.createElement("div");
|
||||
_DOMScrollingElement.style.position = "absolute";
|
||||
_DOMScrollingElement.style.visibility = "hidden";
|
||||
_DOMScrollingElement.style.zIndex = "998";
|
||||
_DOMScrollingElement.style.height = "60px";
|
||||
_DOMScrollingElement.style.width = "60px";
|
||||
_DOMScrollingElement.style.overflow = "scroll";
|
||||
//_DOMScrollingElement.style.backgroundColor = "rgba(0,0,0,1.0)"; // debug help.
|
||||
_DOMScrollingElement.style.opacity = "0";
|
||||
_DOMScrollingElement.style.filter = "alpha(opacity=0)";
|
||||
_DOMScrollingElement.className = "cpdontremove";
|
||||
_DOMBodyElement.appendChild(_DOMScrollingElement);
|
||||
|
||||
var _DOMInnerScrollingElement = theDocument.createElement("div");
|
||||
_DOMInnerScrollingElement.style.width = "400px";
|
||||
_DOMInnerScrollingElement.style.height = "400px";
|
||||
_DOMScrollingElement.appendChild(_DOMInnerScrollingElement);
|
||||
|
||||
// Set an initial scroll offset
|
||||
_DOMScrollingElement.scrollTop = 150;
|
||||
_DOMScrollingElement.scrollLeft = 150;
|
||||
}
|
||||
|
||||
- (void)registerDOMWindow
|
||||
@@ -542,7 +598,6 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
|
||||
[dragServer draggingStartedInPlatformWindow:self globalLocation:[CPPlatform isBrowser] ? location : _CGPointMake(aDOMEvent.screenX, aDOMEvent.screenY)];
|
||||
}
|
||||
|
||||
else if (type === "drag")
|
||||
{
|
||||
var y = aDOMEvent.screenY;
|
||||
@@ -552,7 +607,6 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
|
||||
[dragServer draggingSourceUpdatedWithGlobalLocation:[CPPlatform isBrowser] ? location : _CGPointMake(aDOMEvent.screenX, y)];
|
||||
}
|
||||
|
||||
else if (type === "dragover" || type === "dragleave")
|
||||
{
|
||||
if (aDOMEvent.preventDefault)
|
||||
@@ -563,16 +617,13 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
|
||||
if (dragOperation === CPDragOperationMove || dragOperation === CPDragOperationGeneric || dragOperation === CPDragOperationPrivate)
|
||||
dropEffect = "move";
|
||||
|
||||
else if (dragOperation === CPDragOperationCopy)
|
||||
dropEffect = "copy";
|
||||
|
||||
else if (dragOperation === CPDragOperationLink)
|
||||
dropEffect = "link";
|
||||
|
||||
aDOMEvent.dataTransfer.dropEffect = dropEffect;
|
||||
}
|
||||
|
||||
else if (type === "dragend")
|
||||
{
|
||||
var dropEffect = aDOMEvent.dataTransfer.dropEffect;
|
||||
@@ -588,7 +639,6 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
|
||||
[dragServer draggingEndedInPlatformWindow:self globalLocation:[CPPlatform isBrowser] ? location : _CGPointMake(aDOMEvent.screenX, aDOMEvent.screenY) operation:dragOperation];
|
||||
}
|
||||
|
||||
else //if (type === "drop")
|
||||
{
|
||||
[dragServer performDragOperationInPlatformWindow:self];
|
||||
@@ -607,18 +657,37 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
- (void)keyEvent:(DOMEvent)aDOMEvent
|
||||
{
|
||||
var event,
|
||||
timestamp = aDOMEvent.timeStamp ? aDOMEvent.timeStamp : new Date(),
|
||||
sourceElement = (aDOMEvent.target || aDOMEvent.srcElement),
|
||||
timestamp = aDOMEvent.timeStamp || new Date(),
|
||||
sourceElement = aDOMEvent.target || aDOMEvent.srcElement,
|
||||
windowNumber = [[CPApp keyWindow] windowNumber],
|
||||
modifierFlags = (aDOMEvent.shiftKey ? CPShiftKeyMask : 0) |
|
||||
(aDOMEvent.ctrlKey ? CPControlKeyMask : 0) |
|
||||
(aDOMEvent.altKey ? CPAlternateKeyMask : 0) |
|
||||
(aDOMEvent.metaKey ? CPCommandKeyMask : 0);
|
||||
|
||||
//We want to stop propagation if this is a command key AND this character or keycode has been added to our blacklist
|
||||
StopDOMEventPropagation = !!(!(modifierFlags & (CPControlKeyMask | CPCommandKeyMask)) ||
|
||||
CharacterKeysToPrevent[String.fromCharCode(aDOMEvent.keyCode || aDOMEvent.charCode).toLowerCase()] ||
|
||||
KeyCodesToPrevent[aDOMEvent.keyCode]);
|
||||
// With a few exceptions, all key events are blocked from propagating to
|
||||
// the browser. Here the following exceptions are being allowed:
|
||||
//
|
||||
// - All keys pressed along with a ctrl or cmd key _unless_ they are in
|
||||
// one of the two blacklists.
|
||||
// - Any key listed in the whitelist.
|
||||
//
|
||||
// The ctrl/cmd keys are used for browser hotkeys as are the keys listed in
|
||||
// the whitelist (F1-F12 at the time of writing).
|
||||
//
|
||||
// If a key is listed in both the blacklist and whitelist, the blacklist is
|
||||
// checked first. The key will be blocked from propagating in that case.
|
||||
|
||||
StopDOMEventPropagation = YES;
|
||||
|
||||
// Make sure it is not in the blacklists.
|
||||
if (!(CharacterKeysToPrevent[String.fromCharCode(aDOMEvent.keyCode || aDOMEvent.charCode).toLowerCase()] || KeyCodesToPrevent[aDOMEvent.keyCode]))
|
||||
{
|
||||
// It is not in the blacklist, let it through if the ctrl/cmd key is
|
||||
// also down or it's in the whitelist.
|
||||
if ((modifierFlags & (CPControlKeyMask | CPCommandKeyMask)) || KeyCodesToAllow[aDOMEvent.keyCode])
|
||||
StopDOMEventPropagation = NO;
|
||||
}
|
||||
|
||||
var isNativePasteEvent = NO,
|
||||
isNativeCopyOrCutEvent = NO,
|
||||
@@ -627,19 +696,36 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
switch (aDOMEvent.type)
|
||||
{
|
||||
case "keydown": // Grab and store the keycode now since it is correct and consistent at this point.
|
||||
if (aDOMEvent.keyCode.keyCode in MozKeyCodeToKeyCodeMap)
|
||||
if (aDOMEvent.keyCode in MozKeyCodeToKeyCodeMap)
|
||||
_keyCode = MozKeyCodeToKeyCodeMap[aDOMEvent.keyCode];
|
||||
else
|
||||
_keyCode = aDOMEvent.keyCode;
|
||||
|
||||
var characters = KeyCodesToFunctionUnicodeMap[_keyCode] || String.fromCharCode(_keyCode).toLowerCase();
|
||||
var characters;
|
||||
|
||||
// Handle key codes for which String.fromCharCode won't work.
|
||||
if (aDOMEvent.which === 0 || aDOMEvent.charCode === 0)
|
||||
characters = KeyCodesToUnicodeMap[_keyCode];
|
||||
|
||||
if (!characters)
|
||||
characters = String.fromCharCode(_keyCode).toLowerCase();
|
||||
|
||||
overrideCharacters = (modifierFlags & CPShiftKeyMask || _capsLockActive) ? characters.toUpperCase() : characters;
|
||||
|
||||
// check for caps lock state
|
||||
if (_keyCode === CPKeyCodes.CAPS_LOCK)
|
||||
_capsLockActive = YES;
|
||||
|
||||
if (modifierFlags & (CPControlKeyMask | CPCommandKeyMask))
|
||||
if ([ModifierKeyCodes containsObject:_keyCode])
|
||||
{
|
||||
// A modifier key will never fire keypress. We don't need to do any other processing so we just fire it here and break.
|
||||
event = [CPEvent keyEventWithType:CPFlagsChanged location:location modifierFlags:modifierFlags
|
||||
timestamp:timestamp windowNumber:windowNumber context:nil
|
||||
characters:nil charactersIgnoringModifiers:nil isARepeat:NO keyCode:_keyCode];
|
||||
|
||||
break;
|
||||
}
|
||||
else if (modifierFlags & (CPControlKeyMask | CPCommandKeyMask))
|
||||
{
|
||||
//we are simply going to skip all keypress events that use cmd/ctrl key
|
||||
//this lets us be consistent in all browsers and send on the keydown
|
||||
@@ -696,8 +782,15 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
_lastKey = keyCode;
|
||||
_charCodes[keyCode] = charCode;
|
||||
|
||||
var characters = overrideCharacters || KeyCodesToFunctionUnicodeMap[charCode] || String.fromCharCode(charCode),
|
||||
charactersIgnoringModifiers = characters.toLowerCase();
|
||||
var characters = overrideCharacters;
|
||||
// Is this a special key?
|
||||
if (!characters && (aDOMEvent.which === 0 || aDOMEvent.charCode === 0))
|
||||
characters = KeyCodesToUnicodeMap[charCode];
|
||||
|
||||
if (!characters)
|
||||
characters = String.fromCharCode(charCode);
|
||||
|
||||
charactersIgnoringModifiers = characters.toLowerCase(); // FIXME: This isn't correct. It SHOULD include Shift.
|
||||
|
||||
// Safari won't send proper capitalization during cmd-key events
|
||||
if (!overrideCharacters && (modifierFlags & CPCommandKeyMask) && ((modifierFlags & CPShiftKeyMask) || _capsLockActive))
|
||||
@@ -705,7 +798,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
|
||||
event = [CPEvent keyEventWithType:CPKeyDown location:location modifierFlags:modifierFlags
|
||||
timestamp:timestamp windowNumber:windowNumber context:nil
|
||||
characters:characters charactersIgnoringModifiers:charactersIgnoringModifiers isARepeat:isARepeat keyCode:keyCode];
|
||||
characters:characters charactersIgnoringModifiers:charactersIgnoringModifiers isARepeat:isARepeat keyCode:charCode];
|
||||
|
||||
if (isNativePasteEvent)
|
||||
{
|
||||
@@ -728,7 +821,10 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
if (keyCode === CPKeyCodes.CAPS_LOCK)
|
||||
_capsLockActive = NO;
|
||||
|
||||
var characters = KeyCodesToFunctionUnicodeMap[charCode] || String.fromCharCode(charCode),
|
||||
if ([ModifierKeyCodes containsObject:keyCode])
|
||||
break;
|
||||
|
||||
var characters = KeyCodesToUnicodeMap[charCode] || String.fromCharCode(charCode),
|
||||
charactersIgnoringModifiers = characters.toLowerCase();
|
||||
|
||||
if (!(modifierFlags & CPShiftKeyMask) && (modifierFlags & CPCommandKeyMask) && !_capsLockActive)
|
||||
@@ -862,7 +958,13 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
|
||||
- (void)scrollEvent:(DOMEvent)aDOMEvent
|
||||
{
|
||||
if(!aDOMEvent)
|
||||
if (_hideDOMScrollingElementTimeout)
|
||||
{
|
||||
clearTimeout(_hideDOMScrollingElementTimeout);
|
||||
_hideDOMScrollingElementTimeout = nil;
|
||||
}
|
||||
|
||||
if (!aDOMEvent)
|
||||
aDOMEvent = window.event;
|
||||
|
||||
var location = nil;
|
||||
@@ -881,7 +983,6 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
{
|
||||
x += element.offsetLeft;
|
||||
y += element.offsetTop;
|
||||
|
||||
} while (element = element.offsetParent);
|
||||
}
|
||||
|
||||
@@ -901,7 +1002,13 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
(aDOMEvent.altKey ? CPAlternateKeyMask : 0) |
|
||||
(aDOMEvent.metaKey ? CPCommandKeyMask : 0);
|
||||
|
||||
StopDOMEventPropagation = YES;
|
||||
// Show the dom element
|
||||
_DOMScrollingElement.style.visibility = "visible";
|
||||
_DOMScrollingElement.style.top = (location.y - 15) + @"px";
|
||||
_DOMScrollingElement.style.left = (location.x - 15) + @"px";
|
||||
|
||||
// We let the browser handle the scrolling
|
||||
StopDOMEventPropagation = NO;
|
||||
|
||||
var theWindow = [self hitTest:location];
|
||||
|
||||
@@ -912,40 +1019,54 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
|
||||
location = [theWindow convertBridgeToBase:location];
|
||||
|
||||
if(typeof aDOMEvent.wheelDeltaX != "undefined")
|
||||
{
|
||||
deltaX = aDOMEvent.wheelDeltaX / 120.0;
|
||||
deltaY = aDOMEvent.wheelDeltaY / 120.0;
|
||||
}
|
||||
|
||||
else if (aDOMEvent.wheelDelta)
|
||||
deltaY = aDOMEvent.wheelDelta / 120.0;
|
||||
|
||||
else if (aDOMEvent.detail)
|
||||
deltaY = -aDOMEvent.detail / 3.0;
|
||||
|
||||
else
|
||||
return;
|
||||
|
||||
if(!CPFeatureIsCompatible(CPJavaScriptNegativeMouseWheelValues))
|
||||
{
|
||||
deltaX = -deltaX;
|
||||
deltaY = -deltaY;
|
||||
}
|
||||
|
||||
var event = [CPEvent mouseEventWithType:CPScrollWheel location:location modifierFlags:modifierFlags
|
||||
timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:-1 clickCount:1 pressure:0 ];
|
||||
|
||||
timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:-1 clickCount:1 pressure:0];
|
||||
event._DOMEvent = aDOMEvent;
|
||||
event._deltaX = deltaX;
|
||||
event._deltaY = deltaY;
|
||||
|
||||
[CPApp sendEvent:event];
|
||||
// We lag 1 event behind without this timeout.
|
||||
setTimeout(function()
|
||||
{
|
||||
// Find the scroll delta
|
||||
var deltaX = _DOMScrollingElement.scrollLeft - 150,
|
||||
deltaY = _DOMScrollingElement.scrollTop - 150;
|
||||
|
||||
if (StopDOMEventPropagation)
|
||||
CPDOMEventStop(aDOMEvent, self);
|
||||
// If we scroll super with momentum,
|
||||
// there are so many events going off that
|
||||
// a tiny percent don't actually have any deltas.
|
||||
//
|
||||
// This does *not* make scrolling appear sluggish,
|
||||
// it just seems like that is something that happens.
|
||||
//
|
||||
// We get free performance boost if we skip sending these events,
|
||||
// as sending a scroll event with no deltas doesn't do anything.
|
||||
if (deltaX || deltaY)
|
||||
{
|
||||
event._deltaX = deltaX;
|
||||
event._deltaY = deltaY;
|
||||
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
[CPApp sendEvent:event];
|
||||
}
|
||||
|
||||
// We set StopDOMEventPropagation = NO on line 1008
|
||||
//if (StopDOMEventPropagation)
|
||||
// CPDOMEventStop(aDOMEvent, self);
|
||||
|
||||
// Reset the DOM elements scroll offset
|
||||
_DOMScrollingElement.scrollLeft = 150;
|
||||
_DOMScrollingElement.scrollTop = 150;
|
||||
|
||||
// Is this needed?
|
||||
//[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
|
||||
}, 0);
|
||||
|
||||
// We hide the dom element after a little bit
|
||||
// so that other DOM elements such as inputs
|
||||
// can receive events.
|
||||
_hideDOMScrollingElementTimeout = setTimeout(function()
|
||||
{
|
||||
_DOMScrollingElement.style.visibility = "hidden";
|
||||
}, 300);
|
||||
}
|
||||
|
||||
- (void)resizeEvent:(DOMEvent)aDOMEvent
|
||||
@@ -1007,8 +1128,8 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
|
||||
newEvent.shiftKey = newEvent.ctrlKey = newEvent.altKey = newEvent.metaKey = false;
|
||||
|
||||
newEvent.preventDefault = function(){if(aDOMEvent.preventDefault) aDOMEvent.preventDefault()};
|
||||
newEvent.stopPropagation = function(){if(aDOMEvent.stopPropagation) aDOMEvent.stopPropagation()};
|
||||
newEvent.preventDefault = function() { if (aDOMEvent.preventDefault) aDOMEvent.preventDefault() };
|
||||
newEvent.stopPropagation = function() { if (aDOMEvent.stopPropagation) aDOMEvent.stopPropagation() };
|
||||
|
||||
[self mouseEvent:newEvent];
|
||||
|
||||
@@ -1057,7 +1178,6 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
|
||||
if (_mouseDownWindow)
|
||||
windowNumber = [_mouseDownWindow windowNumber];
|
||||
|
||||
else
|
||||
{
|
||||
var theWindow = [self hitTest:location];
|
||||
@@ -1073,7 +1193,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
|
||||
if (type === "mouseup")
|
||||
{
|
||||
if(_mouseIsDown)
|
||||
if (_mouseIsDown)
|
||||
{
|
||||
event = _CPEventFromNativeMouseEvent(aDOMEvent, _mouseDownIsRightClick ? CPRightMouseUp : CPLeftMouseUp, location, modifierFlags, timestamp, windowNumber, nil, -1, CPDOMEventGetClickCount(_lastMouseUp, timestamp, location), 0);
|
||||
|
||||
@@ -1083,7 +1203,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
_mouseDownIsRightClick = NO;
|
||||
}
|
||||
|
||||
if(_DOMEventMode)
|
||||
if (_DOMEventMode)
|
||||
{
|
||||
_DOMEventMode = NO;
|
||||
return;
|
||||
@@ -1092,6 +1212,9 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
|
||||
else if (type === "mousedown")
|
||||
{
|
||||
var button = aDOMEvent.button;
|
||||
_mouseDownIsRightClick = button == 2 || (CPBrowserIsOperatingSystem(CPMacOperatingSystem) && button == 0 && modifierFlags & CPControlKeyMask);
|
||||
|
||||
if (sourceElement.tagName === "INPUT" && sourceElement != _DOMFocusElement)
|
||||
{
|
||||
if ([CPPlatform supportsDragAndDrop])
|
||||
@@ -1104,11 +1227,11 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
_mouseIsDown = YES;
|
||||
|
||||
//fake a down and up event so that event tracking mode will work correctly
|
||||
[CPApp sendEvent:[CPEvent mouseEventWithType:CPLeftMouseDown location:location modifierFlags:modifierFlags
|
||||
[CPApp sendEvent:[CPEvent mouseEventWithType:_mouseDownIsRightClick ? CPRightMouseDown : CPLeftMouseDown location:location modifierFlags:modifierFlags
|
||||
timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:-1
|
||||
clickCount:CPDOMEventGetClickCount(_lastMouseDown, timestamp, location) pressure:0]];
|
||||
|
||||
[CPApp sendEvent:[CPEvent mouseEventWithType:CPLeftMouseUp location:location modifierFlags:modifierFlags
|
||||
[CPApp sendEvent:[CPEvent mouseEventWithType:_mouseDownIsRightClick ? CPRightMouseUp : CPLeftMouseUp location:location modifierFlags:modifierFlags
|
||||
timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:-1
|
||||
clickCount:CPDOMEventGetClickCount(_lastMouseDown, timestamp, location) pressure:0]];
|
||||
|
||||
@@ -1120,9 +1243,6 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
_DOMBodyElement.style["-khtml-user-drag"] = "element";
|
||||
}
|
||||
|
||||
var button = aDOMEvent.button;
|
||||
_mouseDownIsRightClick = button == 2 || (button == 0 && modifierFlags & CPControlKeyMask);
|
||||
|
||||
StopContextMenuDOMEventPropagation = YES;
|
||||
|
||||
event = _CPEventFromNativeMouseEvent(aDOMEvent, _mouseDownIsRightClick ? CPRightMouseDown : CPLeftMouseDown, location, modifierFlags, timestamp, windowNumber, nil, -1, CPDOMEventGetClickCount(_lastMouseDown, timestamp, location), 0);
|
||||
@@ -1152,7 +1272,18 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
CPDOMEventStop(aDOMEvent, self);
|
||||
|
||||
// if there are any tracking event listeners then show the event guard so we don't lose events to iframes
|
||||
_DOMEventGuard.style.display = (CPApp._eventListeners.length === 0) ? "none" : "";
|
||||
// TODO Actually check for tracking event listeners, not just any listener but _CPRunModalLoop.
|
||||
var hasTrackingEventListener = NO;
|
||||
for (var i=0; i < CPApp._eventListeners.length; i++)
|
||||
{
|
||||
if (CPApp._eventListeners[i]._callback !== _CPRunModalLoop)
|
||||
{
|
||||
hasTrackingEventListener = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_DOMEventGuard.style.display = hasTrackingEventListener ? "" : "none";
|
||||
|
||||
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
|
||||
}
|
||||
@@ -1356,7 +1487,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
*/
|
||||
+ (void)preventCharacterKeysFromPropagating:(CPArray)characters
|
||||
{
|
||||
for(var i=characters.length; i>0; i--)
|
||||
for (var i = characters.length; i > 0; i--)
|
||||
CharacterKeysToPrevent[""+characters[i-1].toLowerCase()] = YES;
|
||||
}
|
||||
|
||||
@@ -1382,7 +1513,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
|
||||
*/
|
||||
+ (void)preventKeyCodesFromPropagating:(CPArray)keyCodes
|
||||
{
|
||||
for(var i=keyCodes.length; i>0; i--)
|
||||
for (var i = keyCodes.length; i > 0; i--)
|
||||
KeyCodesToPrevent[keyCodes[i-1]] = YES;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
These graphics come from the Tango Desktop Project (http://tango.freedesktop.org/Tango_Desktop_Project).
|
||||
They are released under the Creative Commons Attribution Share-Alike license, full text below.
|
||||
|
||||
|
||||
(license available from CC here: http://creativecommons.org/licenses/by-sa/2.5/)
|
||||
|
||||
License
|
||||
|
||||
THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
|
||||
|
||||
BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.
|
||||
|
||||
1. Definitions
|
||||
|
||||
"Collective Work" means a work, such as a periodical issue, anthology or encyclopedia, in which the Work in its entirety in unmodified form, along with a number of other contributions, constituting separate and independent works in themselves, are assembled into a collective whole. A work that constitutes a Collective Work will not be considered a Derivative Work (as defined below) for the purposes of this License.
|
||||
"Derivative Work" means a work based upon the Work or upon the Work and other pre-existing works, such as a translation, musical arrangement, dramatization, fictionalization, motion picture version, sound recording, art reproduction, abridgment, condensation, or any other form in which the Work may be recast, transformed, or adapted, except that a work that constitutes a Collective Work will not be considered a Derivative Work for the purpose of this License. For the avoidance of doubt, where the Work is a musical composition or sound recording, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered a Derivative Work for the purpose of this License.
|
||||
"Licensor" means the individual or entity that offers the Work under the terms of this License.
|
||||
"Original Author" means the individual or entity who created the Work.
|
||||
"Work" means the copyrightable work of authorship offered under the terms of this License.
|
||||
"You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation.
|
||||
"License Elements" means the following high-level license attributes as selected by Licensor and indicated in the title of this License: Attribution, ShareAlike.
|
||||
2. Fair Use Rights. Nothing in this license is intended to reduce, limit, or restrict any rights arising from fair use, first sale or other limitations on the exclusive rights of the copyright owner under copyright law or other applicable laws.
|
||||
|
||||
3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below:
|
||||
|
||||
to reproduce the Work, to incorporate the Work into one or more Collective Works, and to reproduce the Work as incorporated in the Collective Works;
|
||||
to create and reproduce Derivative Works;
|
||||
to distribute copies or phonorecords of, display publicly, perform publicly, and perform publicly by means of a digital audio transmission the Work including as incorporated in Collective Works;
|
||||
to distribute copies or phonorecords of, display publicly, perform publicly, and perform publicly by means of a digital audio transmission Derivative Works.
|
||||
For the avoidance of doubt, where the work is a musical composition:
|
||||
|
||||
Performance Royalties Under Blanket Licenses. Licensor waives the exclusive right to collect, whether individually or via a performance rights society (e.g. ASCAP, BMI, SESAC), royalties for the public performance or public digital performance (e.g. webcast) of the Work.
|
||||
Mechanical Rights and Statutory Royalties. Licensor waives the exclusive right to collect, whether individually or via a music rights society or designated agent (e.g. Harry Fox Agency), royalties for any phonorecord You create from the Work ("cover version") and distribute, subject to the compulsory license created by 17 USC Section 115 of the US Copyright Act (or the equivalent in other jurisdictions).
|
||||
Webcasting Rights and Statutory Royalties. For the avoidance of doubt, where the Work is a sound recording, Licensor waives the exclusive right to collect, whether individually or via a performance-rights society (e.g. SoundExchange), royalties for the public digital performance (e.g. webcast) of the Work, subject to the compulsory license created by 17 USC Section 114 of the US Copyright Act (or the equivalent in other jurisdictions).
|
||||
The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. All rights not expressly granted by Licensor are hereby reserved.
|
||||
|
||||
4. Restrictions.The license granted in Section 3 above is expressly made subject to and limited by the following restrictions:
|
||||
|
||||
You may distribute, publicly display, publicly perform, or publicly digitally perform the Work only under the terms of this License, and You must include a copy of, or the Uniform Resource Identifier for, this License with every copy or phonorecord of the Work You distribute, publicly display, publicly perform, or publicly digitally perform. You may not offer or impose any terms on the Work that alter or restrict the terms of this License or the recipients' exercise of the rights granted hereunder. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties. You may not distribute, publicly display, publicly perform, or publicly digitally perform the Work with any technological measures that control access or use of the Work in a manner inconsistent with the terms of this License Agreement. The above applies to the Work as incorporated in a Collective Work, but this does not require the Collective Work apart from the Work itself to be made subject to the terms of this License. If You create a Collective Work, upon notice from any Licensor You must, to the extent practicable, remove from the Collective Work any credit as required by clause 4(c), as requested. If You create a Derivative Work, upon notice from any Licensor You must, to the extent practicable, remove from the Derivative Work any credit as required by clause 4(c), as requested.
|
||||
You may distribute, publicly display, publicly perform, or publicly digitally perform a Derivative Work only under the terms of this License, a later version of this License with the same License Elements as this License, or a Creative Commons iCommons license that contains the same License Elements as this License (e.g. Attribution-ShareAlike 2.5 Japan). You must include a copy of, or the Uniform Resource Identifier for, this License or other license specified in the previous sentence with every copy or phonorecord of each Derivative Work You distribute, publicly display, publicly perform, or publicly digitally perform. You may not offer or impose any terms on the Derivative Works that alter or restrict the terms of this License or the recipients' exercise of the rights granted hereunder, and You must keep intact all notices that refer to this License and to the disclaimer of warranties. You may not distribute, publicly display, publicly perform, or publicly digitally perform the Derivative Work with any technological measures that control access or use of the Work in a manner inconsistent with the terms of this License Agreement. The above applies to the Derivative Work as incorporated in a Collective Work, but this does not require the Collective Work apart from the Derivative Work itself to be made subject to the terms of this License.
|
||||
If you distribute, publicly display, publicly perform, or publicly digitally perform the Work or any Derivative Works or Collective Works, You must keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or (ii) if the Original Author and/or Licensor designate another party or parties (e.g. a sponsor institute, publishing entity, journal) for attribution in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; the title of the Work if supplied; to the extent reasonably practicable, the Uniform Resource Identifier, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and in the case of a Derivative Work, a credit identifying the use of the Work in the Derivative Work (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). Such credit may be implemented in any reasonable manner; provided, however, that in the case of a Derivative Work or Collective Work, at a minimum such credit will appear where any other comparable authorship credit appears and in a manner at least as prominent as such other comparable authorship credit.
|
||||
5. Representations, Warranties and Disclaimer
|
||||
|
||||
UNLESS OTHERWISE AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE MATERIALS, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.
|
||||
|
||||
6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
7. Termination
|
||||
|
||||
This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Derivative Works or Collective Works from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License.
|
||||
Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above.
|
||||
8. Miscellaneous
|
||||
|
||||
Each time You distribute or publicly digitally perform the Work or a Collective Work, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License.
|
||||
Each time You distribute or publicly digitally perform a Derivative Work, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License.
|
||||
If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.
|
||||
No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent.
|
||||
This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You.
|
||||
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 177 B After Width: | Height: | Size: 186 B |
|
Before Width: | Height: | Size: 167 B After Width: | Height: | Size: 181 B |
|
Before Width: | Height: | Size: 311 B After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 179 B After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 331 B After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 114 B After Width: | Height: | Size: 1002 B |
|
Before Width: | Height: | Size: 118 B After Width: | Height: | Size: 997 B |
|
Before Width: | Height: | Size: 114 B After Width: | Height: | Size: 1002 B |
|
Before Width: | Height: | Size: 182 B After Width: | Height: | Size: 1017 B |
|
Before Width: | Height: | Size: 115 B After Width: | Height: | Size: 1000 B |
|
Before Width: | Height: | Size: 185 B After Width: | Height: | Size: 1019 B |
|
Before Width: | Height: | Size: 349 B After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 663 B After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 110 B |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 283 B After Width: | Height: | Size: 283 B |
|
Before Width: | Height: | Size: 289 B After Width: | Height: | Size: 289 B |
|
Before Width: | Height: | Size: 424 B After Width: | Height: | Size: 424 B |
|
Before Width: | Height: | Size: 419 B After Width: | Height: | Size: 419 B |
|
Before Width: | Height: | Size: 420 B After Width: | Height: | Size: 420 B |
|
Before Width: | Height: | Size: 639 B After Width: | Height: | Size: 639 B |
|
Before Width: | Height: | Size: 625 B After Width: | Height: | Size: 625 B |
|
Before Width: | Height: | Size: 617 B After Width: | Height: | Size: 617 B |
|
Before Width: | Height: | Size: 269 B After Width: | Height: | Size: 269 B |
|
Before Width: | Height: | Size: 653 B After Width: | Height: | Size: 653 B |
|
Before Width: | Height: | Size: 657 B After Width: | Height: | Size: 657 B |
|
Before Width: | Height: | Size: 841 B After Width: | Height: | Size: 841 B |