Compare commits

..
3 Commits
1291 changed files with 22060 additions and 157408 deletions
-5
View File
@@ -5,8 +5,3 @@ Demos
./Aristo
WebSite
.push-package
*.xcodeproj/*.pbxuser
*.xcodeproj/*.perspectivev3
xcuserdata/
!*.xcodeproj/project.pbxproj
target
-2
View File
@@ -1,2 +0,0 @@
rvm_install_on_use_flag=1
rvm jruby-head@buildr
+4 -19
View File
@@ -24,7 +24,6 @@
@import "CPAlert.j"
@import "CPAnimation.j"
@import "CPApplication.j"
@import "CPArrayController.j"
@import "CPBezierPath.j"
@import "CPBox.j"
@import "CPBrowser.j"
@@ -32,15 +31,13 @@
@import "CPButtonBar.j"
@import "CPCheckBox.j"
@import "CPCib.j"
@import "CPCibBindingConnector.j"
@import "CPCibConnector.j"
@import "CPCibControlConnector.j"
@import "CPCibLoading.j"
@import "CPCibOutletConnector.j"
@import "CPCibRuntimeAttributesConnector.j"
@import "CPClipView.j"
@import "CPCollectionView.j"
@import "CPCollectionViewItem.j"
@import "CPCollectionView.j"
@import "CPColor.j"
@import "CPColorPanel.j"
@import "CPColorWell.j"
@@ -56,11 +53,8 @@
@import "CPFont.j"
@import "CPFontManager.j"
@import "CPGeometry.j"
@import "CPGraphics.j"
@import "CPImage.j"
@import "CPImageView.j"
@import "CPKeyBinding.j"
@import "CPLevelIndicator.j"
@import "CPMenu.j"
@import "CPMenuItem.j"
@import "CPOpenPanel.j"
@@ -68,33 +62,24 @@
@import "CPPanel.j"
@import "CPPasteboard.j"
@import "CPPopUpButton.j"
@import "CPPredicateEditor.j"
@import "CPPredicateEditorRowTemplate.j"
@import "CPProgressIndicator.j"
@import "CPRadio.j"
@import "CPResponder.j"
@import "CPRuleEditor.j"
@import "CPScroller.j"
@import "CPScrollView.j"
@import "CPSearchField.j"
@import "CPScrollView.j"
@import "CPScroller.j"
@import "CPSecureTextField.j"
@import "CPSegmentedControl.j"
@import "CPShadow.j"
@import "CPSlider.j"
@import "CPSound.j"
@import "CPSplitView.j"
@import "CPStepper.j"
@import "CPTabView.j"
@import "CPTableColumn.j"
@import "CPTableView.j"
@import "CPTabView.j"
@import "CPText.j"
@import "CPTextField.j"
@import "CPTokenField.j"
@import "CPToolbar.j"
@import "CPToolbarItem.j"
@import "_CPToolTip.j"
@import "CPTreeNode.j"
@import "CPUserDefaultsController.j"
@import "CPView.j"
@import "CPViewAnimation.j"
@import "CPViewController.j"
+11 -46
View File
@@ -26,16 +26,11 @@
@import <Foundation/CPIndexSet.j>
@import <Foundation/CPString.j>
@import "CPView.j"
@import "CPButton.j"
@import <AppKit/CPView.j>
#import "CoreGraphics/CGGeometry.h"
/*!
@ingroup appkit
@class CPAccordionViewItem
<p>A CPAccordionViewItem represents a single section of a CPAccordionView.</p>
*/
@implementation CPAccordionViewItem : CPObject
{
CPString _identifier @accessors(property=identifier);
@@ -48,10 +43,6 @@
return [self initWithIdentifier:@""];
}
/*!
Initializes a new CPAccordionViewItem with the specified identifier. This identifier may
then be used in subsequent methods to provide abstract introspection of the CPAccordionView.
*/
- (id)initWithIdentifier:(CPString)anIdentifier
{
self = [super init];
@@ -64,25 +55,6 @@
@end
/*!
@ingroup appkit
@class CPAccordionView
<p>CPAccordionView provides a container for CPAccordionViewItem objects and manages layout state
for all sub-layout items.</p>
<strong>Example</strong><br />
<pre>
var myAccordionView = [[CPAccordionView alloc] initWithFrame:CGRectMakeZero()];
var firstItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"firstSection"]];
[firstItem setView:[[CPView alloc] initWithFrame:CGRectMakeZero()]];
var secondItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"secondSection"]];
[secondItem setView:[[CPView alloc] initWithFrame:CGRectMakeZero()]];
[myAccordionView addItem:firstItem];
[myAccordionView addItem:secondItem];
[myAccordionView setAutoresizingMask: CPViewWidthSizable | CPViewHeightSizable];
</pre>
*/
@implementation CPAccordionView : CPView
{
CPInteger _dirtyItemIndex;
@@ -92,10 +64,7 @@ var secondItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"secondSection
CPMutableArray _itemViews;
CPIndexSet _expandedItemIndexes;
}
/*!
Initializes the receiver for usage with the specified bounding rectangle
@return the initialized view
*/
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
@@ -126,11 +95,7 @@ var secondItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"secondSection
{
return _items;
}
/*!
Append a CPAccordionViewItem to the receiver. Note that the CPAccordionViewItem must contain
a valid CPView derived component or a TypeError will be generated when the contents of the
ViewItem are disclosed.
*/
- (void)addItem:(CPAccordionViewItem)anItem
{
[self insertItem:anItem atIndex:_items.length];
@@ -213,7 +178,7 @@ var secondItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"secondSection
if ([itemView isCollapsed])
[self expandItemAtIndex:anIndex];
else
[self collapseItemAtIndex:anIndex];
}
@@ -237,12 +202,12 @@ var secondItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"secondSection
var itemView = _itemViews[anIndex];
if (!itemView)
return;
if (!isEnabled)
[self collapseItemAtIndex:anIndex];
else
[self expandItemAtIndex:anIndex];
[itemView setEnabled:isEnabled];
}
@@ -270,7 +235,7 @@ var secondItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"secondSection
{
if (_items.length <= 0)
return [self setFrameSize:_CGSizeMake(_CGRectGetWidth([self frame]), 0.0)];
if (_dirtyItemIndex === CPNotFound)
return;
@@ -391,7 +356,7 @@ var secondItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"secondSection
[_contentView setFrameSize:_CGSizeMake(aWidth, contentHeight)];
[self setFrame:_CGRectMake(0.0, aY, aWidth, contentHeight + headerHeight)];
}
}
}
- (void)resizeSubviewsWithOldSize:(CGSize)aSize
@@ -408,7 +373,7 @@ var secondItem = [[CPAccordionViewItem alloc] initWithIdentifier:@"secondSection
/*
else if (aKeyPath === "itemHeaderPrototype")
{
}
*/
}
+177 -567
View File
@@ -6,9 +6,7 @@
* Copyright 2008, Jake MacMullin.
*
* 11/10/2008 Ross Boucher
* - Make it conform to style guidelines, general cleanup and enhancements
* 11/10/2010 Antoine Mercadal
* - Enhancements, better compliance with Cocoa API
* - Make it conform to style guidelines, general cleanup and ehancements
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -28,34 +26,39 @@
@import <Foundation/CPObject.j>
@import <Foundation/CPString.j>
@import "CPApplication.j"
@import "CPButton.j"
@import "CPColor.j"
@import "CPFont.j"
@import "CPImage.j"
@import "CPImageView.j"
@import "CPPanel.j"
@import "CPTextField.j"
@import <AppKit/CPApplication.j>
@import <AppKit/CPButton.j>
@import <AppKit/CPColor.j>
@import <AppKit/CPFont.j>
@import <AppKit/CPImage.j>
@import <AppKit/CPImageView.j>
@import <AppKit/CPPanel.j>
@import <AppKit/CPTextField.j>
/*
@global
@group CPAlertStyle
*/
CPWarningAlertStyle = 0;
CPWarningAlertStyle = 0;
/*
@global
@group CPAlertStyle
*/
CPInformationalAlertStyle = 1;
CPInformationalAlertStyle = 1;
/*
@global
@group CPAlertStyle
*/
CPCriticalAlertStyle = 2;
CPCriticalAlertStyle = 2;
var CPAlertWarningImage,
CPAlertInformationImage,
CPAlertErrorImage;
/*!
@ingroup appkit
CPAlert is an alert panel that can be displayed modally to present the
user with a message and one or more options.
@@ -71,83 +74,41 @@ CPCriticalAlertStyle = 2;
@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 : CPView
@implementation CPAlert : CPObject
{
BOOL _showHelp @accessors(property=showsHelp);
BOOL _showSuppressionButton @accessors(property=showsSuppressionButton);
CPPanel _alertPanel;
CPAlertStyle _alertStyle @accessors(property=alertStyle);
CPString _title @accessors(property=title);
CPView _accessoryView @accessors(property=accessoryView);
CPImage _icon @accessors(property=icon);
CPArray _buttons @accessors(property=buttons,readonly);
CPCheckBox _suppressionButton @accessors(property=suppressionButton,readonly);
id _delegate @accessors(property=delegate);
id _modalDelegate;
SEL _didEndSelector;
CPWindow _window @accessors(property=window,readonly);
int _defaultWindowStyle;
CPImageView _alertImageView;
CPTextField _informativeLabel;
CPTextField _messageLabel;
CPButton _alertHelpButton;
CPImageView _alertImageView;
BOOL _needsLayout;
CPAlertStyle _alertStyle;
CPString _windowTitle;
int _windowStyle;
int _buttonCount;
CPArray _buttons;
id _delegate;
}
#pragma mark Creating Alerts
/*!
Returns a CPAlert object with the provided info
@param aMessage the main body text of the alert
@param defaultButton the title of the default button
@param alternateButton if not nil, the title of a second button
@param otherButton if not nil, the title of the third button
@param informativeText if not nil the informative text of the alert
@return fully initialized CPAlert
*/
+ (CPAlert)alertWithMessageText:(CPString)aMessage defaultButton:(CPString)defaultButtonTitle alternateButton:(CPString)alternateButtonTitle otherButton:(CPString)otherButtonTitle informativeTextWithFormat:(CPString)informativeText
+ (void)initialize
{
var alert = [[CPAlert alloc] init];
if (self != CPAlert)
return;
[alert setMessageText:aMessage];
[alert addButtonWithTitle:defaultButtonTitle];
var bundle = [CPBundle bundleForClass:[self class]];
if (alternateButtonTitle)
[alert addButtonWithTitle:alternateButtonTitle];
if (otherButtonTitle)
[alert addButtonWithTitle:otherButtonTitle];
if (informativeText)
[alert setInformativeText:informativeText];
return alert;
}
/*!
Return an CPAlert with type error
@param anErrorMessage the message of the alert
@return fully initialized CPAlert
*/
+ (CPAlert)alertWithError:(CPString)anErrorMessage
{
var alert = [[CPAlert alloc] init];
[alert setMessageText:anErrorMessage];
[alert setAlertStyle:CPCriticalAlertStyle];
return alert;
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)];
}
/*!
@@ -155,384 +116,166 @@ CPCriticalAlertStyle = 2;
*/
- (id)init
{
self = [super init];
if (self)
if (self = [super init])
{
_buttons = [];
_alertStyle = CPWarningAlertStyle;
_showHelp = NO;
_needsLayout = YES;
_defaultWindowStyle = CPTitledWindowMask;
_buttonCount = 0;
_buttons = [CPArray array];
_alertStyle = CPWarningAlertStyle;
_messageLabel = [CPTextField labelWithTitle:@"Alert"];
_alertImageView = [[CPImageView alloc] init];
_informativeLabel = [[CPTextField alloc] init];
_suppressionButton = [CPCheckBox checkBoxWithTitle:@"Do not show this message again"];
_alertHelpButton = [[CPButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 16.0, 16.0)];
[_alertHelpButton setTarget:self];
[_alertHelpButton setAction:@selector(_showHelp:)];
[self setWindowStyle:nil];
}
return self;
}
#pragma mark Accessors
/*!
Sets the window appearance.
@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]];
var count = [_buttons count];
for(var i=0; i < count; i++)
{
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];
}
if (!_messageLabel)
{
var bounds = [[_alertPanel contentView] bounds];
_messageLabel = [[CPTextField alloc] initWithFrame:CGRectMake(57.0, 10.0, CGRectGetWidth(bounds) - 73.0, 62.0)];
[_messageLabel setFont:[CPFont boldSystemFontOfSize:13.0]];
[_messageLabel setLineBreakMode:CPLineBreakByWordWrapping];
[_messageLabel setAlignment:CPJustifiedTextAlignment];
[_messageLabel setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
_alertImageView = [[CPImageView alloc] initWithFrame:CGRectMake(15.0, 12.0, 32.0, 32.0)];
}
[[_alertPanel contentView] addSubview:_messageLabel];
[[_alertPanel contentView] addSubview:_alertImageView];
}
/*!
set the theme to use
@param the theme to use
Sets the window's title. If this is not defined, a default title based on your warning level will be used.
@param aTitle the title to use in place of the default. Set to nil to use default.
*/
- (void)setTheme:(CPTheme)aTheme
- (void)setTitle:(CPString)aTitle
{
if (aTheme === [self theme])
return;
if (aTheme === [CPTheme defaultHudTheme])
_defaultWindowStyle = CPTitledWindowMask | CPHUDBackgroundWindowMask;
else
_defaultWindowStyle = CPTitledWindowMask;
_window = nil; // will be regenerated at next layout
_needsLayout = YES;
[super setTheme:aTheme];
_windowTitle = aTitle;
}
/*! @deprecated
/*!
Gets the window's title.
*/
- (void)setWindowStyle:(int)aStyle
- (CPString)title
{
CPLog.warn("DEPRECATED: setWindowStyle: is deprecated. use setTheme: instead");
[self setTheme:(aStyle === CPHUDBackgroundWindowMask) ? [CPTheme defaultHudTheme] : [CPTheme defaultTheme]];
return _windowTitle;
}
/*! @deprecated
/*!
Gets the window's style.
*/
- (int)windowStyle
{
CPLog.warn("DEPRECATED: windowStyle: is deprecated. use theme instead");
return _defaultWindowStyle;
return _windowStyle;
}
/*!
set the text of the alert's message
@param aText CPString containing the text
Sets the receivers delegate.
@param delegate - Delegate for the alert. nil removes the delegate.
*/
- (void)setMessageText:(CPString)aText
- (void)setDelegate:(id)delegate
{
[_messageLabel setStringValue:aText];
_needsLayout = YES;
_delegate = delegate;
}
/*!
return the content of the message text
@return CPString containing the message text
Gets the receiver's delegate.
*/
- (void)delegate
{
return _delegate;
}
/*!
Sets the alert style of the receiver.
@param style - Alert style for the alert.
*/
- (void)setAlertStyle:(CPAlertStyle)style
{
_alertStyle = style;
}
/*!
Gets the alert style.
*/
- (CPAlertStyle)alertStyle
{
return _alertStyle;
}
/*!
Sets the receivers message text, or title, to a given text.
@param messageText - Message text for the alert.
*/
- (void)setMessageText:(CPString)messageText
{
[_messageLabel setStringValue:messageText];
}
/*!
Return's the receiver's message text body.
*/
- (CPString)messageText
{
return [_messageLabel stringValue];
}
/*!
set the text of the alert's informative text
@param aText CPString containing the informative text
*/
- (void)setInformativeText:(CPString)aText
{
[_informativeLabel setStringValue:aText];
_needsLayout = YES;
}
/*!
return the content of the message text
@return CPString containing the message text
*/
- (CPString)informativeText
{
return [_informativeLabel stringValue];
}
/*!
Sets the title of the alert window.
This API is not present in Cocoa.
@param aTitle CPString containing the window title
*/
- (void)setTitle:(CPString)aTitle
{
_title = aTitle;
[_window setTitle:aTitle];
}
/*!
set the accessory view
@param aView the accessory view
*/
- (void)setAccessoryView:(CPView)aView
{
_accessoryView = aView;
_needsLayout = YES;
}
/*!
set if alert shows the suppression button
@param shouldShowSuppressionButton YES or NO
*/
- (void)setShowsSuppressionButton:(BOOL)shouldShowSuppressionButton
{
_showSuppressionButton = shouldShowSuppressionButton;
_needsLayout = YES;
}
#pragma mark Accessing Buttons
/*!
Adds a button with a given title to the receiver.
Buttons will be added starting from the right hand side of the \c CPAlert panel.
The first button will have the index 0, the second button 1 and so on.
The first button will automatically be given a key equivalent of Return,
and any button titled "Cancel" will be given a key equivalent of Escape.
You really shouldn't need more than 3 buttons.
@param title the title of the button
*/
- (void)addButtonWithTitle:(CPString)aTitle
- (void)addButtonWithTitle:(CPString)title
{
var bounds = [[_window contentView] bounds],
count = [_buttons count],
button = [[CPButton alloc] initWithFrame:CGRectMakeZero()];
[button setTitle:aTitle];
[button setTag:count];
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 setTitle:title];
[button setTarget:self];
[button setAction:@selector(_takeReturnCodeFrom:)];
[button setTag:_buttonCount];
[button setAction:@selector(_notifyDelegate:)];
[button setTheme:(_windowStyle === CPHUDBackgroundWindowMask) ? [CPTheme themeNamed:"Aristo-HUD"] : [CPTheme defaultTheme]];
[button setAutoresizingMask:CPViewMinXMargin | CPViewMinYMargin];
[[_window contentView] addSubview:button];
[[_alertPanel contentView] addSubview:button];
if (_buttonCount == 0)
[_alertPanel setDefaultButton:button];
if (count == 0)
[button setKeyEquivalent:CPCarriageReturnCharacter];
else if ([aTitle lowercaseString] === @"cancel")
[button setKeyEquivalent:CPEscapeFunctionKey];
[_buttons insertObject:button atIndex:0];
_buttonCount++;
[_buttons addObject:button];
}
#pragma mark Layout
/*!
@ignore
*/
- (void)_layoutMessageView
{
var inset = [self currentValueForThemeAttribute:@"content-inset"],
sizeWithFontCorrection = 6.0,
messageLabelWidth,
messageLabelTextSize;
[_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];
messageLabelWidth = CGRectGetWidth([[_window contentView] frame]) - inset.left - inset.right;
messageLabelTextSize = [[_messageLabel stringValue] sizeWithFont:[_messageLabel font] inWidth:messageLabelWidth];
[_messageLabel setFrame:CGRectMake(inset.left, inset.top, messageLabelTextSize.width, messageLabelTextSize.height + sizeWithFontCorrection)];
}
/*!
@ignore
*/
- (void)_layoutInformativeView
{
var inset = [self currentValueForThemeAttribute:@"content-inset"],
defaultElementsMargin = [self currentValueForThemeAttribute:@"default-elements-margin"],
sizeWithFontCorrection = 6.0,
informativeLabelWidth,
informativeLabelOriginY,
informativeLabelTextSize;
[_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 setAlignment:[self currentValueForThemeAttribute:@"informative-text-alignment"]];
[_informativeLabel setLineBreakMode:CPLineBreakByWordWrapping];
informativeLabelWidth = CGRectGetWidth([[_window contentView] frame]) - inset.left - inset.right,
informativeLabelOriginY = [_messageLabel frameOrigin].y + [_messageLabel frameSize].height + defaultElementsMargin,
informativeLabelTextSize = [[_informativeLabel stringValue] sizeWithFont:[_informativeLabel font] inWidth:informativeLabelWidth];
[_informativeLabel setFrame:CGRectMake(inset.left, informativeLabelOriginY, informativeLabelTextSize.width, informativeLabelTextSize.height + sizeWithFontCorrection)];
}
/*!
@ignore
*/
- (void)_layoutAccessoryView
{
if (!_accessoryView)
return;
var inset = [self currentValueForThemeAttribute:@"content-inset"],
defaultElementsMargin = [self currentValueForThemeAttribute:@"default-elements-margin"],
accessoryViewWidth = CGRectGetWidth([[_window contentView] frame]) - inset.left - inset.right,
accessoryViewOriginY = CGRectGetMaxY([_informativeLabel frame]) + defaultElementsMargin;
[_accessoryView setFrameOrigin:CGPointMake(inset.left, accessoryViewOriginY)];
[[_window contentView] addSubview:_accessoryView];
}
/*!
@ignore
*/
- (void)_layoutSuppressionButton
{
if (!_showSuppressionButton)
return;
var inset = [self currentValueForThemeAttribute:@"content-inset"],
suppressionViewXOffset = [self currentValueForThemeAttribute:@"suppression-button-x-offset"],
suppressionViewYOffset = [self currentValueForThemeAttribute:@"suppression-button-y-offset"],
defaultElementsMargin = [self currentValueForThemeAttribute:@"default-elements-margin"],
suppressionButtonViewOriginY = CGRectGetMaxY([(_accessoryView || _informativeLabel) frame]) + defaultElementsMargin + suppressionViewYOffset;
[_suppressionButton setTextColor:[self currentValueForThemeAttribute:@"suppression-button-text-color"]];
[_suppressionButton setFont:[self currentValueForThemeAttribute:@"suppression-button-text-font"]];
[_suppressionButton setTextShadowColor:[self currentValueForThemeAttribute:@"suppression-button-text-shadow-color"]];
[_suppressionButton setTextShadowOffset:[self currentValueForThemeAttribute:@"suppression-button-text-shadow-offset"]];
[_suppressionButton sizeToFit];
[_suppressionButton setFrameOrigin:CGPointMake(inset.left + suppressionViewXOffset, suppressionButtonViewOriginY)];
[[_window contentView] addSubview:_suppressionButton];
}
/*!
@ignore
*/
- (CGSize)_layoutButtonsFromView:(CPView)lastView
{
var inset = [self currentValueForThemeAttribute:@"content-inset"],
minimumSize = [self currentValueForThemeAttribute:@"size"],
buttonOffset = [self currentValueForThemeAttribute:@"button-offset"],
helpLeftOffset = [self currentValueForThemeAttribute:@"help-image-left-offset"],
aRepresentativeButton = [_buttons objectAtIndex:0],
defaultElementsMargin = [self currentValueForThemeAttribute:@"default-elements-margin"],
panelSize = [[_window contentView] frame].size,
buttonsOriginY,
offsetX;
[aRepresentativeButton setTheme:[self theme]];
[aRepresentativeButton sizeToFit];
panelSize.height = CGRectGetMaxY([lastView frame]) + defaultElementsMargin + [aRepresentativeButton frameSize].height;
if (panelSize.height < minimumSize.height)
panelSize.height = minimumSize.height;
buttonsOriginY = panelSize.height - [aRepresentativeButton frameSize].height + buttonOffset;
offsetX = panelSize.width - inset.right;
for (var i = [_buttons count] - 1; i >= 0 ; i--)
{
var button = _buttons[i];
[button setTheme:[self theme]];
[button sizeToFit];
var buttonFrame = [button frame],
width = MAX(80.0, CGRectGetWidth(buttonFrame)),
height = CGRectGetHeight(buttonFrame);
offsetX -= width;
[button setFrame:CGRectMake(offsetX, buttonsOriginY, width, height)];
offsetX -= 10;
}
if (_showHelp)
{
var helpImage = [self currentValueForThemeAttribute:@"help-image"],
helpImagePressed = [self currentValueForThemeAttribute:@"help-image-pressed"],
helpImageSize = helpImage ? [helpImage size] : CGSizeMakeZero(),
helpFrame = CGRectMake(helpLeftOffset, buttonsOriginY, helpImageSize.width, helpImageSize.height);
[_alertHelpButton setImage:helpImage];
[_alertHelpButton setAlternateImage:helpImagePressed];
[_alertHelpButton setBordered:NO];
[_alertHelpButton setFrame:helpFrame];
}
panelSize.height += [aRepresentativeButton frameSize].height + inset.bottom + buttonOffset;
return panelSize;
}
/*!
@ignore
*/
- (void)layout
{
if (!_needsLayout)
return;
if (!_window)
[self _createWindowWithStyle:nil];
var iconOffset = [self currentValueForThemeAttribute:@"image-offset"],
theImage = _icon,
finalSize;
if (!theImage)
switch (_alertStyle)
{
case CPWarningAlertStyle:
theImage = [self currentValueForThemeAttribute:@"warning-image"];
break;
case CPInformationalAlertStyle:
theImage = [self currentValueForThemeAttribute:@"information-image"];
break;
case CPCriticalAlertStyle:
theImage = [self currentValueForThemeAttribute:@"error-image"];
break;
}
[_alertImageView setImage:theImage];
var imageSize = theImage ? [theImage size] : CGSizeMakeZero();
[_alertImageView setFrame:CGRectMake(iconOffset.x, iconOffset.y, imageSize.width, imageSize.height)];
[self _layoutMessageView];
[self _layoutInformativeView];
[self _layoutAccessoryView];
[self _layoutSuppressionButton];
var lastView = _informativeLabel;
if (_showSuppressionButton)
lastView = _suppressionButton;
else if (_accessoryView)
lastView = _accessoryView
finalSize = [self _layoutButtonsFromView:lastView];
if ([_window styleMask] & CPDocModalWindowMask)
finalSize.height -= 26; // adjust the absence of title bar
[_window setFrameSize:finalSize];
[_window center];
_needsLayout = NO;
}
#pragma mark Displaying Alerts
/*!
Displays the \c CPAlert panel as a modal dialog. The user will not be
able to interact with any other controls until s/he has dismissed the alert
@@ -540,167 +283,34 @@ CPCriticalAlertStyle = 2;
*/
- (void)runModal
{
if (!([_window styleMask] & _defaultWindowStyle))
var theTitle;
switch (_alertStyle)
{
_needsLayout = YES;
[self _createWindowWithStyle:_defaultWindowStyle];
case CPWarningAlertStyle: [_alertImageView setImage:CPAlertWarningImage];
theTitle = @"Warning";
break;
case CPInformationalAlertStyle: [_alertImageView setImage:CPAlertInformationImage];
theTitle = @"Information";
break;
case CPCriticalAlertStyle: [_alertImageView setImage:CPAlertErrorImage];
theTitle = @"Error";
break;
}
[self layout];
[CPApp runModalForWindow:_window];
[_alertPanel setTitle:_windowTitle ? _windowTitle : theTitle];
[CPApp runModalForWindow:_alertPanel];
}
/*!
Runs the receiver modally as an alert sheet attached to a specified window.
@param window The parent window for the sheet.
@param modalDelegate The delegate for the modal-dialog session.
@param alertDidEndSelector Message the alert sends to modalDelegate after the sheet is dismissed.
@param contextInfo Contextual data passed to modalDelegate in didEndSelector message.
*/
- (void)beginSheetModalForWindow:(CPWindow)aWindow modalDelegate:(id)modalDelegate didEndSelector:(SEL)alertDidEndSelector contextInfo:(id)contextInfo
/* @ignore */
- (void)_notifyDelegate:(id)button
{
if (!([_window styleMask] & CPDocModalWindowMask))
{
_needsLayout = YES;
[self _createWindowWithStyle:CPDocModalWindowMask];
}
[CPApp abortModal];
[_alertPanel close];
[self layout];
_modalDelegate = modalDelegate;
_didEndSelector = alertDidEndSelector;
[CPApp beginSheet:_window modalForWindow:aWindow 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)aWindow
{
[self beginSheetModalForWindow:aWindow modalDelegate:nil didEndSelector:nil contextInfo:nil];
}
#pragma mark Private
/*!
@ignore
*/
- (void)_createWindowWithStyle:(int)forceStyle
{
var frame = CGRectMakeZero();
frame.size = [self currentValueForThemeAttribute:@"size"];
_window = [[CPWindow alloc] initWithContentRect:frame styleMask:forceStyle || _defaultWindowStyle];
if (_title)
[_window setTitle:_title];
var contentView = [_window contentView],
count = [_buttons count];
if (count)
while (count--)
[contentView addSubview:_buttons[count]];
else
[self addButtonWithTitle:@"OK"];
[contentView addSubview:_messageLabel];
[contentView addSubview:_alertImageView];
[contentView addSubview:_informativeLabel];
if (_showHelp)
[contentView addSubview:_alertHelpButton];
}
/*!
@ignore
*/
- (@action)_showHelp:(id)aSender
{
if ([_delegate respondsToSelector:@selector(alertShowHelp:)])
[_delegate alertShowHelp:self];
}
/*
@ignore
*/
- (@action)_takeReturnCodeFrom:(id)aSender
{
if ([_window isSheet])
[CPApp endSheet:_window returnCode:[aSender tag]];
else
{
[CPApp abortModal];
[_window close];
[self _alertDidEnd:_window returnCode:[aSender tag] contextInfo:nil];
}
}
/*!
@ignore
*/
- (void)_alertDidEnd:(CPWindow)aWindow returnCode:(int)returnCode contextInfo:(id)contextInfo
{
if ([_delegate respondsToSelector:@selector(alertDidEnd:returnCode:)])
[_delegate alertDidEnd:self returnCode:returnCode];
if (_didEndSelector)
objj_msgSend(_modalDelegate, _didEndSelector, self, returnCode, contextInfo);
_modalDelegate = nil;
_didEndSelector = nil;
}
#pragma mark Theme Attributes
+ (CPString)defaultThemeClass
{
return @"alert";
}
+ (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],
[CPNull null],
[CPNull null],
[CPNull null],
0.0,
0.0,
3.0,
[CPColor blackColor],
[CPFont systemFontOfSize:12.0],
[CPNull null],
0.0
]
forKeys:[@"size", @"content-inset", @"informative-offset", @"button-offset",
@"message-text-alignment", @"message-text-color", @"message-text-font", @"message-text-shadow-color", @"message-text-shadow-offset",
@"informative-text-alignment", @"informative-text-color", @"informative-text-font", @"informative-text-shadow-color", @"informative-text-shadow-offset",
@"image-offset",
@"information-image",
@"warning-image",
@"error-image",
@"help-image",
@"help-image-left-offset",
@"help-image-pressed",
@"suppression-button-y-offset",
@"suppression-button-x-offset",
@"default-elements-margin",
@"suppression-button-text-color",
@"suppression-button-text-font",
@"suppression-button-text-shadow-color",
@"suppression-button-text-shadow-offset"
]];
if (_delegate && [_delegate respondsToSelector:@selector(alertDidEnd:returnCode:)])
[_delegate alertDidEnd:self returnCode:[button tag]];
}
@end
+40 -117
View File
@@ -21,7 +21,6 @@
*/
@import <Foundation/CPObject.j>
@import <Foundation/CPTimer.j>
@import "CAMediaTimingFunction.j"
@@ -49,14 +48,14 @@ CPAnimationLinear = 3;
ACTUAL_FRAME_RATE = 0;
/*!
/*!
@ingroup appkit
@class CPAnimation
Manages an animation. Contains timing and progress information.
@par Delegate Methods
@delegate -(BOOL)animationShouldStart:(CPAnimation)animation;
Called at the beginning of \c -startAnimation.
@param animation the animation that will start
@@ -82,13 +81,13 @@ ACTUAL_FRAME_RATE = 0;
{
CPTimeInterval _lastTime;
CPTimeInterval _duration;
CPAnimationCurve _animationCurve;
CAMediaTimingFunction _timingFunction;
float _frameRate;
float _progress;
id _delegate;
CPTimer _timer;
}
@@ -102,7 +101,7 @@ ACTUAL_FRAME_RATE = 0;
- (id)initWithDuration:(float)aDuration animationCurve:(CPAnimationCurve)anAnimationCurve
{
self = [super init];
if (self)
{
_progress = 0.0;
@@ -111,14 +110,14 @@ ACTUAL_FRAME_RATE = 0;
[self setAnimationCurve:anAnimationCurve];
}
return self;
}
/*!
Sets the animation's pace.
@param anAnimationCurve the animation's pace
@throws CPInvalidArgumentException if an invalid animation curve is specified
@throws CPInvalidArgumentException if an invalid animation curve is specified
*/
- (void)setAnimationCurve:(CPAnimationCurve)anAnimationCurve
{
@@ -126,13 +125,13 @@ ACTUAL_FRAME_RATE = 0;
{
case CPAnimationEaseInOut: timingFunctionName = kCAMediaTimingFunctionEaseInEaseOut;
break;
case CPAnimationEaseIn: timingFunctionName = kCAMediaTimingFunctionEaseIn;
break;
case CPAnimationEaseOut: timingFunctionName = kCAMediaTimingFunctionEaseOut;
break;
case CPAnimationLinear: timingFunctionName = kCAMediaTimingFunctionLinear;
break;
@@ -140,7 +139,7 @@ ACTUAL_FRAME_RATE = 0;
reason:"Invalid value provided for animation curve"];
break;
}
_animationCurve = anAnimationCurve;
_timingFunction = [CAMediaTimingFunction functionWithName:timingFunctionName];
}
@@ -162,7 +161,7 @@ ACTUAL_FRAME_RATE = 0;
{
if (aDuration < 0)
[CPException raise:CPInvalidArgumentException reason:"aDuration can't be negative"];
_duration = aDuration;
}
@@ -183,7 +182,7 @@ ACTUAL_FRAME_RATE = 0;
{
if (frameRate < 0)
[CPException raise:CPInvalidArgumentException reason:"frameRate can't be negative"];
_frameRate = frameRate;
}
@@ -222,13 +221,13 @@ ACTUAL_FRAME_RATE = 0;
// If we're already animating, or our delegate stops us, animate.
if (_timer || _delegate && [_delegate respondsToSelector:@selector(animationShouldStart:)] && ![_delegate animationShouldStart:self])
return;
if (_progress === 1.0)
_progress = 0.0;
ACTUAL_FRAME_RATE = 0;
_lastTime = new Date();
_timer = [CPTimer scheduledTimerWithTimeInterval:0.0 target:self selector:@selector(animationTimerDidFire:) userInfo:nil repeats:YES];
}
@@ -243,14 +242,14 @@ ACTUAL_FRAME_RATE = 0;
_lastTime = currentTime;
++ACTUAL_FRAME_RATE;
[self setCurrentProgress:progress];
if (progress === 1.0)
{
[_timer invalidate];
_timer = nil;
if ([_delegate respondsToSelector:@selector(animationDidEnd:)])
[_delegate animationDidEnd:self];
}
@@ -263,10 +262,10 @@ ACTUAL_FRAME_RATE = 0;
{
if (!_timer)
return;
[_timer invalidate];
_timer = nil;
if ([_delegate respondsToSelector:@selector(animationDidStop:)])
[_delegate animationDidStop:self];
}
@@ -303,17 +302,17 @@ ACTUAL_FRAME_RATE = 0;
- (float)currentValue
{
var t = [self currentProgress];
if ([_delegate respondsToSelector:@selector(animation:valueForProgress:)])
return [_delegate animation:self valueForProgress:t];
var c1 = [],
c2 = [];
[_timingFunction getControlPointAtIndex:1 values:c1];
[_timingFunction getControlPointAtIndex:2 values:c2];
return CubicBezierAtTime(t, c1[0], c1[1], c2[0], c2[1], _duration);
return CubicBezierAtTime(t,c1[0],c1[1],c2[0],c2[1],_duration);
}
@end
@@ -321,104 +320,28 @@ ACTUAL_FRAME_RATE = 0;
// currently used function to determine time
// 1:1 conversion to js from webkit source files
// UnitBezier.h, WebCore_animation_AnimationBase.cpp
var CubicBezierAtTime = function CubicBezierAtTime(t, p1x, p1y, p2x, p2y, duration)
var CubicBezierAtTime = function CubicBezierAtTime(t,p1x,p1y,p2x,p2y,duration)
{
var ax = 0,
bx = 0,
cx = 0,
ay = 0,
by = 0,
cy = 0;
var ax=0,bx=0,cx=0,ay=0,by=0,cy=0;
// `ax t^3 + bx t^2 + cx t' expanded using Horner's rule.
function sampleCurveX(t)
{
return ((ax * t + bx) * t + cx) * t;
}
function sampleCurveY(t)
{
return ((ay * t + by) * t + cy) * t;
}
function sampleCurveDerivativeX(t)
{
return (3.0 * ax * t + 2.0 * bx) * t + cx;
}
function sampleCurveX(t) {return ((ax*t+bx)*t+cx)*t;};
function sampleCurveY(t) {return ((ay*t+by)*t+cy)*t;};
function sampleCurveDerivativeX(t) {return (3.0*ax*t+2.0*bx)*t+cx;};
// The epsilon value to pass given that the animation is going to run over |duration| seconds. The longer the animation, the more precision is needed in the timing function result to avoid ugly discontinuities.
function solveEpsilon(duration)
{
return 1.0 / (200.0 * duration);
}
function solve(x, epsilon)
{
return sampleCurveY(solveCurveX(x, epsilon));
}
function solveEpsilon(duration) {return 1.0/(200.0*duration);};
function solve(x,epsilon) {return sampleCurveY(solveCurveX(x,epsilon));};
// Given an x value, find a parametric value it came from.
function solveCurveX(x, epsilon)
{
var t0,
t1,
t2 = x,
x2,
d2,
i = 0;
function solveCurveX(x,epsilon) {var t0,t1,t2,x2,d2,i;
function fabs(n) {if(n>=0) {return n;}else {return 0-n;}};
// First try a few iterations of Newton's method -- normally very fast.
for (; i < 8; i++)
{
x2 = sampleCurveX(t2) - x;
if (ABS(x2) < epsilon)
return t2;
d2 = sampleCurveDerivativeX(t2);
if (ABS(d2) < 1e-6)
break;
t2 = t2 - x2 / d2;
}
for(t2=x, i=0; i<8; i++) {x2=sampleCurveX(t2)-x; if(fabs(x2)<epsilon) {return t2;} d2=sampleCurveDerivativeX(t2); if(fabs(d2)<1e-6) {break;} t2=t2-x2/d2;}
// Fall back to the bisection method for reliability.
t0 = 0.0;
t1 = 1.0;
t2 = x;
if (t2 < t0)
return t0;
if (t2 > t1)
return t1;
while (t0 < t1)
{
x2 = sampleCurveX(t2);
if (ABS(x2 - x) < epsilon)
return t2;
if (x > x2)
t0 = t2;
else
t1 = t2;
t2 = (t1 - t0) * 0.5 + t0;
}
t0=0.0; t1=1.0; t2=x; if(t2<t0) {return t0;} if(t2>t1) {return t1;}
while(t0<t1) {x2=sampleCurveX(t2); if(fabs(x2-x)<epsilon) {return t2;} if(x>x2) {t0=t2;}else {t1=t2;} t2=(t1-t0)*.5+t0;}
return t2; // Failure.
};
// Calculate the polynomial coefficients, implicit first and last control points are (0,0) and (1,1).
cx = 3.0 * p1x;
bx = 3.0 * (p2x - p1x) - cx;
ax = 1.0 - cx - bx;
cy = 3.0 * p1y;
by = 3.0 * (p2y - p1y) - cy;
ay = 1.0 - cy - by;
cx=3.0*p1x; bx=3.0*(p2x-p1x)-cx; ax=1.0-cx-bx; cy=3.0*p1y; by=3.0*(p2y-p1y)-cy; ay=1.0-cy-by;
// Convert from input time to parametric value in curve, then from that to output time.
return solve(t, solveEpsilon(duration));
};
+29 -214
View File
@@ -31,6 +31,7 @@
@import "CPCibLoading.j"
@import "CPPlatform.j"
#include "Platform/Platform.h"
var CPMainCibFile = @"CPMainCibFile",
CPMainCibFileHumanFriendly = @"Main cib file base name";
@@ -57,7 +58,7 @@ CPRunContinuesResponse = -1002;
@ingroup appkit
@class CPApplication
CPApplication is THE way to start up the Cappuccino framework for your application to use.
CPApplication is THE way to start up the Cappucino framework for your application to use.
Every GUI application has exactly one instance of CPApplication (or of a custom subclass of
CPApplication). Your program's main() function can create that instance by calling the
\c CPApplicationMain function. A simple example looks like this:
@@ -90,6 +91,7 @@ CPRunContinuesResponse = -1002;
CPWindow _previousKeyWindow;
CPWindow _previousMainWindow;
CPMenu _mainMenu;
CPDocumentController _documentController;
CPModalSession _currentSession;
@@ -106,8 +108,6 @@ CPRunContinuesResponse = -1002;
CPImage _applicationIconImage;
CPPanel _aboutPanel;
CPArray _themeBlends @accessors(property=themeBlends);
}
/*!
@@ -141,8 +141,6 @@ CPRunContinuesResponse = -1002;
_windows = [];
[_windows addObject:nil];
_themeBlends = [];
}
return self;
@@ -294,21 +292,11 @@ CPRunContinuesResponse = -1002;
}
}
/*!
Sets the applications icon image. This image is used in the default "About" window.
By default this value is pulled from the CPApplicationIcon key in your info.plist file.
@param anImage - The image to set.
*/
- (void)setApplicationIconImage:(CPImage)anImage
{
_applicationIconImage = anImage;
}
/*!
Returns the application icon image. By default this is pulled from the CPApplicationIcon key of info.plist.
@return CPImage - Your application icon image.
*/
- (CPImage)applicationIconImage
{
if (_applicationIconImage)
@@ -321,38 +309,11 @@ CPRunContinuesResponse = -1002;
return _applicationIconImage;
}
/*!
Opens the standard about panel with no options.
*/
- (void)orderFrontStandardAboutPanel:(id)sender
{
[self orderFrontStandardAboutPanelWithOptions:nil];
}
/*!
Opens the standard about panel. This method takes a single argument \c options.
Options is a dictionary that can contain any of the following keys:
<pre>
ApplicationName - The name of your application.
ApplicationIcon - Application icon image.
Version - The full version of your application
ApplicationVersion - The shorter version number of your application.
Copyright - Human readable copyright information.
</pre>
If you choose not the include any of the above keys, they will default
to the following respective keys in your info.plist file.
<pre>
CPBundleName
CPApplicationIcon (through a call to -applicationIconImage, see documentation for that method for more details)
CPBundleVersion
CPBundleShortVersionString
CPHumanReadableCopyright
</pre>
@param options - A dictionary with the aboe listed keys. You can pass nil to default to your plist values.
*/
- (void)orderFrontStandardAboutPanelWithOptions:(CPDictionary)options
{
if (!_aboutPanel)
@@ -364,9 +325,7 @@ CPRunContinuesResponse = -1002;
applicationVersion = [options objectForKey:@"ApplicationVersion"] || [mainInfo objectForKey:@"CPBundleShortVersionString"],
copyright = [options objectForKey:@"Copyright"] || [mainInfo objectForKey:@"CPHumanReadableCopyright"];
var aboutPanelPath = [[CPBundle bundleForClass:[CPWindowController class]] pathForResource:@"AboutPanel.cib"],
aboutPanelController = [CPWindowController alloc],
aboutPanelController = [aboutPanelController initWithWindowCibPath:aboutPanelPath owner:aboutPanelController],
var aboutPanelController = [[CPWindowController alloc] initWithWindowCibName:@"AboutPanel"],
aboutPanel = [aboutPanelController window],
contentView = [aboutPanel contentView],
imageView = [contentView viewWithTag:1],
@@ -544,8 +503,7 @@ CPRunContinuesResponse = -1002;
var theWindow = aModalSession._window;
[theWindow center];
[theWindow makeKeyWindow];
[theWindow orderFront:self];
[theWindow makeKeyAndOrderFront:self];
// [theWindow._bridge _obscureWindowsBelowModalWindow];
@@ -568,7 +526,7 @@ CPRunContinuesResponse = -1002;
- (BOOL)_handleKeyEquivalent:(CPEvent)anEvent
{
return [[self keyWindow] performKeyEquivalent:anEvent] ||
[[self mainMenu] performKeyEquivalent:anEvent];
[_mainMenu performKeyEquivalent:anEvent];
}
/*!
@@ -612,10 +570,6 @@ CPRunContinuesResponse = -1002;
[[anEvent window] sendEvent:anEvent];
}
/*!
If the delegate responds to the given selector it will call the method on the delegate,
otherwise the method will be passed to CPResponder.
*/
- (void)doCommandBySelector:(SEL)aSelector
{
if ([_delegate respondsToSelector:aSelector])
@@ -661,11 +615,7 @@ CPRunContinuesResponse = -1002;
*/
- (CPArray)orderedWindows
{
#if PLATFORM(DOM)
return CPWindowObjectList();
#else
return [];
#endif
}
- (void)hide:(id)aSender
@@ -679,7 +629,7 @@ CPRunContinuesResponse = -1002;
*/
- (CPMenu)mainMenu
{
return [self menu];
return _mainMenu;
}
/*!
@@ -687,30 +637,21 @@ CPRunContinuesResponse = -1002;
@param aMenu the menu to set for the application
*/
- (void)setMainMenu:(CPMenu)aMenu
{
[self setMenu:aMenu];
}
- (void)setMenu:(CPMenu)aMenu
{
if ([aMenu _menuName] === "CPMainMenu")
{
if ([self menu] === aMenu)
if (_mainMenu === aMenu)
return;
[super setMenu:aMenu];
_mainMenu = aMenu;
if ([CPPlatform supportsNativeMainMenu])
window.cpSetMainMenu([self menu]);
window.cpSetMainMenu(_mainMenu);
}
else
[aMenu _setMenuName:@"CPMainMenu"];
}
/*!
Opens the shared color panel.
@param aSender
*/
- (void)orderFrontColorPanel:(id)aSender
{
[[CPColorPanel sharedColorPanel] orderFront:self];
@@ -734,7 +675,7 @@ CPRunContinuesResponse = -1002;
if ([super tryToPerform:anAction with:anObject])
return YES;
if ([_delegate respondsToSelector:anAction])
if([_delegate respondsToSelector:anAction])
{
[_delegate performSelector:anAction withObject:anObject];
@@ -879,38 +820,16 @@ CPRunContinuesResponse = -1002;
return nil;
}
/*!
Fires a callback function when an event matching a given mask occurs.
@param aCallback - A js function to be fired.
@prarm aMask - An event mask for the next event.
@param anExpiration - The date for which this callback expires (not implemented).
@param inMode (not implemented).
@param shouldDequeue (not implemented).
*/
- (void)setCallback:(Function)aCallback forNextEventMatchingMask:(unsigned int)aMask untilDate:(CPDate)anExpiration inMode:(CPString)aMode dequeue:(BOOL)shouldDequeue
{
_eventListeners.push(_CPEventListenerMake(aMask, aCallback));
}
/*!
Assigns a target and action for the next event matching a given event mask.
The callback method called will be passed the CPEvent when it fires.
@param aTarget - The target object for the callback.
@param aSelector - The selector which should be called on the target object.
@param aMask - The mask for a given event which should trigger the callback.
@param anExpiration - The date for which the callback expires (not implemented).
@param aMode (not implemented).
@param shouldDequeue (not implemented).
*/
- (void)setTarget:(id)aTarget selector:(SEL)aSelector forNextEventMatchingMask:(unsigned int)aMask untilDate:(CPDate)anExpiration inMode:(CPString)aMode dequeue:(BOOL)shouldDequeue
- (CPEvent)setTarget:(id)aTarget selector:(SEL)aSelector forNextEventMatchingMask:(unsigned int)aMask untilDate:(CPDate)anExpiration inMode:(CPString)aMode dequeue:(BOOL)shouldDequeue
{
_eventListeners.push(_CPEventListenerMake(aMask, function (anEvent) { objj_msgSend(aTarget, aSelector, anEvent); }));
}
/*!
Returns the last event recieved by your application.
*/
- (CPEvent)currentEvent
{
return _currentEvent;
@@ -936,31 +855,17 @@ CPRunContinuesResponse = -1002;
}
[aWindow orderFront:self];
[aSheet setPlatformWindow:[aWindow platformWindow]];
[aWindow _attachSheet:aSheet modalDelegate:aModalDelegate didEndSelector:aDidEndSelector contextInfo:aContextInfo];
}
/*!
Ends a sheet modal.
The following are predefined return codes:
<pre>
CPRunStoppedResponse
CPRunAbortedResponse
CPRunContinuesResponse
</pre>
@param sheet - The window object (sheet) to dismiss.
@param returnCode - The return code to send to the delegate. You can use one of the return codes above or a custom value that you define.
*/
- (void)endSheet:(CPWindow)sheet returnCode:(int)returnCode
{
var count = [_windows count];
while (--count >= 0)
{
var aWindow = [_windows objectAtIndex:count],
context = aWindow._sheetContext;
var aWindow = [_windows objectAtIndex:count];
var context = aWindow._sheetContext;
if (context != nil && context["sheet"] === sheet)
{
@@ -971,58 +876,22 @@ CPRunContinuesResponse = -1002;
}
}
/*!
Ends a sheet and sends the return code "0".
@param sheet - The CPWindow object (sheet) that should be dismissed.
*/
- (void)endSheet:(CPWindow)sheet
{
// FIX ME: this is wrong: by Cocoa this should be: CPRunStoppedResponse.
[self endSheet:sheet returnCode:0];
}
/*!
Returns and array of slash seperated arugments to your application.
These values are pulled from your window location hash.
For exampled if your application loaded:
<pre>
index.html#280north/cappuccino/issues
</pre>
The follow array would be returned:
<pre>
["280north", "cappuccino", "issues"]
</pre>
@return CPArray - The array of arguments.
*/
- (CPArray)arguments
{
if (_fullArgsString !== window.location.hash)
if(_fullArgsString !== window.location.hash)
[self _reloadArguments];
return _args;
}
/*!
Sets the arguments of your application.
That is, set the slash seperated values of an array as the window location hash.
For example if you pass an array:
<pre>
["280north", "cappuccino", "issues"]
</pre>
The new window location would be
<pre>
index.html#280north/cappuccino/issues
</pre>
@param args - An array of arguments.
*/
- (void)setArguments:(CPArray)args
{
if (!args || args.length == 0)
if(!args || args.length == 0)
{
_args = [];
window.location.hash = @"#";
@@ -1030,13 +899,13 @@ CPRunContinuesResponse = -1002;
return;
}
if (![args isKindOfClass:CPArray])
if([args class] != CPArray)
args = [CPArray arrayWithObject:args];
_args = args;
var toEncode = [_args copy];
for (var i = 0, count = toEncode.length; i < count; i++)
for(var i=0, count = toEncode.length; i<count; i++)
toEncode[i] = encodeURIComponent(toEncode[i]);
var hash = [toEncode componentsJoinedByString:@"/"];
@@ -1061,23 +930,6 @@ CPRunContinuesResponse = -1002;
_args = [];
}
/*!
Returns a dictionary of the window location named arguments.
For example if your location was:
<pre>
index.html?owner=280north&repo=cappuccino&type=issues
</pre>
a CPDictionary with the keys:
<pre>
owner, repo, type
</pre>
and respective values:
<pre>
280north, cappuccino, issues
</pre>
Will be returned.
*/
- (CPDictionary)namedArguments
{
return _namedArgs;
@@ -1158,18 +1010,9 @@ CPRunContinuesResponse = -1002;
userInfo:nil];
}
- (CPThemeBlend)themeBlend
{
return (_themeBlends.length > 0 ? _themeBlends[0] : nil);
}
- (void)setThemeBlend:(CPThemeBlend)aThemeBlend
{
_themeBlends[0] = aThemeBlend;
}
+ (CPString)defaultThemeName
{
// FIXME: don't hardcode
return ([[CPBundle mainBundle] objectForInfoDictionaryKey:"CPDefaultTheme"] || @"Aristo");
}
@@ -1185,8 +1028,7 @@ var _CPEventListenerMake = function(anEventMask, aCallback)
return { _mask:anEventMask, _callback:aCallback };
}
// Make this a global for use in CPPlatformWindow+DOM.j.
_CPRunModalLoop = function(anEvent)
var _CPRunModalLoop = function(anEvent)
{
[CPApp setCallback:_CPRunModalLoop forNextEventMatchingMask:CPAnyEventMask untilDate:nil inMode:0 dequeue:NO];
@@ -1230,14 +1072,15 @@ function CPApplicationMain(args, namedArgs)
[_CPAppBootstrapper performActions];
}
var _CPAppBootstrapperActions = nil,
_CPAppThemeURLsToLoad = [];
var _CPAppBootstrapperActions = nil;
@implementation _CPAppBootstrapper : CPObject
{
}
+ (CPArray)actions
{
return [@selector(bootstrapPlatform), @selector(loadThemes), @selector(loadMainCibFile)];
return [@selector(bootstrapPlatform), @selector(loadDefaultTheme), @selector(loadMainCibFile)];
}
+ (void)performActions
@@ -1261,29 +1104,9 @@ var _CPAppBootstrapperActions = nil,
return [CPPlatform bootstrap];
}
+ (BOOL)loadThemes
+ (BOOL)loadDefaultTheme
{
_CPAppThemeURLsToLoad.push([CPApplication defaultThemeName]);
var auxiliaryThemes = ([[CPBundle mainBundle] objectForInfoDictionaryKey:@"CPAuxiliaryThemes"] || []);
_CPAppThemeURLsToLoad = _CPAppThemeURLsToLoad.concat(auxiliaryThemes);
[self loadNextTheme];
return YES;
}
+ (BOOL)loadNextTheme
{
var themeName = _CPAppThemeURLsToLoad.shift();
if (themeName === @"Aristo")
themeURL = [[CPBundle bundleForClass:[CPApplication class]] pathForResource:themeName + @".blend"];
else
themeURL = [[CPBundle mainBundle] pathForResource:themeName + @".blend"];
var blend = [[CPThemeBlend alloc] initWithContentsOfURL:themeURL];
var blend = [[CPThemeBlend alloc] initWithContentsOfURL:[[CPBundle bundleForClass:[CPApplication class]] pathForResource:[CPApplication defaultThemeName] + ".blend"]];
[blend loadWithDelegate:self];
@@ -1292,17 +1115,9 @@ var _CPAppBootstrapperActions = nil,
+ (void)blendDidFinishLoading:(CPThemeBlend)aThemeBlend
{
var themeBlends = [CPApp themeBlends];
[CPTheme setDefaultTheme:[CPTheme themeNamed:[CPApplication defaultThemeName]]];
[themeBlends addObject:aThemeBlend];
if ([themeBlends count] === 1)
[CPTheme setDefaultTheme:[CPTheme themeNamed:[CPApplication defaultThemeName]]];
if (_CPAppThemeURLsToLoad.length === 0)
[self performActions];
else
[self loadNextTheme];
[self performActions];
}
+ (BOOL)loadMainCibFile
@@ -1397,7 +1212,7 @@ var _CPAppBootstrapperActions = nil,
+ (void)reset
{
_CPAppBootstrapperActions = nil;
_CPAppBootstrapperActions = nil;
}
@end
File diff suppressed because it is too large Load Diff
+12 -13
View File
@@ -4,7 +4,7 @@
* Created by Ross Boucher.
* Copyright 2009, 280 North, Inc.
*
* Adapted from Kevin Wojniak, portions Copyright 2009 Kevin Wojniak.
* Adapted from Kevin Wojniak, portions Copyright 2009 Kevin Wojniak.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -20,27 +20,26 @@
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
* Copyright 2009 280 North, Inc.
*/
@import <AppKit/CPGraphicsContext.j>
@import <Foundation/CPObject.j>
@import "CPGraphicsContext.j"
// Class defaults
var DefaultLineWidth = 1.0;
/*!
/*!
@ingroup appkit
@class CPBezierPath
A CPBezierPath allows you to create paths for drawing to the screen using a simpler API than CoreGraphics.
Paths can form any shape, including regular polygons like squares and triangles; circles, arcs; or complex
line segments.
Paths can form any shape, including regular polgyons like squares and triangles; circles, arcs; or complex
line segments.
A path can be stroked and filled using the relevant method. The currently active fill and stroke color will
be used, which can be set by calling setFill: and setStroke: on any CPColor object (or set: for both).
*/
@@ -65,9 +64,9 @@ var DefaultLineWidth = 1.0;
+ (CPBezierPath)bezierPathWithOvalInRect:(CGRect)rect
{
var path = [self bezierPath];
[path appendBezierPathWithOvalInRect:rect];
return path;
}
@@ -77,9 +76,9 @@ var DefaultLineWidth = 1.0;
+ (CPBezierPath)bezierPathWithRect:(CGRect)rect
{
var path = [self bezierPath];
[path appendBezierPathWithRect:rect];
return path;
}
@@ -184,6 +183,7 @@ var DefaultLineWidth = 1.0;
CGContextBeginPath(ctx);
CGContextAddPath(ctx, _path);
CGContextSetLineWidth(ctx, [self lineWidth]);
CGContextClosePath(ctx);
CGContextStrokePath(ctx);
}
@@ -280,7 +280,6 @@ var DefaultLineWidth = 1.0;
{
CGPathAddPath(_path, nil, other._path);
}
/*!
Remove all path elements; clears path.
*/
+53 -243
View File
@@ -19,39 +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"
// CPBoxType
CPBoxPrimary = 0;
CPBoxSecondary = 1;
CPBoxSeparator = 2;
CPBoxOldStyle = 3;
CPBoxCustom = 4;
// CPBorderType
CPNoBorder = 0;
CPLineBorder = 1;
CPLineBorder = 1;
CPBezelBorder = 2;
CPGrooveBorder = 3;
/*!
@ingroup appkit
@class CPBox
A CPBox is a simple view which can display a border.
*/
@implementation CPBox : CPView
{
CPBoxType _boxType;
CPBorderType _borderType;
CPColor _borderColor;
CPColor _fillColor;
float _cornerRadius;
float _borderWidth;
CPSize _contentMargin;
CPView _contentView;
}
@@ -64,19 +50,18 @@ 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];
@@ -84,9 +69,7 @@ CPGrooveBorder = 3;
_contentMargin = CGSizeMake(0.0, 0.0);
_contentView = [[CPView alloc] initWithFrame:[self bounds]];
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
[self setAutoresizesSubviews:YES];
[self addSubview:_contentView];
}
@@ -95,96 +78,19 @@ CPGrooveBorder = 3;
// Configuring Boxes
/*!
Returns the receiver's border rectangle.
@return the border rectangle of the box
*/
- (CPRect)borderRect
{
return [self bounds];
}
/*!
Returns the receiver's border type. Possible values are:
<pre>
CPNoBorder
CPLineBorder
CPBezelBorder
CPGrooveBorder
</pre>
@return the border type of the box
*/
- (CPBorderType)borderType
{
return _borderType;
}
/*!
Sets the receiver's border type. Valid values are:
<pre>
CPNoBorder
CPLineBorder
CPBezelBorder
CPGrooveBorder
</pre>
@param borderType the border type to use
*/
- (void)setBorderType:(CPBorderType)aBorderType
- (void)setBorderType:(CPBorderType)value
{
if (_borderType === aBorderType)
return;
_borderType = aBorderType;
[self setNeedsDisplay:YES];
}
/*!
Returns the receiver's box type. Possible values are:
<pre>
CPBoxPrimary
CPBoxSecondary
CPBoxSeparator
CPBoxOldStyle
CPBoxCustom
</pre>
(In the current implementation, all values act the same except CPBoxSeparator.)
@return the box type of the box.
*/
- (CPBoxType)boxType
{
return _boxType;
}
/*!
Sets the receiver's box type. Valid values are:
<pre>
CPBoxPrimary
CPBoxSecondary
CPBoxSeparator
CPBoxOldStyle
CPBoxCustom
</pre>
(In the current implementation, all values act the same except CPBoxSeparator.)
@param aBoxType the box type of the box.
*/
- (void)setBoxType:(CPBoxType)aBoxType
{
if (_boxType === aBoxType)
return;
_boxType = aBoxType;
_borderType = value;
[self setNeedsDisplay:YES];
}
@@ -255,10 +161,9 @@ 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
@@ -268,9 +173,9 @@ CPGrooveBorder = 3;
- (void)setContentViewMargins:(CPSize)size
{
if (size.width < 0 || size.height < 0)
if(size.width < 0 || size.height < 0)
[CPException raise:CPGenericException reason:@"Margins must be positive"];
_contentMargin = CGSizeMakeCopy(size);
[self setNeedsDisplay:YES];
}
@@ -284,151 +189,56 @@ 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,
var bounds = [self bounds];
strokeRect = CGRectMake(bounds.origin.x + border2,
bounds.origin.y + border2,
bounds.size.width - _borderWidth,
bounds.size.height - _borderWidth),
fillRect = CGRectMake(bounds.origin.x + border2,
bounds.origin.y + border2,
bounds.size.width - _borderWidth,
bounds.size.height - _borderWidth);
switch (_boxType)
CGContextSetFillColor(aContext, [self fillColor]);
CGContextSetStrokeColor(aContext, [self borderColor]);
CGContextSetLineWidth(aContext, _borderWidth);
switch(_borderType)
{
case CPBoxSeparator:
// NSBox does not include a horizontal flag for the separator type. We have to determine
// the type of separator to draw by the width and height of the frame.
if (CGRectGetWidth(bounds) === 5.0)
return [self _drawVerticalSeperatorInRect:bounds];
else if (CGRectGetHeight(bounds) === 5.0)
return [self _drawHorizontalSeperatorInRect:bounds];
case CPLineBorder: CGContextFillRoundedRectangleInRect(aContext, fillRect, _cornerRadius, YES, YES, YES, YES);
CGContextStrokeRoundedRectangleInRect(aContext, strokeRect, _cornerRadius, YES, YES, YES, YES);
break;
break;
case CPBezelBorder: CGContextFillRoundedRectangleInRect(aContext, fillRect, _cornerRadius, YES, YES, YES, YES);
CGContextSetStrokeColor(aContext, [CPColor colorWithWhite:190.0/255.0 alpha:1.0]);
CGContextBeginPath(aContext);
CGContextMoveToPoint(aContext, strokeRect.origin.x, strokeRect.origin.y);
CGContextAddLineToPoint(aContext, CGRectGetMinX(strokeRect), CGRectGetMaxY(strokeRect)),
CGContextAddLineToPoint(aContext, CGRectGetMaxX(strokeRect), CGRectGetMaxY(strokeRect)),
CGContextAddLineToPoint(aContext, CGRectGetMaxX(strokeRect), CGRectGetMinY(strokeRect)),
CGContextStrokePath(aContext);
CGContextSetStrokeColor(aContext, [CPColor colorWithWhite:142.0/255.0 alpha:1.0]);
CGContextBeginPath(aContext);
CGContextMoveToPoint(aContext, bounds.origin.x, strokeRect.origin.y);
CGContextAddLineToPoint(aContext, CGRectGetMaxX(bounds), CGRectGetMinY(strokeRect));
CGContextStrokePath(aContext);
break;
default: break;
}
switch (_borderType)
{
case CPBezelBorder:
[self _drawBezelBorderInRect:bounds];
break;
default:
case CPLineBorder:
[self _drawLineBorderInRect:bounds];
break;
}
}
- (void)_drawHorizontalSeperatorInRect:(CGRect)aRect
{
var context = [[CPGraphicsContext currentContext] graphicsPort];
CGContextSetStrokeColor(context, [self borderColor]);
CGContextSetLineWidth(context, 1.0);
CGContextMoveToPoint(context, CGRectGetMinX(aRect), CGRectGetMinY(aRect) + 0.5);
CGContextAddLineToPoint(context, CGRectGetWidth(aRect), CGRectGetMinY(aRect) + 0.5);
CGContextStrokePath(context);
}
- (void)_drawVerticalSeperatorInRect:(CGRect)aRect
{
var context = [[CPGraphicsContext currentContext] graphicsPort];
CGContextSetStrokeColor(context, [self borderColor]);
CGContextSetLineWidth(context, 1.0);
CGContextMoveToPoint(context, CGRectGetMinX(aRect) + 0.5, CGRectGetMinY(aRect));
CGContextAddLineToPoint(context, CGRectGetMinX(aRect) + 0.5, CGRectGetHeight(aRect));
CGContextStrokePath(context);
}
- (void)_drawBezelBorderInRect:(CGRect)aRect
{
var context = [[CPGraphicsContext currentContext] graphicsPort],
sides = [CPMinYEdge, CPMaxXEdge, CPMaxYEdge, CPMinXEdge],
sideGray = 190.0 / 255.0,
grays = [142.0 / 255.0, sideGray, sideGray, sideGray],
borderWidth = _borderWidth;
while (borderWidth--)
aRect = CPDrawTiledRects(aRect, aRect, sides, grays);
CGContextSetFillColor(context, [self fillColor]);
CGContextFillRect(context, aRect);
}
- (void)_drawLineBorderInRect:(CGRect)aRect
{
var context = [[CPGraphicsContext currentContext] graphicsPort];
aRect = CGRectInset(aRect, _borderWidth / 2.0, _borderWidth / 2.0);
CGContextSetFillColor(context, [self fillColor]);
CGContextSetStrokeColor(context, [self borderColor]);
CGContextSetLineWidth(context, _borderWidth);
CGContextFillRoundedRectangleInRect(context, aRect, _cornerRadius, YES, YES, YES, YES);
CGContextStrokeRoundedRectangleInRect(context, aRect, _cornerRadius, YES, YES, YES, YES);
}
@end
var CPBoxTypeKey = @"CPBoxTypeKey",
CPBoxBorderTypeKey = @"CPBoxBorderTypeKey",
CPBoxBorderColorKey = @"CPBoxBorderColorKey",
CPBoxFillColorKey = @"CPBoxFillColorKey",
CPBoxCornerRadiusKey = @"CPBoxCornerRadiusKey",
CPBoxBorderWidthKey = @"CPBoxBorderWidthKey",
CPBoxContentMarginKey = @"CPBoxContentMarginKey";
@implementation CPBox (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
_boxType = [aCoder decodeIntForKey:CPBoxTypeKey];
_borderType = [aCoder decodeIntForKey:CPBoxBorderTypeKey];
_borderColor = [aCoder decodeObjectForKey:CPBoxBorderColorKey];
_fillColor = [aCoder decodeObjectForKey:CPBoxFillColorKey];
_cornerRadius = [aCoder decodeFloatForKey:CPBoxCornerRadiusKey];
_borderWidth = [aCoder decodeFloatForKey:CPBoxBorderWidthKey];
_contentMargin = [aCoder decodeSizeForKey:CPBoxContentMarginKey];
_contentView = [self subviews][0];
[self setAutoresizesSubviews:YES];
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeInt:_boxType forKey:CPBoxTypeKey];
[aCoder encodeInt:_borderType forKey:CPBoxBorderTypeKey];
[aCoder encodeObject:_borderColor forKey:CPBoxBorderColorKey];
[aCoder encodeObject:_fillColor forKey:CPBoxFillColorKey];
[aCoder encodeFloat:_cornerRadius forKey:CPBoxCornerRadiusKey];
[aCoder encodeFloat:_borderWidth forKey:CPBoxBorderWidthKey];
[aCoder encodeSize:_contentMargin forKey:CPBoxContentMarginKey];
}
@end
+56 -113
View File
@@ -20,17 +20,14 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPIndexSet.j>
@import "CPControl.j"
@import "CPImage.j"
@import "CPTableView.j"
@import "CPTextField.j"
@import "CPScrollView.j"
/*!
/*!
@ingroup appkit
@class CPBrowser
@class CPBrowser
*/
@implementation CPBrowser : CPControl
@@ -67,14 +64,14 @@
+ (CPImage)branchImage
{
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPBrowser class]]
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPBrowser class]]
pathForResource:"browser-leaf.png"]
size:CGSizeMake(9,9)];
}
+ (CPImage)highlightedBranchImage
{
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPBrowser class]]
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPBrowser class]]
pathForResource:"browser-leaf-highlighted.png"]
size:CGSizeMake(9,9)];
}
@@ -83,47 +80,42 @@
{
if (self = [super initWithFrame:aFrame])
{
[self _init];
_rowHeight = 23.0;
_defaultColumnWidth = 140.0;
_minColumnWidth = 80.0;
_imageWidth = 23.0;
_leafWidth = 13.0;
_columnWidths = [];
_pathSeparator = "/";
_tableViews = [];
_tableDelegates = [];
_allowsMultipleSelection = YES;
_allowsEmptySelection = YES;
_tableViewClass = [_CPBrowserTableView class];
_prototypeView = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
[_prototypeView setVerticalAlignment:CPCenterVerticalTextAlignment];
[_prototypeView setValue:[CPColor whiteColor] forThemeAttribute:"text-color" inState:CPThemeStateSelected];
[_prototypeView setLineBreakMode:CPLineBreakByTruncatingTail];
_horizontalScrollView = [[CPScrollView alloc] initWithFrame:[self bounds]];
[_horizontalScrollView setHasVerticalScroller:NO];
[_horizontalScrollView setAutohidesScrollers:YES];
[_horizontalScrollView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
_contentView = [[CPView alloc] initWithFrame:CGRectMake(0, 0, 0, CGRectGetHeight([self bounds]))];
[_contentView setAutoresizingMask:CPViewHeightSizable];
[_horizontalScrollView setDocumentView:_contentView];
[self addSubview:_horizontalScrollView];
}
return self;
}
- (void)_init
{
_rowHeight = 23.0;
_defaultColumnWidth = 140.0;
_minColumnWidth = 80.0;
_imageWidth = 23.0;
_leafWidth = 13.0;
_columnWidths = [];
_pathSeparator = "/";
_tableViews = [];
_tableDelegates = [];
_allowsMultipleSelection = YES;
_allowsEmptySelection = YES;
_tableViewClass = [_CPBrowserTableView class];
_prototypeView = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
[_prototypeView setVerticalAlignment:CPCenterVerticalTextAlignment];
[_prototypeView setValue:[CPColor whiteColor] forThemeAttribute:"text-color" inState:CPThemeStateSelectedDataView];
[_prototypeView setLineBreakMode:CPLineBreakByTruncatingTail];
_horizontalScrollView = [[CPScrollView alloc] initWithFrame:[self bounds]];
[_horizontalScrollView setHasVerticalScroller:NO];
[_horizontalScrollView setAutohidesScrollers:YES];
[_horizontalScrollView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
_contentView = [[CPView alloc] initWithFrame:CGRectMake(0, 0, 0, CGRectGetHeight([self bounds]))];
[_contentView setAutoresizingMask:CPViewHeightSizable];
[_horizontalScrollView setDocumentView:_contentView];
[self addSubview:_horizontalScrollView];
}
- (void)setPrototypeView:(CPView)aPrototypeView
{
_prototypeView = [CPKeyedUnarchiver unarchiveObjectWithData:
@@ -137,7 +129,7 @@
}
- (void)setDelegate:(id)anObject
{
{
_delegate = anObject;
_delegateSupportsImages = [_delegate respondsToSelector:@selector(browser:imageValueForItem:)];
@@ -175,10 +167,12 @@
if (columnIndex >= _tableViews.length)
return;
var oldValue = _tableViews.length - 1,
indexPlusOne = columnIndex + 1; // unloads all later columns.
var oldValue = _tableViews.length - 1;
[[_tableViews.slice(indexPlusOne) valueForKey:"enclosingScrollView"]
// unloads all later columns.
var indexPlusOne = columnIndex + 1;
[[_tableViews.slice(indexPlusOne) valueForKey:"enclosingScrollView"]
makeObjectsPerformSelector:@selector(removeFromSuperview)];
_tableViews = _tableViews.slice(0, indexPlusOne);
@@ -202,10 +196,10 @@
selectionIndexes = [lastColumn selectedRowIndexes];
if (lastIndex >= 0 && [selectionIndexes count] > 1)
[CPException raise:CPInvalidArgumentException
[CPException raise:CPInvalidArgumentException
reason:"Can't add column, column "+lastIndex+" has invalid selection."];
var index = lastIndex + 1,
var index = lastIndex+1,
item = index === 0 ? _rootItem : [_tableDelegates[lastIndex] childAtIndex:[selectionIndexes firstIndex]];
if (index > 0 && item && [self isLeafItem:item])
@@ -237,7 +231,7 @@
[table setAction:@selector(_tableViewClicked:)];
[table setDoubleAction:@selector(_tableViewDoubleClicked:)];
[table setDraggingDestinationFeedbackStyle:CPTableViewDraggingDestinationFeedbackStyleRegular];
var scrollView = [[_CPBrowserScrollView alloc] initWithFrame:CGRectMakeZero()];
[scrollView _setBrowser:self];
[scrollView setDocumentView:table];
@@ -278,10 +272,10 @@
[view setBranchImage:[[self class] branchImage]];
[view setHighlightedBranchImage:[[self class] highlightedBranchImage]];
[column setDataView:view];
[column setResizingMask:CPTableColumnNoResizing];
[aTableView addTableColumn:column];
}
@@ -304,7 +298,7 @@
tableHeight = CGRectGetHeight([tableView bounds]);
[[tableView tableColumnWithIdentifier:"Image"] setWidth:_imageWidth];
[[tableView tableColumnWithIdentifier:"Content"] setWidth:[self columnContentWidthForColumnWidth:width]];
[[tableView tableColumnWithIdentifier:"Content"] setWidth:width - (_leafWidth + _delegateSupportsImages ? _imageWidth : 0) - scrollerWidth - scrollerWidth];
[[tableView tableColumnWithIdentifier:"Leaf"] setWidth:_leafWidth];
[tableView setRowHeight:_rowHeight];
@@ -436,14 +430,12 @@
- (float)columnContentWidthForColumnWidth:(float)aWidth
{
var columnSpacing = [_tableViews[0] intercellSpacing].width;
return aWidth - (_leafWidth + columnSpacing + (_delegateSupportsImages ? _imageWidth + columnSpacing : 0)) - columnSpacing - [CPScroller scrollerWidth];
return aWidth - (_leafWidth + _delegateSupportsImages ? _imageWidth : 0) - [CPScroller scrollerWidth];
}
- (float)columnWidthForColumnContentWidth:(float)aWidth
{
var columnSpacing = [_tableViews[0] intercellSpacing].width;
return aWidth + (_leafWidth + columnSpacing + (_delegateSupportsImages ? _imageWidth + columnSpacing: 0)) + columnSpacing + [CPScroller scrollerWidth];
return aWidth + (_leafWidth + _delegateSupportsImages ? _imageWidth : 0) + [CPScroller scrollerWidth];
}
- (void)setImageWidth:(float)aWidth
@@ -505,7 +497,7 @@
[_contentView scrollRectToVisible:[[[self tableViewInColumn:columnIndex] enclosingScrollView] frame]];
}
- (void)scrollRowToVisible:(unsigned)rowIndex inColumn:(unsigned)columnIndex
(void)scrollRowToVisible:(unsigned)rowIndex inColumn:(unsigned)columnIndex
{
[self scrollColumnToVisible:columnIndex];
[[self tableViewInColumn:columnIndex] scrollRowToVisible:rowIndex];
@@ -592,7 +584,7 @@
if ([_delegate respondsToSelector:@selector(browser:selectionIndexesForProposedSelection:inColumn:)])
indexSet = [_delegate browser:self selectionIndexesForProposedSelection:indexSet inColumn:column];
if ([_delegate respondsToSelector:@selector(browser:shouldSelectRowIndexes:inColumn:)] &&
if ([_delegate respondsToSelector:@selector(browser:shouldSelectRowIndexes:inColumn:)] &&
![_delegate browser:self shouldSelectRowIndexes:indexSet inColumn:column])
return;
@@ -657,53 +649,6 @@
@end
@implementation CPBrowser (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
[self _init];
_allowsEmptySelection = [aCoder decodeBoolForKey:@"CPBrowserAllowsEmptySelectionKey"];
_allowsMultipleSelection = [aCoder decodeBoolForKey:@"CPBrowserAllowsMultipleSelectionKey"];
_prototypeView = [aCoder decodeObjectForKey:@"CPBrowserPrototypeViewKey"];
_rowHeight = [aCoder decodeFloatForKey:@"CPBrowserRowHeightKey"];
_imageWidth = [aCoder decodeFloatForKey:@"CPBrowserImageWidthKey"];
_minColumnWidth = [aCoder decodeFloatForKey:@"CPBrowserMinColumnWidthKey"];
_columnWidths = [aCoder decodeObjectForKey:@"CPBrowserColumnWidthsKey"];
[self setDelegate:[aCoder decodeObjectForKey:@"CPBrowserDelegateKey"]];
[self setAutohidesScroller:[aCoder decodeBoolForKey:@"CPBrowserAutohidesScrollerKey"]];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
// Don't encode the subviews, they're transient and will be recreated from data.
var actualSubviews = _subviews;
_subviews = [];
[super encodeWithCoder:aCoder];
_subviews = actualSubviews;
[aCoder encodeBool:[self autohidesScroller] forKey:@"CPBrowserAutohidesScrollerKey"];
[aCoder encodeBool:_allowsEmptySelection forKey:@"CPBrowserAllowsEmptySelectionKey"];
[aCoder encodeBool:_allowsMultipleSelection forKey:@"CPBrowserAllowsMultipleSelectionKey"];
[aCoder encodeObject:_delegate forKey:@"CPBrowserDelegateKey"];
[aCoder encodeObject:_prototypeView forKey:@"CPBrowserPrototypeViewKey"];
[aCoder encodeFloat:_rowHeight forKey:@"CPBrowserRowHeightKey"];
[aCoder encodeFloat:_imageWidth forKey:@"CPBrowserImageWidthKey"];
[aCoder encodeFloat:_minColumnWidth forKey:@"CPBrowserMinColumnWidthKey"];
[aCoder encodeObject:_columnWidths forKey:@"CPBrowserColumnWidthsKey"];
}
@end
var _CPBrowserResizeControlBackgroundImage = nil;
@implementation _CPBrowserResizeControl : CPView
@@ -851,7 +796,7 @@ var _CPBrowserResizeControlBackgroundImage = nil;
}
- (void)moveLeft:(id)sender
{
{
var previousColumn = [_browser selectedColumn] - 1,
selectedRow = [_browser selectedRowInColumn:previousColumn];
@@ -859,14 +804,12 @@ var _CPBrowserResizeControlBackgroundImage = nil;
}
- (void)moveRight:(id)sender
{
{
[_browser selectRow:0 inColumn:[_browser selectedColumn] + 1];
}
@end
@import <Foundation/CPObject.j>
@implementation _CPBrowserTableDelegate : CPObject
{
CPBrowser _browser @accessors;
@@ -917,7 +860,7 @@ var _CPBrowserResizeControlBackgroundImage = nil;
- (CPDragOperation)tableView:(CPTableView)aTableView validateDrop:(id)info proposedRow:(int)row proposedDropOperation:(CPTableViewDropOperation)operation
{
if ([_delegate respondsToSelector:@selector(browser:validateDrop:proposedRow:column:dropOperation:)])
return [_delegate browser:_browser validateDrop:info proposedRow:row column:_index dropOperation:operation];
[_delegate browser:_browser validateDrop:info proposedRow:row column:_index dropOperation:operation];
else
return CPDragOperationNone;
}
@@ -978,9 +921,9 @@ var _CPBrowserResizeControlBackgroundImage = nil;
{
var imageView = [self layoutEphemeralSubviewNamed:@"image-view"
positioned:CPWindowAbove
relativeToEphemeralSubviewNamed:nil],
isHighlighted = [self themeState] & CPThemeStateSelectedDataView;
relativeToEphemeralSubviewNamed:nil];
var isHighlighted = [self themeState] & CPThemeStateSelected;
[imageView setImage: _isLeaf ? (isHighlighted ? _highlightedBranchImage : _branchImage) : nil];
[imageView setImageScaling:CPScaleNone];
}
+80 -317
View File
@@ -26,6 +26,8 @@
@import "CPControl.j"
@import "CPStringDrawing.j"
#include "CoreGraphics/CGGeometry.h"
/* @group CPBezelStyle */
@@ -70,18 +72,9 @@ CPPushInCellMask = CPPushInButtonMask;
CPChangeGrayCellMask = CPGrayButtonMask;
CPChangeBackgroundCellMask = CPBackgroundButtonMask;
CPButtonStateMixed = CPThemeState("mixed");
CPButtonStateBezelStyleRounded = CPThemeState("rounded");
CPButtonStateMixed = CPThemeState("mixed");
// add all future correspondance between bezel styles and theme state here.
var CPButtonBezelStyleStateMap = [CPDictionary dictionaryWithObjects:[CPButtonStateBezelStyleRounded, nil]
forKeys:[CPRoundedBezelStyle, CPRoundRectBezelStyle]];
CPButtonDefaultHeight = 24.0;
CPButtonImageOffset = 3.0;
/*!
/*!
@ingroup appkit
@class CPButton
@@ -92,9 +85,12 @@ CPButtonImageOffset = 3.0;
@implementation CPButton : CPControl
{
BOOL _allowsMixedState;
CPString _title;
CPString _alternateTitle;
CPImage _image;
CPImage _alternateImage;
CPInteger _showsStateBy;
CPInteger _highlightsBy;
@@ -103,14 +99,6 @@ CPButtonImageOffset = 3.0;
// NS-style Display Properties
CPBezelStyle _bezelStyle;
CPControlSize _controlSize;
CPString _keyEquivalent;
unsigned _keyEquivalentModifierMask;
CPTimer _continuousDelayTimer;
CPTimer _continuousTimer;
float _periodicDelay;
float _periodicInterval;
}
+ (id)buttonWithTitle:(CPString)aTitle
@@ -129,26 +117,21 @@ CPButtonImageOffset = 3.0;
return button;
}
+ (CPString)defaultThemeClass
+ (CPString)themeClass
{
return @"button";
}
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[[CPNull null], 0.0, _CGInsetMakeZero(), _CGInsetMakeZero(), [CPNull null]]
forKeys:[@"image", @"image-offset", @"bezel-inset", @"content-inset", @"bezel-color"]];
return [CPDictionary dictionaryWithObjects:[_CGInsetMakeZero(), _CGInsetMakeZero(), [CPNull null]]
forKeys:[@"bezel-inset", @"content-inset", @"bezel-color"]];
}
/*!
Initializes and returns a newly allocated CPButton object with a specified frame rectangle.
@param aFrame The frame rectangle for the created button object.
@return An initialized CPView object or nil if the object couldn't be created.
*/
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
// Should we instead override the defaults?
@@ -156,32 +139,19 @@ CPButtonImageOffset = 3.0;
[self setValue:CPCenterVerticalTextAlignment forThemeAttribute:@"vertical-alignment"];
[self setValue:CPImageLeft forThemeAttribute:@"image-position"];
[self setValue:CPScaleNone forThemeAttribute:@"image-scaling"];
[self setBezelStyle:CPRoundRectBezelStyle];
_controlSize = CPRegularControlSize;
// [self setBezelStyle:CPRoundRectBezelStyle];
[self setBordered:YES];
[self _init];
}
return self;
}
- (void)_init
{
_controlSize = CPRegularControlSize;
_keyEquivalent = @"";
_keyEquivalentModifierMask = 0;
// Continuous button defaults.
_periodicInterval = 0.05;
_periodicDelay = 0.5;
}
// Setting the state
/*!
Returns a Boolean value indicating whether the button allows a mixed state.
@return \c YES if the button has a 'mixed' state in addition to on and off.
Returns \c YES if the button has a 'mixed' state in addition to on and off.
*/
- (BOOL)allowsMixedState
{
@@ -205,10 +175,6 @@ CPButtonImageOffset = 3.0;
[self setState:CPOnState];
}
/*!
Sets the value of the button using an Objective-J object.
@param anObjectValue The value of the button interpreted as an Objective-J object.
*/
- (void)setObjectValue:(id)anObjectValue
{
if (!anObjectValue || anObjectValue === @"" || ([anObjectValue intValue] === 0))
@@ -217,7 +183,7 @@ CPButtonImageOffset = 3.0;
else if (![anObjectValue isKindOfClass:[CPNumber class]])
anObjectValue = CPOnState;
else if (anObjectValue >= CPOnState)
else if (anObjectValue > CPOnState)
anObjectValue = CPOnState
else if (anObjectValue < CPOffState)
@@ -243,13 +209,6 @@ CPButtonImageOffset = 3.0;
}
}
/*!
Returns the button's next state.
@return The button's state. A button can have two or three states.
If it has two, this value is either \c CPOffState (the normal or unpressed state)
or \c CPOnState (the alternate or pressed state).
If it has three, this value can be \c CPOnState (the feature is in effect everywhere), \c CPOffState (the feature is in effect nowhere), or \c CPMixedState (the feature is in effect somewhere).
*/
- (CPInteger)nextState
{
if ([self allowsMixedState])
@@ -262,16 +221,8 @@ CPButtonImageOffset = 3.0;
return 1 - [self state];
}
/*!
Sets the button's next state to \c aState.
@param aState Possible states are any of the CPButton globals:
\c CPOffState, \c CPOnState, \c CPMixedState
*/
- (void)setNextState
{
if ([self infoForBinding:CPValueBinding])
[self setAllowsMixedState:NO];
[self setState:[self nextState]];
}
@@ -293,27 +244,17 @@ CPButtonImageOffset = 3.0;
return [self intValue];
}
/*!
Sets the title displayed by the button when in its normal state.
@param aTitle The string to set as the button's title. This title is always shown on buttons
that dont use their alternate contents when highlighting or displaying their alternate state.
*/
- (void)setTitle:(CPString)aTitle
{
if (_title === aTitle)
return;
_title = aTitle;
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
/*!
Returns the title displayed on the button when its in its normal state.
@return The title displayed on the receiver when its in its normal state
or the empty string if the button doesnt display a title.
*/
- (CPString)title
{
return _title;
@@ -323,7 +264,7 @@ CPButtonImageOffset = 3.0;
{
if (_alternateTitle === aTitle)
return;
_alternateTitle = aTitle;
[self setNeedsLayout];
@@ -337,12 +278,18 @@ CPButtonImageOffset = 3.0;
- (void)setImage:(CPImage)anImage
{
[self setValue:anImage forThemeAttribute:@"image"];
if (_image === anImage)
return;
_image = anImage;
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
- (CPImage)image
{
return [self valueForThemeAttribute:@"image" inState:CPThemeStateNormal];
return _image;
}
/*!
@@ -351,7 +298,13 @@ CPButtonImageOffset = 3.0;
*/
- (void)setAlternateImage:(CPImage)anImage
{
[self setValue:anImage forThemeAttribute:@"image" inState:CPThemeStateHighlighted];
if (_alternateImage === anImage)
return;
_alternateImage = anImage;
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
/*!
@@ -359,17 +312,7 @@ CPButtonImageOffset = 3.0;
*/
- (CPImage)alternateImage
{
return [self valueForThemeAttribute:@"image" inState:CPThemeStateHighlighted];
}
- (void)setImageOffset:(float)theImageOffset
{
[self setValue:theImageOffset forThemeAttribute:@"image-offset"];
}
- (float)imageOffset
{
return [self valueForThemeAttribute:@"image-offset"];
return _alternateImage;
}
- (void)setShowsStateBy:(CPInteger)aMask
@@ -430,13 +373,13 @@ CPButtonImageOffset = 3.0;
[self setShowsStateBy:CPContentsCellMask];
break;
case CPSwitchButton: [CPException raise:CPInvalidArgumentException
case CPSwitchButton: [CPException raise:CPInvalidArgumentException
reason:"The CPSwitchButton type is not supported in Cappuccino, use the CPCheckBox class instead."];
case CPRadioButton: [CPException raise:CPInvalidArgumentException
case CPRadioButton: [CPException raise:CPInvalidArgumentException
reason:"The CPRadioButton type is not supported in Cappuccino, use the CPRadio class instead."];
default: [CPException raise:CPInvalidArgumentException
default: [CPException raise:CPInvalidArgumentException
reason:"Unknown button type."];
}
@@ -452,7 +395,7 @@ CPButtonImageOffset = 3.0;
_imageDimsWhenDisabled = imageShouldDimWhenDisabled;
if ([self hasThemeState:CPThemeStateDisabled])
if (_imageDimsWhenDisabled)
{
[self setNeedsDisplay:YES];
[self setNeedsLayout];
@@ -464,45 +407,16 @@ CPButtonImageOffset = 3.0;
return _imageDimsWhenDisabled;
}
- (void)setPeriodicDelay:(float)aDelay interval:(float)anInterval
{
_periodicDelay = aDelay;
_periodicInterval = anInterval;
}
- (void)mouseDown:(CPEvent)anEvent
{
if ([self isContinuous])
{
_continuousDelayTimer = [CPTimer scheduledTimerWithTimeInterval:_periodicDelay callback: function()
{
if (!_continuousTimer)
_continuousTimer = [CPTimer scheduledTimerWithTimeInterval:_periodicInterval target:self selector:@selector(onContinousEvent:) userInfo:anEvent repeats:YES];
}
repeats:NO];
}
[super mouseDown:anEvent];
}
- (void)onContinousEvent:(CPTimer)aTimer
{
if (_target && _action && [_target respondsToSelector:_action])
[_target performSelector:_action withObject:self];
}
- (BOOL)startTrackingAt:(CGPoint)aPoint
{
[self highlight:YES];
return [super startTrackingAt:aPoint];
}
- (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp
{
[self highlight:NO];
[self invalidateTimers];
[super stopTracking:lastPoint at:aPoint mouseIsUp:mouseIsUp];
@@ -510,21 +424,6 @@ CPButtonImageOffset = 3.0;
[self setNextState];
}
- (void)invalidateTimers
{
if (_continuousTimer)
{
[_continuousTimer invalidate];
_continuousTimer = nil;
}
if (_continuousDelayTimer)
{
[_continuousDelayTimer invalidate];
_continuousDelayTimer = nil;
}
}
- (CGRect)contentRectForBounds:(CGRect)bounds
{
var contentInset = [self currentValueForThemeAttribute:@"content-inset"];
@@ -532,12 +431,11 @@ CPButtonImageOffset = 3.0;
if (_CGInsetIsEmpty(contentInset))
return bounds;
bounds = _CGRectMakeCopy(bounds);
bounds.origin.x += contentInset.left;
bounds.origin.y += contentInset.top;
bounds.size.width -= contentInset.left + contentInset.right;
bounds.size.height -= contentInset.top + contentInset.bottom;
return bounds;
}
@@ -551,7 +449,6 @@ CPButtonImageOffset = 3.0;
if (_CGInsetIsEmpty(bezelInset))
return bounds;
bounds = _CGRectMakeCopy(bounds);
bounds.origin.x += bezelInset.left;
bounds.origin.y += bezelInset.top;
bounds.size.width -= bezelInset.left + bezelInset.right;
@@ -560,20 +457,13 @@ CPButtonImageOffset = 3.0;
return bounds;
}
- (CGSize)_minimumFrameSize
/*!
Adjust the size of the button to fit the title and surrounding button image.
*/
- (void)sizeToFit
{
var size = CGSizeMakeZero(),
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"],
var size = [([self title] || " ") sizeWithFont:[self currentValueForThemeAttribute:@"font"]],
contentInset = [self currentValueForThemeAttribute:@"content-inset"],
minSize = [self currentValueForThemeAttribute:@"min-size"],
maxSize = [self currentValueForThemeAttribute:@"max-size"];
@@ -586,30 +476,17 @@ CPButtonImageOffset = 3.0;
if (maxSize.height >= 0.0)
size.height = MIN(size.height, maxSize.height);
return size;
}
/*!
Adjust the size of the button to fit the title and surrounding button image.
*/
- (void)sizeToFit
{
[self layoutSubviews];
[self setFrameSize:[self _minimumFrameSize]];
if ([self ephemeralSubviewNamed:@"content-view"])
[self layoutSubviews];
[self setFrameSize:size];
}
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
{
if (aName === "bezel-view")
return [self bezelRectForBounds:[self bounds]];
else if (aName === "content-view")
return [self contentRectForBounds:[self bounds]];
return [super rectForEphemeralSubviewNamed:aName];
}
@@ -620,7 +497,7 @@ CPButtonImageOffset = 3.0;
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
[view setHitTests:NO];
return view;
}
else
@@ -642,8 +519,7 @@ CPButtonImageOffset = 3.0;
if (contentView)
{
[contentView setText:([self hasThemeState:CPThemeStateHighlighted] && _alternateTitle) ? _alternateTitle : _title];
[contentView setImage:[self currentValueForThemeAttribute:@"image"]];
[contentView setImageOffset:[self currentValueForThemeAttribute:@"image-offset"]];
[contentView setImage:([self hasThemeState:CPThemeStateHighlighted] && _alternateImage) ? _alternateImage : _image];
[contentView setFont:[self currentValueForThemeAttribute:@"font"]];
[contentView setTextColor:[self currentValueForThemeAttribute:@"text-color"]];
@@ -658,6 +534,14 @@ CPButtonImageOffset = 3.0;
}
}
- (void)setDefaultButton:(BOOL)shouldBeDefaultButton
{
if (shouldBeDefaultButton)
[self setThemeState:CPThemeStateDefault];
else
[self unsetThemeState:CPThemeStateDefault];
}
- (void)setBordered:(BOOL)shouldBeBordered
{
if (shouldBeBordered)
@@ -671,120 +555,26 @@ CPButtonImageOffset = 3.0;
return [self hasThemeState:CPThemeStateBordered];
}
/*!
Sets the keyboard shortcut for this button. For special keys see
CPEvent.j CP...FunctionKey and CPText.j CP...Character.
@param aString the keyboard shortcut as a string
*/
- (void)setKeyEquivalent:(CPString)aString
{
_keyEquivalent = aString || @"";
// Check if the key equivalent is the enter key
// Treat \r and \n as the same key equivalent. See issue #710.
if (aString === CPNewlineCharacter || aString === CPCarriageReturnCharacter)
[self setThemeState:CPThemeStateDefault];
else
[self unsetThemeState:CPThemeStateDefault];
}
- (void)viewWillMoveToWindow:(CPWindow)aWindow
{
var selfWindow = [self window];
if (selfWindow === aWindow || aWindow === nil)
return;
if ([selfWindow defaultButton] === self)
[selfWindow setDefaultButton:nil];
if ([self keyEquivalent] === CPNewlineCharacter || [self keyEquivalent] === CPCarriageReturnCharacter)
[aWindow setDefaultButton:self];
}
/*!
Returns the keyboard shortcut for this button.
*/
- (CPString)keyEquivalent
{
return _keyEquivalent;
}
/*!
Returns the mask used with this button's key equivalent.
*/
- (void)setKeyEquivalentModifierMask:(unsigned)aMask
{
_keyEquivalentModifierMask = aMask;
}
/*!
Sets the mask to be used with this button's key equivalent.
*/
- (unsigned)keyEquivalentModifierMask
{
return _keyEquivalentModifierMask;
}
/*!
Checks the button's key equivalent against that in the event, and if they
match simulates a button click.
*/
- (BOOL)performKeyEquivalent:(CPEvent)anEvent
{
// Don't handle the key equivalent for the default window because the window will handle it for us
if ([[self window] defaultButton] === self)
return NO;
if (![anEvent _triggersKeyEquivalent:[self keyEquivalent] withModifierMask:[self keyEquivalentModifierMask]])
return NO;
[self performClick:nil];
return YES;
}
@end
@implementation CPButton (NS)
- (void)setBezelStyle:(unsigned)aBezelStyle
{
if (aBezelStyle === _bezelStyle)
return;
var currentState = [CPButtonBezelStyleStateMap objectForKey:_bezelStyle],
newState = [CPButtonBezelStyleStateMap objectForKey:aBezelStyle];
if (currentState)
[self unsetThemeState:currentState];
if (newState)
[self setThemeState:newState];
_bezelStyle = aBezelStyle;
}
- (unsigned)bezelStyle
{
return _bezelStyle;
}
@end
var CPButtonImageKey = @"CPButtonImageKey",
CPButtonAlternateImageKey = @"CPButtonAlternateImageKey",
CPButtonTitleKey = @"CPButtonTitleKey",
CPButtonAlternateTitleKey = @"CPButtonAlternateTitleKey",
CPButtonIsBorderedKey = @"CPButtonIsBorderedKey",
CPButtonAllowsMixedStateKey = @"CPButtonAllowsMixedStateKey",
CPButtonImageDimsWhenDisabledKey = @"CPButtonImageDimsWhenDisabledKey",
CPButtonImagePositionKey = @"CPButtonImagePositionKey",
CPButtonKeyEquivalentKey = @"CPButtonKeyEquivalentKey",
CPButtonKeyEquivalentMaskKey = @"CPButtonKeyEquivalentMaskKey",
CPButtonPeriodicDelayKey = @"CPButtonPeriodicDelayKey",
CPButtonPeriodicIntervalKey = @"CPButtonPeriodicIntervalKey";
var CPButtonImageKey = @"CPButtonImageKey",
CPButtonAlternateImageKey = @"CPButtonAlternateImageKey",
CPButtonTitleKey = @"CPButtonTitleKey",
CPButtonAlternateTitleKey = @"CPButtonAlternateTitleKey",
CPButtonIsBorderedKey = @"CPButtonIsBorderedKey";
@implementation CPButton (CPCoding)
@@ -795,37 +585,21 @@ var CPButtonImageKey = @"CPButtonImageKey",
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
[self _init];
_title = [aCoder decodeObjectForKey:CPButtonTitleKey];
_alternateTitle = [aCoder decodeObjectForKey:CPButtonAlternateTitleKey];
if ([aCoder containsValueForKey:CPButtonAllowsMixedStateKey])
_allowsMixedState = [aCoder decodeBoolForKey:CPButtonAllowsMixedStateKey];
[self setImageDimsWhenDisabled:[aCoder decodeObjectForKey:CPButtonImageDimsWhenDisabledKey]];
if ([aCoder containsValueForKey:CPButtonImagePositionKey])
[self setImagePosition:[aCoder decodeIntForKey:CPButtonImagePositionKey]];
if ([aCoder containsValueForKey:CPButtonKeyEquivalentKey])
[self setKeyEquivalent:CFData.decodeBase64ToUtf16String([aCoder decodeObjectForKey:CPButtonKeyEquivalentKey])];
if ([aCoder containsValueForKey:CPButtonPeriodicDelayKey])
_periodicDelay = [aCoder decodeObjectForKey:CPButtonPeriodicDelayKey];
if ([aCoder containsValueForKey:CPButtonPeriodicIntervalKey])
_periodicInterval = [aCoder decodeObjectForKey:CPButtonPeriodicIntervalKey];
_keyEquivalentModifierMask = [aCoder decodeIntForKey:CPButtonKeyEquivalentMaskKey];
_controlSize = CPRegularControlSize;
[self setImage:[aCoder decodeObjectForKey:CPButtonImageKey]];
[self setAlternateImage:[aCoder decodeObjectForKey:CPButtonAlternateImageKey]];
[self setTitle:[aCoder decodeObjectForKey:CPButtonTitleKey]];
[self setAlternateTitle:[aCoder decodeObjectForKey:CPButtonAlternateTitleKey]];
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
return self;
}
@@ -836,23 +610,12 @@ var CPButtonImageKey = @"CPButtonImageKey",
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[self invalidateTimers];
[aCoder encodeObject:_image forKey:CPButtonImageKey];
[aCoder encodeObject:_alternateImage forKey:CPButtonAlternateImageKey];
[aCoder encodeObject:_title forKey:CPButtonTitleKey];
[aCoder encodeObject:_alternateTitle forKey:CPButtonAlternateTitleKey];
[aCoder encodeBool:_allowsMixedState forKey:CPButtonAllowsMixedStateKey];
[aCoder encodeBool:[self imageDimsWhenDisabled] forKey:CPButtonImageDimsWhenDisabledKey];
[aCoder encodeInt:[self imagePosition] forKey:CPButtonImagePositionKey];
if (_keyEquivalent)
[aCoder encodeObject:CFData.encodeBase64Utf16String(_keyEquivalent) forKey:CPButtonKeyEquivalentKey];
[aCoder encodeInt:_keyEquivalentModifierMask forKey:CPButtonKeyEquivalentMaskKey];
[aCoder encodeObject:_periodicDelay forKey:CPButtonPeriodicDelayKey];
[aCoder encodeObject:_periodicInterval forKey:CPButtonPeriodicIntervalKey];
}
@end
+13 -11
View File
@@ -1,5 +1,7 @@
@import "CPView.j"
@import <AppKit/CPView.j>
#include "CoreGraphics/CGGeometry.h"
@implementation CPButtonBar : CPView
@@ -48,7 +50,7 @@
return button;
}
+ (CPString)defaultThemeClass
+ (CPString)themeClass
{
return @"button-bar";
}
@@ -195,12 +197,12 @@
availableWidth = frameWidth - resizeWidth - 1;
for (var i = 0, count = [buttonsNotHidden count]; i < count; i++)
{
{
var button = buttonsNotHidden[i],
width = CGRectGetWidth([button frame]);
if (availableWidth > width)
availableWidth -= width;
availableWidth -=width;
else
break;
@@ -215,15 +217,15 @@
currentButtonOffset += width - 1;
}
[button setValue:normalColor forThemeAttribute:@"bezel-color" inState:CPThemeStateNormal | CPThemeStateBordered];
[button setValue:highlightedColor forThemeAttribute:@"bezel-color" inState:CPThemeStateHighlighted | CPThemeStateBordered];
[button setValue:disabledColor forThemeAttribute:@"bezel-color" inState:CPThemeStateDisabled | CPThemeStateBordered];
[button setValue:textColor forThemeAttribute:@"text-color" inState:CPThemeStateBordered];
[button setValue:normalColor forThemeAttribute:@"bezel-color" inState:CPThemeStateNormal|CPThemeStateBordered];
[button setValue:highlightedColor forThemeAttribute:@"bezel-color" inState:CPThemeStateHighlighted|CPThemeStateBordered];
[button setValue:disabledColor forThemeAttribute:@"bezel-color" inState:CPThemeStateDisabled|CPThemeStateBordered];
[button setValue:textColor forThemeAttribute:@"text-color" inState:CPThemeStateBordered];
// FIXME shouldn't need this
[button setValue:normalColor forThemeAttribute:@"bezel-color" inState:CPThemeStateNormal | CPThemeStateBordered | CPPopUpButtonStatePullsDown];
[button setValue:highlightedColor forThemeAttribute:@"bezel-color" inState:CPThemeStateHighlighted | CPThemeStateBordered | CPPopUpButtonStatePullsDown];
[button setValue:disabledColor forThemeAttribute:@"bezel-color" inState:CPThemeStateDisabled | CPThemeStateBordered | CPPopUpButtonStatePullsDown];
[button setValue:normalColor forThemeAttribute:@"bezel-color" inState:CPThemeStateNormal|CPThemeStateBordered|CPPopUpButtonStatePullsDown];
[button setValue:highlightedColor forThemeAttribute:@"bezel-color" inState:CPThemeStateHighlighted|CPThemeStateBordered|CPPopUpButtonStatePullsDown];
[button setValue:disabledColor forThemeAttribute:@"bezel-color" inState:CPThemeStateDisabled|CPThemeStateBordered|CPPopUpButtonStatePullsDown];
[self addSubview:button];
}
+2 -62
View File
@@ -23,8 +23,6 @@
@import "CPButton.j"
CPCheckBoxImageOffset = 4.0;
@implementation CPCheckBox : CPButton
{
}
@@ -39,19 +37,11 @@ CPCheckBoxImageOffset = 4.0;
return [self buttonWithTitle:aTitle];
}
+ (CPString)defaultThemeClass
+ (CPString)themeClass
{
return @"check-box";
}
+ (Class)_binderClassForBinding:(CPString)theBinding
{
if (theBinding === CPValueBinding)
return [_CPCheckBoxValueBinder class];
return [super _binderClassForBinding:theBinding];
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
@@ -65,7 +55,7 @@ CPCheckBoxImageOffset = 4.0;
[self setImagePosition:CPImageLeft];
[self setAlignment:CPLeftTextAlignment];
[self setBordered:NO];
[self setBordered:YES];
}
return self;
@@ -95,53 +85,3 @@ CPCheckBoxImageOffset = 4.0;
}
@end
@implementation _CPCheckBoxValueBinder : CPBinder
{
}
- (void)setValueFor:(CPString)theBinding
{
var destination = [_info objectForKey:CPObservedObjectKey],
keyPath = [_info objectForKey:CPObservedKeyPathKey],
options = [_info objectForKey:CPOptionsKey],
newValue = [destination valueForKeyPath:keyPath],
isPlaceholder = CPIsControllerMarker(newValue);
if (isPlaceholder)
{
switch (newValue)
{
case CPMultipleValuesMarker:
newValue = CPMixedState;
break;
case CPNoSelectionMarker:
newValue = CPOffState;
break;
case CPNotApplicableMarker:
if ([options objectForKey:CPRaisesForNotApplicableKeysBindingOption])
[CPException raise:CPGenericException reason:@"can't transform non applicable key on: "+_source+" value: "+newValue];
newValue = CPOffState;
break;
}
if (newValue === CPMixedState)
{
[_source setAllowsMixedState:YES];
}
else
{
// Cocoa will always set allowsMixedState to NO
// This behavior will be fine for Cappuccino as well if we (like Cocoa)
// default the CPConditionallySetsEnabledBindingOption to YES
[_source setAllowsMixedState:NO];
}
}
[_source setState:newValue];
}
@end
+26 -24
View File
@@ -22,12 +22,14 @@
@import "CPView.j"
#include "CoreGraphics/CGGeometry.h"
/*!
/*!
@ingroup appkit
@class CPClipView
CPClipView allows you to define a clip rect and display only that portion of its containing view.
CPClipView allows you to define a clip rect and display only that portion of its containing view.
It is used to hold the document view in a CPScrollView.
*/
@implementation CPClipView : CPView
@@ -45,7 +47,7 @@
return;
var defaultCenter = [CPNotificationCenter defaultCenter];
if (_documentView)
{
[defaultCenter
@@ -57,29 +59,29 @@
removeObserver:self
name:CPViewBoundsDidChangeNotification
object:_documentView];
[_documentView removeFromSuperview];
}
_documentView = aView;
if (_documentView)
{
[self addSubview:_documentView];
[_documentView setPostsFrameChangedNotifications:YES];
[_documentView setPostsBoundsChangedNotifications:YES];
[_documentView setPostsFrameChangedNotifications:YES];
[_documentView setPostsBoundsChangedNotifications:YES];
[defaultCenter
[defaultCenter
addObserver:self
selector:@selector(viewFrameChanged:)
name:CPViewFrameDidChangeNotification
name:CPViewFrameDidChangeNotification
object:_documentView];
[defaultCenter
[defaultCenter
addObserver:self
selector:@selector(viewBoundsChanged:)
name:CPViewBoundsDidChangeNotification
name:CPViewBoundsDidChangeNotification
object:_documentView];
}
}
@@ -104,7 +106,7 @@
return _CGPointMakeZero();
var documentFrame = [_documentView frame];
aPoint.x = MAX(0.0, MIN(aPoint.x, MAX(_CGRectGetWidth(documentFrame) - _CGRectGetWidth(_bounds), 0.0)));
aPoint.y = MAX(0.0, MIN(aPoint.y, MAX(_CGRectGetHeight(documentFrame) - _CGRectGetHeight(_bounds), 0.0)));
@@ -115,7 +117,7 @@
{
if (_CGPointEqualToPoint(_bounds.origin, aPoint))
return;
[super setBoundsOrigin:aPoint];
var superview = [self superview],
@@ -124,7 +126,7 @@
// FIXME: Should CPScrollView be finding out about this on its own somehow?
scrollViewClass = objj_getClass("CPScrollView");
if ([superview isKindOfClass:scrollViewClass])
if([superview isKindOfClass:scrollViewClass])
[superview reflectScrolledClipView:self];
}
@@ -164,12 +166,12 @@
- (void)_constrainScrollPoint
{
var oldScrollPoint = [self bounds].origin;
// Call scrollToPoint: because the current scroll point may no longer make
// Call scrollToPoint: because the current scroll point may no longer make
// sense given the new frame of the document view.
[self scrollToPoint:oldScrollPoint];
// scrollToPoint: takes care of reflectScrollClipView: for us, so bail if
// scrollToPoint: takes care of reflectScrollClipView: for us, so bail if
// the scroll points are not equal (meaning scrollToPoint: didn't early bail).
if (!CGPointEqualToPoint(oldScrollPoint, [self bounds].origin))
return;
@@ -185,7 +187,7 @@
[superview reflectScrolledClipView:self];
}
- (BOOL)autoscroll:(CPEvent)anEvent
- (BOOL)autoscroll:(CPEvent)anEvent
{
var bounds = [self bounds],
eventLocation = [self convertPoint:[anEvent locationInWindow] fromView:nil],
@@ -220,7 +222,7 @@
deltaX = bounds.size.width;
}
return [self scrollToPoint:CGPointMake(bounds.origin.x - deltaX, bounds.origin.y - deltaY)];
return [self scrollToPoint:CGPointMake(bounds.origin.x - deltaX, bounds.origin.y - deltaY)];
}
@end
@@ -234,14 +236,14 @@ var CPClipViewDocumentViewKey = @"CPScrollViewDocumentView";
{
if (self = [super initWithCoder:aCoder])
[self setDocumentView:[aCoder decodeObjectForKey:CPClipViewDocumentViewKey]];
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:_documentView forKey:CPClipViewDocumentViewKey];
}
+31 -189
View File
@@ -131,49 +131,6 @@
/*!
Sets the item prototype to \c anItem
The item prototype should implement the CPCoding protocol
because the item is copied by archiving and unarchiving the
prototypal view.
Example:
<pre>
@implement MyCustomView : CPCollectionViewItem
{
CPArray items @accessors;
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
items = [];
}
return self;
}
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
items = [aCoder decodeObjectForKey:@"KEY"];
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[aCoder encodeObject:items forKey:@"KEY"];
[super encodeWithCoder:aCoder];
}
@end
</pre>
This will allow the collection view to create multiple 'clean' copies
of the item prototype which will maintain the original values for item
and all of the properties archived by the super class.
@param anItem the new item prototype
*/
- (void)setItemPrototype:(CPCollectionViewItem)anItem
@@ -246,8 +203,8 @@
*/
- (void)setContent:(CPArray)anArray
{
// reset the _selectionIndexes
[self setSelectionIndexes:[CPIndexSet indexSet]];
if (_content == anArray)
return;
_content = anArray;
@@ -340,7 +297,7 @@
*/
- (void)setSelectionIndexes:(CPIndexSet)anIndexSet
{
if ([_selectionIndexes isEqual:anIndexSet] || !_isSelectable)
if (_selectionIndexes == anIndexSet || !_isSelectable)
return;
var index = CPNotFound;
@@ -355,11 +312,8 @@
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound)
[_items[index] setSelected:YES];
var binderClass = [[self class] _binderClassForBinding:@"selectionIndexes"];
[[binderClass getBinding:@"selectionIndexes" forObject:self] reverseSetValueFor:@"selectionIndexes"];
if ([_delegate respondsToSelector:@selector(collectionViewDidChangeSelection:)])
[_delegate collectionViewDidChangeSelection:self];
[_delegate collectionViewDidChangeSelection:self]
}
/*!
@@ -386,7 +340,7 @@
_items = [];
if (!_itemPrototype)
if (!_itemPrototype || !_content)
return;
var index = 0;
@@ -412,7 +366,7 @@
{
var width = CGRectGetWidth([self bounds]);
if (width == _tileWidth)
if (![_content count] || width == _tileWidth)
return;
// We try to fit as many views per row as possible. Any remaining space is then
@@ -632,40 +586,13 @@
_mouseDownEvent = anEvent;
var location = [self convertPoint:[anEvent locationInWindow] fromView:nil],
index = [self _indexAtPoint:location];
row = FLOOR(location.y / (_itemSize.height + _verticalMargin)),
column = FLOOR(location.x / (_itemSize.width + _horizontalMargin)),
index = row * _numberOfColumns + column;
if (index >= 0 && index < _items.length)
{
if (_allowsMultipleSelection && ([anEvent modifierFlags] & CPCommandKeyMask || [anEvent modifierFlags] & CPShiftKeyMask))
{
if ([anEvent modifierFlags] & CPCommandKeyMask)
{
var indexes = [_selectionIndexes copy];
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
if ([indexes containsIndex:index])
[indexes removeIndex:index];
else
[indexes addIndex:index];
}
else if ([anEvent modifierFlags] & CPShiftKeyMask)
{
var firstSelectedIndex = [[self selectionIndexes] firstIndex],
newSelectedRange = nil;
if (index < firstSelectedIndex)
newSelectedRange = CPMakeRange(index, (firstSelectedIndex - index) + 1);
else
newSelectedRange = CPMakeRange(firstSelectedIndex, (index - firstSelectedIndex) + 1);
indexes = [[self selectionIndexes] copy];
[indexes addIndexesInRange:newSelectedRange];
}
}
else
indexes = [CPIndexSet indexSetWithIndex:index];
[self setSelectionIndexes:indexes];
}
else if (_allowsEmptySelection)
[self setSelectionIndexes:[CPIndexSet indexSet]];
}
@@ -696,6 +623,8 @@
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:dragTypes owner:self];
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
if (!_itemForDragging)
_itemForDragging = [self newItemForRepresentedObject:_content[[_selectionIndexes firstIndex]]];
else
@@ -768,28 +697,6 @@
return _delegate;
}
/*!
@ignore
*/
- (CPMenu)menuForEvent:(CPEvent)theEvent
{
if (![[self delegate] respondsToSelector:@selector(collectionView:menuForItemAtIndex:)])
return [super menuForEvent:theEvent];
var location = [self convertPoint:[theEvent locationInWindow] fromView:nil],
index = [self _indexAtPoint:location];
return [_delegate collectionView:self menuForItemAtIndex:index];
}
- (int)_indexAtPoint:(CGPoint)thePoint
{
var row = FLOOR(thePoint.y / (_itemSize.height + _verticalMargin)),
column = FLOOR(thePoint.x / (_itemSize.width + _horizontalMargin));
return row * _numberOfColumns + column;
}
- (CPCollectionViewItem)itemAtIndex:(unsigned)anIndex
{
return [_items objectAtIndex:anIndex];
@@ -820,29 +727,6 @@
@implementation CPCollectionView (KeyboardInteraction)
- (void)_modifySelectionWithNewIndex:(int)anIndex direction:(int)aDirection expand:(BOOL)shouldExpand
{
anIndex = MIN(MAX(anIndex, 0), [[self items] count] - 1);
if (_allowsMultipleSelection && shouldExpand)
{
var indexes = [_selectionIndexes copy],
bottomAnchor = [indexes firstIndex],
topAnchor = [indexes lastIndex];
// if the direction is backward (-1) check with the bottom anchor
if (aDirection === -1)
[indexes addIndexesInRange:CPMakeRange(anIndex, bottomAnchor - anIndex + 1)];
else
[indexes addIndexesInRange:CPMakeRange(topAnchor, anIndex - topAnchor + 1)];
}
else
indexes = [CPIndexSet indexSetWithIndex:anIndex];
[self setSelectionIndexes:indexes];
[self _scrollToSelection];
}
- (void)_scrollToSelection
{
var frame = [self frameForItemsAtIndexes:[self selectionIndexes]];
@@ -857,36 +741,26 @@
if (index === CPNotFound)
index = [[self items] count];
[self _modifySelectionWithNewIndex:index - 1 direction:-1 expand:NO];
}
index = MAX(index - 1, 0);
- (void)moveLeftAndModifySelection:(id)sender
{
var index = [[self selectionIndexes] firstIndex];
if (index === CPNotFound)
index = [[self items] count];
[self _modifySelectionWithNewIndex:index - 1 direction:-1 expand:YES];
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
[self _scrollToSelection];
}
- (void)moveRight:(id)sender
{
[self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + 1 direction:1 expand:NO];
}
var index = MIN([[self selectionIndexes] firstIndex] + 1, [[self items] count]-1);
- (void)moveRightAndModifySelection:(id)sender
{
[self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + 1 direction:1 expand:YES];
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
[self _scrollToSelection];
}
- (void)moveDown:(id)sender
{
[self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + [self numberOfColumns] direction:1 expand:NO];
}
var index = MIN([[self selectionIndexes] firstIndex] + [self numberOfColumns], [[self items] count]-1);
- (void)moveDownAndModifySelection:(id)sender
{
[self _modifySelectionWithNewIndex:[[self selectionIndexes] lastIndex] + [self numberOfColumns] direction:1 expand:YES];
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
[self _scrollToSelection];
}
- (void)moveUp:(id)sender
@@ -895,16 +769,10 @@
if (index == CPNotFound)
index = [[self items] count];
[self _modifySelectionWithNewIndex:index - [self numberOfColumns] direction:-1 expand:NO];
}
index = MAX(0, index - [self numberOfColumns]);
- (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];
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
[self _scrollToSelection];
}
- (void)deleteBackward:(id)sender
@@ -914,8 +782,8 @@
[[self delegate] collectionView:self shouldDeleteItemsAtIndexes:[self selectionIndexes]];
var index = [[self selectionIndexes] firstIndex];
if (index > [[self content] count] - 1)
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:[[self content] count] - 1]];
if (index > [[self content] count]-1)
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:[[self content] count]-1]];
[self _scrollToSelection];
[self setNeedsDisplay:YES];
@@ -949,33 +817,15 @@
@end
var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
CPCollectionViewMaxItemSizeKey = @"CPCollectionViewMaxItemSizeKey",
CPCollectionViewVerticalMarginKey = @"CPCollectionViewVerticalMarginKey",
CPCollectionViewMaxNumberOfRowsKey = @"CPCollectionViewMaxNumberOfRowsKey",
CPCollectionViewMaxNumberOfColumnsKey = @"CPCollectionViewMaxNumberOfColumnsKey",
CPCollectionViewSelectableKey = @"CPCollectionViewSelectableKey",
CPCollectionViewAllowsMultipleSelectionKey = @"CPCollectionViewAllowsMultipleSelectionKey",
CPCollectionViewBackgroundColorsKey = @"CPCollectionViewBackgroundColorsKey";
var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
CPCollectionViewMaxItemSizeKey = @"CPCollectionViewMaxItemSizeKey",
CPCollectionViewVerticalMarginKey = @"CPCollectionViewVerticalMarginKey",
CPCollectionViewSelectableKey = @"CPCollectionViewSelectableKey",
CPCollectionViewBackgroundColorsKey = @"CPCollectionViewBackgroundColorsKey";
@implementation CPCollectionView (CPCoding)
- (void)awakeFromCib
{
[super awakeFromCib];
if (CGSizeEqualToSize(_minItemSize, CGSizeMakeZero()) || CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero()))
{
var item = _itemPrototype;
if (CGSizeEqualToSize(_minItemSize, CGSizeMakeZero()))
_minItemSize = [[item view] frameSize];
else if (CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero()))
_maxItemSize = [[item view] frameSize];
}
}
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
@@ -992,13 +842,9 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeK
_minItemSize = [aCoder decodeSizeForKey:CPCollectionViewMinItemSizeKey] || CGSizeMakeZero();
_maxItemSize = [aCoder decodeSizeForKey:CPCollectionViewMaxItemSizeKey] || CGSizeMakeZero();
_maxNumberOfRows = [aCoder decodeIntForKey:CPCollectionViewMaxNumberOfRowsKey] || 0;
_maxNumberOfColumns = [aCoder decodeIntForKey:CPCollectionViewMaxNumberOfColumnsKey] || 0;
_verticalMargin = [aCoder decodeFloatForKey:CPCollectionViewVerticalMarginKey];
_isSelectable = [aCoder decodeBoolForKey:CPCollectionViewSelectableKey];
_allowsMultipleSelection = [aCoder decodeBoolForKey:CPCollectionViewAllowsMultipleSelectionKey];
[self setBackgroundColors:[aCoder decodeObjectForKey:CPCollectionViewBackgroundColorsKey]];
@@ -1022,11 +868,7 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeK
if (!CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero()))
[aCoder encodeSize:_maxItemSize forKey:CPCollectionViewMaxItemSizeKey];
[aCoder encodeInt:_maxNumberOfRows forKey:CPCollectionViewMaxNumberOfRowsKey];
[aCoder encodeInt:_maxNumberOfColumns forKey:CPCollectionViewMaxNumberOfColumnsKey];
[aCoder encodeBool:_isSelectable forKey:CPCollectionViewSelectableKey];
[aCoder encodeBool:_allowsMultipleSelection forKey:CPCollectionViewAllowsMultipleSelectionKey];
[aCoder encodeFloat:_verticalMargin forKey:CPCollectionViewVerticalMarginKey];
-1
View File
@@ -22,7 +22,6 @@
@import "CPViewController.j"
/*!
Represents an object inside a CPCollectionView.
*/
+102 -203
View File
@@ -27,13 +27,12 @@
@import "CPCompatibility.j"
@import "CPImage.j"
/// @cond IGNORE
var _redComponent = 0,
_greenComponent = 1,
_blueComponent = 2,
_alphaCompnent = 3;
var _hueComponent = 0,
_saturationComponent = 1,
_brightnessComponent = 2;
@@ -55,81 +54,27 @@ var cachedBlackColor,
cachedShadowColor,
cachedClearColor;
/// @endcond
/*!
Orientation to use with \c CPColorPattern for vertical patterns.
*/
CPColorPatternIsVertical = YES,
/*!
Orientation to use with \c CPColorPattern for horizontal patterns.
*/
CPColorPatternIsHorizontal = NO;
/*!
To create a simple color with a pattern image:
<code>CPColorWithImages(name, width, height{, bundle})</code>
To create a color with a three part pattern image:
<code>CPColorWithImages(slices{, orientation})</code>
where slices is an array of three [name, width, height{, bundle}] arrays,
and orientation is \c CPColorPatternIsVertical or \ref CPColorPatternIsHorizontal.
If orientatation is not passed, it defaults to \ref CPColorPatternIsHorizontal.
To create a color with a nine part pattern image:
<code>CPColorWithImages(slices);</code>
where slices is an array of nine [name, width, height{, bundle}] arrays.
*/
function CPColorWithImages()
{
if (arguments.length < 3)
{
var slices = arguments[0],
imageSlices = [];
for (var i = 0; i < slices.length; ++i)
{
var slice = slices[i];
imageSlices.push(slice ? CPImageInBundle(slice[0], CGSizeMake(slice[1], slice[2]), slice[3]) : nil);
}
if (imageSlices.length === 3)
return [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:imageSlices isVertical:arguments[1] || CPColorPatternIsHorizontal]];
else
return [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:imageSlices]];
}
else if (arguments.length === 3 || arguments.length === 4)
{
return [CPColor colorWithPatternImage:CPImageInBundle(arguments[0], CGSizeMake(arguments[1], arguments[2]), arguments[3])];
}
else
{
return nil;
}
}
/*!
/*!
@ingroup appkit
@code CPColor
\c CPColor can be used to represent color
in an RGB or HSB model with an optional transparency value.</p>
<p>It also provides some class helper methods that
returns instances of commonly used colors.</p>
<p>The class does not have a \c -set: method
like NextStep based frameworks to change the color of
the current context. To change the color of the current
context, use CGContextSetFillColor().
*/
@implementation CPColor : CPObject
{
CPArray _components;
CPImage _patternImage;
CPString _cssString;
CPString _cssString;
}
/*!
@@ -137,12 +82,12 @@ function CPColorWithImages()
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
@@ -152,17 +97,17 @@ function CPColorWithImages()
/*!
@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
@@ -174,10 +119,10 @@ function CPColorWithImages()
/*!
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
@@ -186,14 +131,14 @@ function CPColorWithImages()
}
/*!
@deprecated in favor of colorWithWhite:alpha:
@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
@@ -203,11 +148,11 @@ function CPColorWithImages()
/*!
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
@@ -217,16 +162,16 @@ function CPColorWithImages()
+ (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];
@@ -241,7 +186,7 @@ function CPColorWithImages()
Creates an RGB color from a hexadecimal string. For example,
the a string of "FFFFFF" would return a white CPColor.
"FF0000" would return a pure red, "00FF00" would return a
pure blue, and "0000FF" would return a pure green.
pure blue, and "0000FF" would return a pure green.
@param hex a 6 character long string of hex
@@ -249,8 +194,7 @@ function CPColorWithImages()
*/
+ (CPColor)colorWithHexString:(string)hex
{
var rgba = hexToRGB(hex);
return rgba ? [[CPColor alloc] _initWithRGBA: rgba] : null;
return [[CPColor alloc] _initWithRGBA: hexToRGB(hex)];
}
/*!
@@ -453,7 +397,7 @@ function CPColorWithImages()
/*!
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
*/
@@ -465,23 +409,23 @@ function CPColorWithImages()
/* @ignore */
- (id)_initWithCSSString:(CPString)aString
{
if (aString.indexOf("rgb") == CPNotFound)
if(aString.indexOf("rgb") == CPNotFound)
return nil;
self = [super init];
var startingIndex = aString.indexOf("("),
parts = aString.substring(startingIndex + 1).split(',');
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] ? parseFloat(parts[3], 10) : 1.0
];
parts[3] ? parseInt(parts[3], 10) / 255.0 : 1.0
]
_cssString = aString;
return self;
}
@@ -489,7 +433,7 @@ function CPColorWithImages()
- (id)_initWithRGBA:(CPArray)components
{
self = [super init];
if (self)
{
_components = components;
@@ -510,14 +454,14 @@ function CPColorWithImages()
- (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;
}
@@ -579,17 +523,17 @@ function CPColorWithImages()
/*!
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];
}
@@ -608,40 +552,37 @@ function CPColorWithImages()
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,
gr = (max - green) / delta,
br = (max - blue) / delta;
if (red == max)
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)
else if (green == max)
hue = 2 + rr - br;
else
else
hue = 4 + gr - rr;
hue /= 6;
if (hue < 0)
if (hue < 0)
hue++;
}
return [
ROUND(hue * 360.0),
ROUND(hue * 360.0),
ROUND(saturation * 100.0),
ROUND(brightness * 100.0)
];
@@ -666,7 +607,7 @@ url("data:image/png;base64,BASE64ENCODEDDATA") // if there is a pattern image
*/
- (CPString)hexString
{
return rgbToHex([self redComponent], [self greenComponent], [self blueComponent]);
return rgbToHex([self redComponent], [self greenComponent], [self blueComponent])
}
- (BOOL)isEqual:(CPColor)aColor
@@ -677,60 +618,19 @@ url("data:image/png;base64,BASE64ENCODEDDATA") // if there is a pattern image
if (aColor === self)
return YES;
if (![aColor isKindOfClass:CPColor])
return NO;
if (_patternImage || [aColor patternImage])
return [_patternImage isEqual:[aColor patternImage]];
// We don't require the components to be equal beyond 8 bits since otherwise
// simple rounding errors will make two colours which are exactly the same on
// screen compare unequal.
return ROUND([self redComponent] * 255.0) == ROUND([aColor redComponent] * 255.0) &&
ROUND([self greenComponent] * 255.0) == ROUND([aColor greenComponent] * 255.0) &&
ROUND([self blueComponent] * 255.0) == ROUND([aColor blueComponent] * 255.0) &&
[self alphaComponent] == [aColor alphaComponent];
return [aColor isKindOfClass:CPColor] && [aColor cssString] === [self cssString];
}
- (CPString)description
{
var description = [super description],
patternImage = [self patternImage];
if (!patternImage)
return description + " " + [self cssString];
description += " {\n";
if ([patternImage isThreePartImage] || [patternImage isNinePartImage])
{
var slices = [patternImage imageSlices];
if ([patternImage isThreePartImage])
description += " orientation: " + ([patternImage isVertical] ? "vertical" : "horizontal") + ",\n";
description += " patternImage (" + slices.length + " part): [\n";
for (var i = 0; i < slices.length; ++i)
{
var imgDescription = [slices[i] description];
description += imgDescription.replace(/^/mg, " ") + ",\n";
}
description = description.substr(0, description.length - 2) + "\n ]\n}";
}
else
description += [patternImage description].replace(/^/mg, " ") + "\n}";
return description;
return [super description]+" "+[self cssString];
}
@end
@implementation CPColor (CoreGraphicsExtensions)
/*!
/*!
Set's the receiver to be the fill and stroke color in the current graphics context
*/
- (void)set
@@ -739,16 +639,16 @@ url("data:image/png;base64,BASE64ENCODEDDATA") // if there is a pattern image
[self setStroke];
}
/*!
/*!
Set's the receiver to be the fill color in the current graphics context
*/
- (void)setFill
{
var ctx = [[CPGraphicsContext currentContext] graphicsPort];
CGContextSetFillColor(ctx, self);
CGContextSetFillColor(ctx, self);
}
/*!
/*!
Set's the receiver to be the stroke color in the current graphics context
*/
- (void)setStroke
@@ -768,10 +668,8 @@ url("data:image/png;base64,BASE64ENCODEDDATA") // if there is a pattern image
@end
/// @cond IGNORE
var CPColorComponentsKey = @"CPColorComponentsKey",
CPColorPatternImageKey = @"CPColorPatternImageKey";
/// @endcond
@implementation CPColor (CPCoding)
@@ -783,7 +681,7 @@ var CPColorComponentsKey = @"CPColorComponentsKey",
{
if ([aCoder containsValueForKey:CPColorPatternImageKey])
return [self _initWithPatternImage:[aCoder decodeObjectForKey:CPColorPatternImageKey]];
return [self _initWithRGBA:[aCoder decodeObjectForKey:CPColorComponentsKey]];
}
@@ -801,49 +699,50 @@ var CPColorComponentsKey = @"CPColorComponentsKey",
@end
/// @cond IGNORE
var hexCharacters = "0123456789ABCDEF";
/*
Used for the CPColor +colorWithHexString: implementation.
Returns an array of rgb components.
*/
var hexToRGB = function(hex)
{
if (hex.length == 3)
hex = hex.charAt(0) + hex.charAt(0) + hex.charAt(1) + hex.charAt(1) + hex.charAt(2) + hex.charAt(2);
// HACK: prevent these from becoming globals. workaround for obj-j "function foo(){}" behavior
var hexToRGB, rgbToHex, byteToHex;
if (hex.length != 6)
/*!
Used for the CPColor \c +colorWithHexString: implementation
@ignore
@class CPColor
@return an array of rgb components
*/
function hexToRGB(hex)
{
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)
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,
green = (hexCharacters.indexOf(hex.charAt(2)) * 16 + hexCharacters.indexOf(hex.charAt(3))) / 255.0,
blue = (hexCharacters.indexOf(hex.charAt(4)) * 16 + hexCharacters.indexOf(hex.charAt(5))) / 255.0;
var 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];
};
}
var rgbToHex = function(r,g,b)
{
function rgbToHex(r,g,b) {
return byteToHex(r) + byteToHex(g) + byteToHex(b);
};
}
var byteToHex = function(n)
{
if (!n || isNaN(n))
return "00";
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);
}
n = FLOOR(MIN(255, MAX(0, 256 * n)));
// Toll-Free bridge CPColor to CGColor.
//CGColor.prototype.isa = CPColor;
//[CPColor initialize];
return hexCharacters.charAt((n - n % 16) / 16) +
hexCharacters.charAt(n % 16);
};
/// @endcond
//http://dev.mootools.net/browser/trunk/Source/Utilities/Color.js?rev=1184
+82 -86
View File
@@ -20,13 +20,11 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPApplication.j"
@import "CPButton.j"
@import "CPCookie.j"
@import "CPPanel.j"
@import "CPView.j"
CPColorPanelColorDidChangeNotification = @"CPColorPanelColorDidChangeNotification";
var PREVIEW_HEIGHT = 20.0,
@@ -37,7 +35,7 @@ var PREVIEW_HEIGHT = 20.0,
var SharedColorPanel = nil,
ColorPickerClasses = [];
/*
A color wheel
@global
@@ -54,7 +52,7 @@ CPSliderColorPickerMode = 2;
CPColorPickerViewWidth = 265,
CPColorPickerViewHeight = 370;
/*!
/*!
@ingroup appkit
@class CPColorPanel
@@ -63,7 +61,7 @@ CPColorPickerViewHeight = 370;
obtain the panel, call the \c +sharedColorPanel method.
*/
@implementation CPColorPanel : CPPanel
{
{
_CPColorPanelToolbar _toolbar;
_CPColorPanelSwatches _swatchView;
_CPColorPanelPreview _previewView;
@@ -82,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
@@ -98,7 +96,7 @@ CPColorPickerViewHeight = 370;
{
if (!SharedColorPanel)
SharedColorPanel = [[CPColorPanel alloc] init];
return SharedColorPanel;
}
@@ -109,7 +107,7 @@ CPColorPickerViewHeight = 370;
+ (void)setPickerMode:(CPColorPanelMode)mode
{
var panel = [CPColorPanel sharedColorPanel];
[panel setMode:mode];
[panel setMode: mode];
}
/*
@@ -118,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)
@@ -127,14 +125,14 @@ CPColorPickerViewHeight = 370;
[self setTitle:@"Color Panel"];
[self setLevel:CPFloatingWindowLevel];
[self setFloatingPanel:YES];
[self setBecomesKeyOnlyIfNeeded:YES];
[self setMinSize:CGSizeMake(219.0, 363.0)];
[self setMinSize:CGSizeMake(219.0, 342.0)];
[self setMaxSize:CGSizeMake(323.0, 537.0)];
}
return self;
}
@@ -145,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];
@@ -167,7 +165,7 @@ CPColorPickerViewHeight = 370;
- (void)setColor:(CPColor)aColor updatePicker:(BOOL)bool
{
[self setColor:aColor];
if (bool)
[_activePicker setColor:_color];
}
@@ -234,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]];
}
@@ -287,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];
@@ -299,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 setAutoresizingMask:CPViewMinXMargin|CPViewMaxXMargin];
[button setImage:image];
[button setAlternateImage:highlightImage];
[_toolbar addSubview:button];
if (!buttonForLater)
buttonForLater = button;
}
@@ -332,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];
@@ -340,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];
@@ -352,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];
@@ -369,10 +367,9 @@ 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];
[_opacitySlider setAutoresizingMask:CPViewWidthSizable];
[_opacitySlider setTarget:self];
[_opacitySlider setAction:@selector(setOpacity:)];
@@ -418,37 +415,37 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
CPCookie _swatchCookie;
}
- (id)initWithFrame:(CPRect)aFrame
-(id)initWithFrame:(CPRect)aFrame
{
self = [super initWithFrame:aFrame];
[self setBackgroundColor: [CPColor grayColor]];
[self registerForDraggedTypes:[CPArray arrayWithObjects:CPColorDragType]];
var whiteColor = [CPColor whiteColor];
_swatchCookie = [[CPCookie alloc] initWithName: CPColorPanelSwatchesCookie];
var colorList = [self startingColorList];
_swatches = [];
for (var i = 0; i < 50; i++)
for(var i=0; i < 50; i++)
{
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
var view = [[CPView alloc] initWithFrame: CPRectMake(13 * i + 1, 1, 12, 12)],
var view = [[CPView alloc] initWithFrame: CPRectMake(13*i+1, 1, 12, 12)],
fillView = [[CPView alloc] initWithFrame:CGRectInset([view bounds], 1.0, 1.0)];
[view setBackgroundColor:whiteColor];
[fillView setBackgroundColor: (i < colorList.length) ? colorList[i] : whiteColor];
[view addSubview:fillView];
[self addSubview: view];
_swatches.push(view);
}
return self;
}
@@ -460,8 +457,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
- (CPArray)startingColorList
{
var cookieValue = [_swatchCookie value];
if (cookieValue == "")
if(cookieValue == "")
{
return [
[CPColor blackColor],
@@ -475,11 +471,11 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
[CPColor yellowColor]
];
}
var cookieValue = eval(cookieValue),
result = [];
for (var i = 0; i < cookieValue.length; i++)
var cookieValue = eval(cookieValue);
var result = [];
for(var i=0; i<cookieValue.length; i++)
result.push([CPColor colorWithHexString: cookieValue[i]]);
return result;
@@ -489,12 +485,12 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
{
var result = [];
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/25-implement-cpbox
for (var i = 0; i < _swatches.length; i++)
for(var i=0; i<_swatches.length; i++)
result.push([[[_swatches[i] subviews][0] backgroundColor] hexString]);
var future = new Date();
future.setYear(2019);
[_swatchCookie setValue: JSON.stringify(result) expires:future domain: nil];
}
@@ -524,8 +520,8 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
{
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil],
bounds = [self bounds];
if (!CGRectContainsPoint(bounds, point) || point.x > [self bounds].size.width - 1 || point.x < 1)
if(!CGRectContainsPoint(bounds, point) || point.x > [self bounds].size.width - 1 || point.x < 1)
return NO;
[_colorPanel setColor: [self colorAtIndex:FLOOR(point.x / 13)] updatePicker: YES];
@@ -535,25 +531,25 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
{
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
if (point.x > [self bounds].size.width - 1 || point.x < 1)
if(point.x > [self bounds].size.width - 1 || point.x < 1)
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
@@ -567,19 +563,19 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
{
if (aType == CPColorDragType)
if(aType == CPColorDragType)
[aPasteboard setData:[CPKeyedArchiver archivedDataWithRootObject:_dragColor] forType:aType];
}
- (void)performDragOperation:(id <CPDraggingInfo>)aSender
{
{
var location = [self convertPoint:[aSender draggingLocation] fromView:nil],
pasteboard = [aSender draggingPasteboard],
swatch = nil;
if (![pasteboard availableTypeFromArray:[CPColorDragType]] || location.x > [self bounds].size.width - 1 || location.x < 1)
if(![pasteboard availableTypeFromArray:[CPColorDragType]] || location.x > [self bounds].size.width - 1 || location.x < 1)
return NO;
[self setColor:[CPKeyedUnarchiver unarchiveObjectWithData:[pasteboard dataForType:CPColorDragType]] atIndex: FLOOR(location.x / 13)];
}
@@ -594,9 +590,9 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
- (id)initWithFrame:(CPRect)aFrame
{
self = [super initWithFrame:aFrame];
[self registerForDraggedTypes:[CPArray arrayWithObjects:CPColorDragType]];
return self;
}
@@ -614,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];
}
@@ -630,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)
@@ -654,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];
}
+39 -36
View File
@@ -21,11 +21,11 @@
*/
@import <Foundation/CPObject.j>
@import "CPColorPanel.j"
@import "CPView.j"
#include "Platform/Platform.h"
/*!
/*!
@ingroup appkit
@class CPColorPicker
@@ -102,18 +102,18 @@
CPColor _cachedColor;
}
- (id)initWithPickerMask:(int)mask colorPanel:(CPColorPanel)owningColorPanel
- (id)initWithPickerMask:(int)mask colorPanel:(CPColorPanel)owningColorPanel
{
return [super initWithPickerMask:mask colorPanel: owningColorPanel];
}
- (id)initView
-(id)initView
{
aFrame = CPRectMake(0, 0, CPColorPickerViewWidth, CPColorPickerViewHeight);
_pickerView = [[CPView alloc] initWithFrame:aFrame];
[_pickerView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
[_pickerView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
_brightnessSlider = [[CPSlider alloc] initWithFrame:CGRectMake(0, (aFrame.size.height - 34), aFrame.size.width, 15)];
@@ -136,17 +136,17 @@
[_pickerView addSubview:_brightnessSlider];
}
- (void)brightnessSliderDidChange:(id)sender
-(void)brightnessSliderDidChange:(id)sender
{
[self updateColor];
}
- (void)colorWheelDidChange:(id)sender
-(void)colorWheelDidChange:(id)sender
{
[self updateColor];
}
- (void)updateColor
-(void)updateColor
{
var hue = [_hueSaturationView angle],
saturation = [_hueSaturationView distance],
@@ -223,7 +223,7 @@
float _radius;
}
- (id)initWithFrame:(CPRect)aFrame
-(id)initWithFrame:(CPRect)aFrame
{
self = [super initWithFrame:aFrame];
@@ -261,19 +261,19 @@
return self;
}
- (void)setWheelBrightness:(float)brightness
-(void)setWheelBrightness:(float)brightness
{
_blackWheelImage.style.opacity = 1.0 - brightness;
_blackWheelImage.style.filter = "alpha(opacity=" + (1.0 - brightness) * 100 + ")"
_blackWheelImage.style.filter = "alpha(opacity=" + (1.0 - brightness)*100 + ")"
}
- (void)setFrameSize:(CPSize)aSize
-(void)setFrameSize:(CPSize)aSize
{
[super setFrameSize:aSize];
[self setWheelSize:aSize];
}
- (void)setWheelSize:(CPSize)aSize
-(void)setWheelSize:(CPSize)aSize
{
var min = MIN(aSize.width, aSize.height);
@@ -296,55 +296,57 @@
[self setAngle:[self degreesToRadians:_angle] distance:(_distance / 100.0) * _radius];
}
- (void)setDelegate:(id)aDelegate
-(void)setDelegate:(id)aDelegate
{
_delegate = aDelegate;
}
- (id)delegate
-(id)delegate
{
return _delegate;
}
- (float)angle
-(float)angle
{
return _angle;
}
- (float)distance
-(float)distance
{
return _distance;
}
- (void)mouseDown:(CPEvent)anEvent
-(void)mouseDown:(CPEvent)anEvent
{
[self reposition:anEvent];
}
- (void)mouseDragged:(CPEvent)anEvent
-(void)mouseDragged:(CPEvent)anEvent
{
[self reposition:anEvent];
}
- (void)reposition:(CPEvent)anEvent
-(void)reposition:(CPEvent)anEvent
{
var bounds = [self bounds],
location = [self convertPoint:[anEvent locationInWindow] fromView:nil],
midX = CGRectGetMidX(bounds),
midY = CGRectGetMidY(bounds),
distance = MIN(SQRT((location.x - midX) * (location.x - midX) + (location.y - midY) * (location.y - midY)), _radius),
angle = ATAN2(location.y - midY, location.x - midX);
location = [self convertPoint:[anEvent locationInWindow] fromView:nil];
var midX = CGRectGetMidX(bounds);
var midY = CGRectGetMidY(bounds);
var distance = MIN(SQRT((location.x - midX)*(location.x - midX) + (location.y - midY)*(location.y - midY)), _radius);
var angle = ATAN2(location.y - midY, location.x - midX);
[self setAngle:angle distance:distance];
[_delegate colorWheelDidChange:self];
}
- (void)setAngle:(int)angle distance:(float)distance
-(void)setAngle:(int)angle distance:(float)distance
{
var bounds = [self bounds],
midX = CGRectGetMidX(bounds),
midY = CGRectGetMidY(bounds);
var bounds = [self bounds];
var midX = CGRectGetMidX(bounds);
var midY = CGRectGetMidY(bounds);
_angle = [self radiansToDegrees:angle];
_distance = (distance / _radius) * 100.0;
@@ -352,22 +354,23 @@
[_crosshair setFrameOrigin:CPPointMake(COS(angle) * distance + midX - 2.0, SIN(angle) * distance + midY - 2.0)];
}
- (void)setPositionToColor:(CPColor)aColor
-(void)setPositionToColor:(CPColor)aColor
{
var hsb = [aColor hsbComponents],
bounds = [self bounds],
angle = [self degreesToRadians:hsb[0]],
bounds = [self bounds];
var angle = [self degreesToRadians:hsb[0]],
distance = (hsb[1] / 100.0) * _radius;
[self setAngle:angle distance:distance];
}
- (int)radiansToDegrees:(float)radians
-(int)radiansToDegrees:(float)radians
{
return ((-radians / PI) * 180 + 360) % 360;
}
- (float)degreesToRadians:(float)degrees
-(float)degreesToRadians:(float)degrees
{
return -(((degrees - 360) / 180) * PI);
}
+29 -29
View File
@@ -29,7 +29,7 @@
var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiveNotification";
/*!
/*!
@ingroup appkit
@class CPColorWell
@@ -41,7 +41,7 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
{
BOOL _active;
BOOL _bordered;
CPColor _color;
CPView _wellView;
}
@@ -49,19 +49,19 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
_active = NO;
_bordered = YES;
_color = [CPColor whiteColor];
[self drawBezelWithHighlight:NO];
[self drawWellInside:CGRectInset([self bounds], 3.0, 3.0)];
[self _registerForNotifications];
}
return self;
}
@@ -97,9 +97,9 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
{
if (_bordered == bordered)
return;
_bordered = bordered;
[self drawWellInside:CGRectInset([self bounds], 3.0, 3.0)];
}
@@ -120,9 +120,9 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
{
if (_color == aColor)
return;
_color = aColor;
[self drawWellInside:CGRectInset([self bounds], 3.0, 3.0)];
}
@@ -137,7 +137,7 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
// Activating and Deactivating Color Wells
/*!
Activates the color well, displays the color panel, and makes the panel's current color the same as its own.
Activates the color well, displays the color panel, and makes the panel's current color the same as its own.
If exclusive is \c YES, deactivates any other CPColorWells. \c NO, keeps them active.
@param shouldBeExclusive whether other color wells should be deactivated.
*/
@@ -152,9 +152,9 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
if ([self isActive])
return;
_active = YES;
[[CPNotificationCenter defaultCenter]
addObserver:self
selector:@selector(colorPanelDidChangeColor:)
@@ -169,9 +169,9 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
{
if (![self isActive])
return;
_active = NO;
[[CPNotificationCenter defaultCenter]
removeObserver:self
name:CPColorPanelColorDidChangeNotification
@@ -202,19 +202,19 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
{
_wellView = [[CPView alloc] initWithFrame:aRect];
[_wellView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
[self addSubview:_wellView];
}
else
[_wellView setFrame:aRect];
[_wellView setBackgroundColor:_color];
}
- (void)colorPanelDidChangeColor:(CPNotification)aNotification
{
[self takeColorFrom:[aNotification object]];
[self sendAction:[self action] to:[self target]];
}
@@ -245,17 +245,17 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
[self drawBezelWithHighlight:CGRectContainsPoint([self bounds], [self convertPoint:[anEvent locationInWindow] fromView:nil])];
}
- (void)mouseUp:(CPEvent)anEvent
-(void)mouseUp:(CPEvent)anEvent
{
[self drawBezelWithHighlight:NO];
if (!CGRectContainsPoint([self bounds], [self convertPoint:[anEvent locationInWindow] fromView:nil]) || ![self isEnabled])
return;
[self activate:YES];
var colorPanel = [CPColorPanel sharedColorPanel];
[colorPanel setColor:_color];
[colorPanel orderFront:self];
}
@@ -274,11 +274,11 @@ var CPColorWellColorKey = "CPColorWellColorKey",
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
_active = NO;
_bordered = [aCoder decodeBoolForKey:CPColorWellBorderedKey];
_bordered = [aCoder decodeObjectForKey:CPColorWellBorderedKey];
_color = [aCoder decodeObjectForKey:CPColorWellColorKey];
[self drawBezelWithHighlight:NO];
@@ -286,7 +286,7 @@ var CPColorWellColorKey = "CPColorWellColorKey",
[self _registerForNotifications];
}
return self;
}
@@ -296,17 +296,17 @@ var CPColorWellColorKey = "CPColorWellColorKey",
*/
- (void)encodeWithCoder:(CPCoder)aCoder
{
// We do this in order to avoid encoding the _wellView, which
// We do this in order to avoid encoding the _wellView, which
// should just automatically be created programmatically as needed.
var actualSubviews = _subviews;
_subviews = [_subviews copy];
[_subviews removeObjectIdenticalTo:_wellView];
[super encodeWithCoder:aCoder];
_subviews = actualSubviews;
[aCoder encodeObject:_color forKey:CPColorWellColorKey];
[aCoder encodeObject:_bordered forKey:CPColorWellBorderedKey];
}
+28 -33
View File
@@ -23,7 +23,6 @@
@import "CPEvent.j"
@import "CPPlatform.j"
// Browser Engines
CPUnknownBrowserEngine = 0;
CPGeckoBrowserEngine = 1;
@@ -44,20 +43,20 @@ CPHTMLCanvasFeature = 1 << 6;
CPHTMLContentEditableFeature = 1 << 7;
CPHTMLDragAndDropFeature = 1 << 8;
CPJavaScriptInnerTextFeature = 1 << 9;
CPJavaScriptTextContentFeature = 1 << 10;
CPJavaScriptClipboardEventsFeature = 1 << 11;
CPJavaScriptClipboardAccessFeature = 1 << 12;
CPJavascriptInnerTextFeature = 1 << 9;
CPJavascriptTextContentFeature = 1 << 10;
CPJavascriptClipboardEventsFeature = 1 << 11;
CPJavascriptClipboardAccessFeature = 1 << 12;
CPJavaScriptCanvasDrawFeature = 1 << 13;
CPJavaScriptCanvasTransformFeature = 1 << 14;
CPVMLFeature = 1 << 15;
CPJavaScriptRemedialKeySupport = 1 << 16;
CPJavascriptRemedialKeySupport = 1 << 16;
CPJavaScriptShadowFeature = 1 << 20;
CPJavaScriptNegativeMouseWheelValues = 1 << 22;
CPJavaScriptMouseWheelValues_8_15 = 1 << 23;
CPJavaScriptMouseWheelValues_8_15 = 1 << 23
CPOpacityRequiresFilterFeature = 1 << 24;
@@ -65,7 +64,6 @@ CPOpacityRequiresFilterFeature = 1 << 24;
CPInputTypeCanBeChangedFeature = 1 << 25;
CPHTML5DragAndDropSourceYOffBy1 = 1 << 26;
CPSOPDisabledFromFileURLs = 1 << 27;
var USER_AGENT = "",
PLATFORM_ENGINE = CPUnknownBrowserEngine,
@@ -79,23 +77,23 @@ if (typeof window !== "undefined" && typeof window.navigator !== "undefined")
USER_AGENT = window.navigator.userAgent;
// Opera
if (typeof window !== "undefined" && window.opera)
if (window.opera)
{
PLATFORM_ENGINE = CPOperaBrowserEngine;
PLATFORM_FEATURES |= CPJavaScriptCanvasDrawFeature;
}
// Internet Explorer
else if (typeof window !== "undefined" && window.attachEvent) // Must follow Opera check.
else if (window.attachEvent) // Must follow Opera check.
{
PLATFORM_ENGINE = CPInternetExplorerBrowserEngine;
// Features we can only be sure of with IE (no known independent tests)
PLATFORM_FEATURES |= CPVMLFeature;
PLATFORM_FEATURES |= CPJavaScriptRemedialKeySupport;
PLATFORM_FEATURES |= CPJavascriptRemedialKeySupport;
PLATFORM_FEATURES |= CPJavaScriptShadowFeature;
PLATFORM_FEATURES |= CPOpacityRequiresFilterFeature;
PLATFORM_FEATURES &= ~CPInputTypeCanBeChangedFeature;
@@ -105,7 +103,7 @@ else if (typeof window !== "undefined" && window.attachEvent) // Must follow Ope
else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
{
PLATFORM_ENGINE = CPWebKitBrowserEngine;
// Features we can only be sure of with WebKit (no known independent tests)
PLATFORM_FEATURES |= CPCSSRGBAFeature;
PLATFORM_FEATURES |= CPHTMLContentEditableFeature;
@@ -113,10 +111,10 @@ else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
if (USER_AGENT.indexOf("Chrome") === -1)
PLATFORM_FEATURES |= CPHTMLDragAndDropFeature;
PLATFORM_FEATURES |= CPJavaScriptClipboardEventsFeature;
PLATFORM_FEATURES |= CPJavaScriptClipboardAccessFeature;
PLATFORM_FEATURES |= CPJavascriptClipboardEventsFeature;
PLATFORM_FEATURES |= CPJavascriptClipboardAccessFeature;
PLATFORM_FEATURES |= CPJavaScriptShadowFeature;
var versionStart = USER_AGENT.indexOf("AppleWebKit/") + "AppleWebKit/".length,
versionEnd = USER_AGENT.indexOf(" ", versionStart),
versionString = USER_AGENT.substring(versionStart, versionEnd),
@@ -124,19 +122,16 @@ else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
majorVersion = parseInt(versionString.substring(0, versionDivision)),
minorVersion = parseInt(versionString.substr(versionDivision + 1));
if ((USER_AGENT.indexOf("Safari") !== CPNotFound && (majorVersion > 525 || (majorVersion === 525 && minorVersion > 14))) || USER_AGENT.indexOf("Chrome") !== CPNotFound)
PLATFORM_FEATURES |= CPJavaScriptRemedialKeySupport;
if((USER_AGENT.indexOf("Safari") !== CPNotFound && (majorVersion > 525 || (majorVersion === 525 && minorVersion > 14))) || USER_AGENT.indexOf("Chrome") !== CPNotFound)
PLATFORM_FEATURES |= CPJavascriptRemedialKeySupport;
// FIXME this is a terrible hack to get around this bug:
// https://bugs.webkit.org/show_bug.cgi?id=21548
if (![CPPlatform isBrowser])
PLATFORM_FEATURES |= CPJavaScriptRemedialKeySupport;
PLATFORM_FEATURES |= CPJavascriptRemedialKeySupport;
if (majorVersion < 532 || (majorVersion === 532 && minorVersion < 6))
PLATFORM_FEATURES |= CPHTML5DragAndDropSourceYOffBy1;
if (USER_AGENT.indexOf("Chrome") === CPNotFound)
PLATFORM_FEATURES |= CPSOPDisabledFromFileURLs;
}
// KHTML
@@ -149,12 +144,12 @@ else if (USER_AGENT.indexOf("KHTML") != -1) // Must follow WebKit check.
else if (USER_AGENT.indexOf("Gecko") !== -1) // Must follow KHTML check.
{
PLATFORM_ENGINE = CPGeckoBrowserEngine;
PLATFORM_FEATURES |= CPJavaScriptCanvasDrawFeature;
var index = USER_AGENT.indexOf("Firefox"),
version = (index === -1) ? 2.0 : parseFloat(USER_AGENT.substring(index + "Firefox".length + 1));
if (version >= 3.0)
PLATFORM_FEATURES |= CPCSSRGBAFeature;
@@ -170,21 +165,21 @@ if (typeof document != "undefined")
if (canvasElement && canvasElement.getContext)
{
PLATFORM_FEATURES |= CPHTMLCanvasFeature;
// Detect Canvas setTransform/transform support
var context = document.createElement("canvas").getContext("2d");
if (context && context.setTransform && context.transform)
PLATFORM_FEATURES |= CPJavaScriptCanvasTransformFeature;
}
var DOMElement = document.createElement("div");
// Detect whether we have innerText or textContent (or neither)
if (DOMElement.innerText != undefined)
PLATFORM_FEATURES |= CPJavaScriptInnerTextFeature;
PLATFORM_FEATURES |= CPJavascriptInnerTextFeature;
else if (DOMElement.textContent != undefined)
PLATFORM_FEATURES |= CPJavaScriptTextContentFeature;
PLATFORM_FEATURES |= CPJavascriptTextContentFeature;
}
function CPFeatureIsCompatible(aFeature)
+121 -382
View File
@@ -23,7 +23,9 @@
@import "CPFont.j"
@import "CPShadow.j"
@import "CPView.j"
@import "CPKeyValueBinding.j"
#include "CoreGraphics/CGGeometry.h"
#include "Platform/Platform.h"
CPLeftTextAlignment = 0;
CPRightTextAlignment = 1;
@@ -42,21 +44,21 @@ CPLineBreakByTruncatingHead = 3;
CPLineBreakByTruncatingTail = 4;
CPLineBreakByTruncatingMiddle = 5;
CPTopVerticalTextAlignment = 1;
CPCenterVerticalTextAlignment = 2;
CPTopVerticalTextAlignment = 1,
CPCenterVerticalTextAlignment = 2,
CPBottomVerticalTextAlignment = 3;
CPScaleProportionally = 0;
CPScaleToFit = 1;
CPScaleNone = 2;
CPScaleProportionally = 0;
CPScaleToFit = 1;
CPScaleNone = 2;
CPNoImage = 0;
CPImageOnly = 1;
CPImageLeft = 2;
CPImageRight = 3;
CPImageBelow = 4;
CPImageAbove = 5;
CPImageOverlaps = 6;
CPNoImage = 0;
CPImageOnly = 1;
CPImageLeft = 2;
CPImageRight = 3;
CPImageBelow = 4;
CPImageAbove = 5;
CPImageOverlaps = 6;
CPOnState = 1;
CPOffState = 0;
@@ -71,9 +73,9 @@ CPControlTextDidBeginEditingNotification = "CPControlTextDidBeginEditingNotif
CPControlTextDidChangeNotification = "CPControlTextDidChangeNotification";
CPControlTextDidEndEditingNotification = "CPControlTextDidEndEditingNotification";
var CPControlBlackColor = [CPColor blackColor];
var CPControlBlackColor = [CPColor blackColor];
/*!
/*!
@ingroup appkit
@class CPControl
@@ -82,7 +84,7 @@ var CPControlBlackColor = [CPColor blackColor];
@implementation CPControl : CPView
{
id _value;
// Target-Action Support
id _target;
SEL _action;
@@ -94,6 +96,8 @@ var CPControlBlackColor = [CPColor blackColor];
BOOL _trackingWasWithinFrame;
unsigned _trackingMouseDownFlags;
CGPoint _previousTrackingLocation;
CPString _toolTip;
}
+ (CPDictionary)themeAttributes
@@ -122,66 +126,21 @@ var CPControlBlackColor = [CPColor blackColor];
@"max-size"]];
}
+ (void)initialize
{
if (self === [CPControl class])
{
[self exposeBinding:@"value"];
[self exposeBinding:@"objectValue"];
[self exposeBinding:@"stringValue"];
[self exposeBinding:@"integerValue"];
[self exposeBinding:@"intValue"];
[self exposeBinding:@"doubleValue"];
[self exposeBinding:@"floatValue"];
[self exposeBinding:@"enabled"];
}
}
+ (Class)_binderClassForBinding:(CPString)theBinding
{
if (theBinding === CPValueBinding)
return [_CPValueBinder class];
return [super _binderClassForBinding:theBinding];
}
/*!
Reverse set the binding iff the CPContinuouslyUpdatesValueBindingOption is set.
*/
- (void)_continuouslyReverseSetBinding
{
var binderClass = [[self class] _binderClassForBinding:CPValueBinding],
theBinding = [binderClass getBinding:CPValueBinding forObject:self];
if ([theBinding continuouslyUpdatesValue])
[theBinding reverseSetValueFor:@"objectValue"];
}
- (void)_reverseSetBinding
{
var binderClass = [[self class] _binderClassForBinding:CPValueBinding],
theBinding = [binderClass getBinding:CPValueBinding forObject:self];
[theBinding reverseSetValueFor:@"objectValue"];
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
_sendActionOn = CPLeftMouseUpMask;
_trackingMouseDownFlags = 0;
}
return self;
}
/*!
Sets the receiver's target action.
Sets the receiver's target action
@param anAction Sets the action message that gets sent to the target.
*/
- (void)setAction:(SEL)anAction
@@ -190,7 +149,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Returns the receiver's target action.
Returns the receiver's target action
*/
- (SEL)action
{
@@ -199,7 +158,6 @@ var CPControlBlackColor = [CPColor blackColor];
/*!
Sets the receiver's target. The target receives action messages from the receiver.
@param aTarget the object that will receive the message specified by action
*/
- (void)setTarget:(id)aTarget
@@ -217,25 +175,50 @@ var CPControlBlackColor = [CPColor blackColor];
/*!
Causes \c anAction to be sent to \c anObject.
@param anAction the action to send
@param anObject the object to which the action will be sent
*/
- (void)sendAction:(SEL)anAction to:(id)anObject
{
[self _reverseSetBinding];
[CPApp sendAction:anAction to:anObject from:self];
}
- (int)sendActionOn:(int)mask
{
var previousMask = _sendActionOn;
_sendActionOn = mask;
return previousMask;
}
/*!
Sets the tooltip for the receiver.
@param aToolTip the tooltip
*/
/*
-(void)setToolTip:(CPString)aToolTip
{
if (_toolTip == aToolTip)
return;
_toolTip = aToolTip;
#if PLATFORM(DOM)
_DOMElement.title = aToolTip;
#endif
}
*/
/*!
Returns the receiver's tooltip
*/
/*
-(CPString)toolTip
{
return _toolTip;
}
*/
/*!
Returns whether the control can continuously send its action messages.
*/
@@ -247,19 +230,16 @@ var CPControlBlackColor = [CPColor blackColor];
/*!
Sets whether the cell can continuously send its action messages.
*/
*/
- (void)setContinuous:(BOOL)flag
{
// Some subclasses should redefine this with CPLeftMouseDraggedMask
if (flag)
_sendActionOn |= CPPeriodicMask;
else
else
_sendActionOn &= ~CPPeriodicMask;
}
/*!
Returns YES if the receiver tracks the mouse outside the frame, otherwise NO.
*/
- (BOOL)tracksMouseOutsideOfFrame
{
return NO;
@@ -268,22 +248,18 @@ var CPControlBlackColor = [CPColor blackColor];
- (void)trackMouse:(CPEvent)anEvent
{
var type = [anEvent type],
currentLocation = [self convertPoint:[anEvent locationInWindow] fromView:nil],
currentLocation = [self convertPoint:[anEvent locationInWindow] fromView:nil];
isWithinFrame = [self tracksMouseOutsideOfFrame] || CGRectContainsPoint([self bounds], currentLocation);
if (type === CPLeftMouseUp)
{
[self stopTracking:_previousTrackingLocation at:currentLocation mouseIsUp:YES];
_trackingMouseDownFlags = 0;
if (isWithinFrame)
[self setThemeState:CPThemeStateHovered];
}
else
{
[self unsetThemeState:CPThemeStateHovered];
if (type === CPLeftMouseDown)
{
_trackingMouseDownFlags = [anEvent modifierFlags];
@@ -295,20 +271,20 @@ var CPControlBlackColor = [CPColor blackColor];
{
if (!_trackingWasWithinFrame)
_continuousTracking = [self startTrackingAt:currentLocation];
else if (_continuousTracking)
_continuousTracking = [self continueTracking:_previousTrackingLocation at:currentLocation];
}
else
[self stopTracking:_previousTrackingLocation at:currentLocation mouseIsUp:NO];
}
[CPApp setTarget:self selector:@selector(trackMouse:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
}
if ((_sendActionOn & (1 << type)) && isWithinFrame)
[self sendAction:_action to:_target];
_trackingWasWithinFrame = isWithinFrame;
_previousTrackingLocation = currentLocation;
}
@@ -322,45 +298,20 @@ var CPControlBlackColor = [CPColor blackColor];
return 0;
}
/*!
Perform a click on the receiver.
@param sender - The sender object
*/
- (void)performClick:(id)sender
- (void)performClick:(id)sender
{
if (![self isEnabled])
return;
[self highlight:YES];
[self setState:[self nextState]];
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];
}
[self sendAction:[self action] to:[self target]];
[CPTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(unhighlightButtonTimerDidFinish:) userInfo:nil repeats:NO];
}
/*!
@ignore
Fired when the button timer finished, usually after the user hits enter.
*/
- (void)unhighlightButtonTimerDidFinish:(id)sender
{
[self highlight:NO];
}
/*!
Returns the mask of modifier keys held down when the user clicked.
*/
- (unsigned)mouseDownFlags
{
return _trackingMouseDownFlags;
@@ -369,7 +320,7 @@ var CPControlBlackColor = [CPColor blackColor];
- (BOOL)startTrackingAt:(CGPoint)aPoint
{
[self highlight:YES];
return (_sendActionOn & CPPeriodicMask) || (_sendActionOn & CPLeftMouseDraggedMask);
}
@@ -387,31 +338,12 @@ var CPControlBlackColor = [CPColor blackColor];
{
if (![self isEnabled])
return;
[self trackMouse:anEvent];
}
- (void)mouseEntered:(CPEvent)anEvent
{
if (![self isEnabled])
return;
[self setThemeState:CPThemeStateHovered];
}
- (void)mouseExited:(CPEvent)anEvent
{
var currentLocation = [self convertPoint:[anEvent locationInWindow] fromView:nil],
isWithinFrame = [self tracksMouseOutsideOfFrame] || CGRectContainsPoint([self bounds], currentLocation);
// Make sure we're not still in the frame because Cappuccino will sent mouseExited events
// for all of the (ephemeral) subviews of a view as well.
if (!isWithinFrame)
[self unsetThemeState:CPThemeStateHovered];
}
/*!
Returns the receiver's object value.
Returns the receiver's object value
*/
- (id)objectValue
{
@@ -419,18 +351,18 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Sets the receiver's object value.
Set's the receiver's object value
*/
- (void)setObjectValue:(id)anObject
{
_value = anObject;
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
/*!
Returns the receiver's float value.
Returns the receiver's float value
*/
- (float)floatValue
{
@@ -439,7 +371,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Sets the receiver's float value.
Sets the receiver's float value
*/
- (void)setFloatValue:(float)aValue
{
@@ -447,7 +379,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Returns the receiver's double value.
Returns the receiver's double value
*/
- (double)doubleValue
{
@@ -456,7 +388,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Sets the receiver's double value.
Set's the receiver's double value
*/
- (void)setDoubleValue:(double)anObject
{
@@ -464,7 +396,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Returns the receiver's int value.
Returns the receiver's int value
*/
- (int)intValue
{
@@ -473,7 +405,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Sets the receiver's int value.
Set's the receiver's int value
*/
- (void)setIntValue:(int)anObject
{
@@ -481,7 +413,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Returns the receiver's int value.
Returns the receiver's int value
*/
- (int)integerValue
{
@@ -490,7 +422,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Sets the receiver's int value.
Set's the receiver's int value
*/
- (void)setIntegerValue:(int)anObject
{
@@ -498,7 +430,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Returns the receiver's string value.
Returns the receiver's int value
*/
- (CPString)stringValue
{
@@ -506,7 +438,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Sets the receiver's string value.
Set's the receiver's int value
*/
- (void)setStringValue:(CPString)anObject
{
@@ -553,228 +485,55 @@ var CPControlBlackColor = [CPColor blackColor];
[self setStringValue:[sender stringValue]];
}
- (void)textDidBeginEditing:(CPNotification)note
- (void)textDidBeginEditing:(CPNotification)note
{
//this looks to prevent false propagation of notifications for other objects
if ([note object] != self)
if([note object] != self)
return;
[[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidBeginEditingNotification object:self userInfo:[CPDictionary dictionaryWithObject:[note object] forKey:"CPFieldEditor"]];
}
- (void)textDidChange:(CPNotification)note
- (void)textDidChange:(CPNotification)note
{
//this looks to prevent false propagation of notifications for other objects
if ([note object] != self)
if([note object] != self)
return;
[[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidChangeNotification object:self userInfo:[CPDictionary dictionaryWithObject:[note object] forKey:"CPFieldEditor"]];
}
- (void)textDidEndEditing:(CPNotification)note
- (void)textDidEndEditing:(CPNotification)note
{
//this looks to prevent false propagation of notifications for other objects
if ([note object] != self)
if([note object] != self)
return;
[self _reverseSetBinding];
[[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidEndEditingNotification object:self userInfo:[CPDictionary dictionaryWithObject:[note object] forKey:"CPFieldEditor"]];
}
/*!
Sets the text alignment of the control.
<pre>
CPLeftTextAlignment
CPCenterTextAlignment
CPRightTextAlignment
CPJustifiedTextAlignment
CPNaturalTextAlignment
</pre>
*/
- (void)setAlignment:(CPTextAlignment)alignment
{
[self setValue:alignment forThemeAttribute:@"alignment"];
#define BRIDGE(UPPERCASE, LOWERCASE, ATTRIBUTENAME) \
/*! Sets the value for ATTRIBUTENAME */\
- (void)set##UPPERCASE:(id)aValue\
{\
[self setValue:aValue forThemeAttribute:ATTRIBUTENAME];\
}\
/*! Returns the current value for ATTRIBUTENAME */\
- (id)LOWERCASE\
{\
return [self valueForThemeAttribute:ATTRIBUTENAME];\
}
/*!
Returns the text alignment of the control.
*/
- (CPTextAlignment)alignment
{
return [self valueForThemeAttribute:@"alignment"];
}
BRIDGE(Alignment, alignment, "alignment")
BRIDGE(VerticalAlignment, verticalAlignment, "vertical-alignment")
BRIDGE(LineBreakMode, lineBreakMode, "line-break-mode")
BRIDGE(TextColor, textColor, "text-color")
BRIDGE(Font, font, "font")
BRIDGE(TextShadowColor, textShadowColor, "text-shadow-color")
BRIDGE(TextShadowOffset, textShadowOffset, "text-shadow-offset")
BRIDGE(ImagePosition, imagePosition, "image-position")
BRIDGE(ImageScaling, imageScaling, "image-scaling")
/*!
Set the vertical text alignment of the control.
<pre>
CPTopVerticalTextAlignment
CPCenterVerticalTextAlignment
CPBottomVerticalTextAlignment
</pre>
*/
- (void)setVerticalAlignment:(CPTextVerticalAlignment)alignment
{
[self setValue:alignment forThemeAttribute:@"vertical-alignment"];
}
/*!
Returns the vertical text alignment of the receiver.
*/
- (CPTextVerticalAlignment)verticalAlignment
{
return [self valueForThemeAttribute:@"vertical-alignment"];
}
/*!
Sets the line break mode of the receiver.
<pre>
CPLineBreakByWordWrapping
CPLineBreakByCharWrapping
CPLineBreakByClipping
CPLineBreakByTruncatingHead
CPLineBreakByTruncatingTail
CPLineBreakByTruncatingMiddle
</pre>
*/
- (void)setLineBreakMode:(CPLineBreakMode)mode
{
[self setValue:mode forThemeAttribute:@"line-break-mode"];
}
/*!
Returns the line break mode of the control.
*/
- (CPLineBreakMode)lineBreakMode
{
return [self valueForThemeAttribute:@"line-break-mode"];
}
/*!
Sets the text color of the receiver.
@param aColor - A CPColor object.
*/
- (void)setTextColor:(CPColor)aColor
{
[self setValue:aColor forThemeAttribute:@"text-color"];
}
/*!
Returns the text color of the receiver.
*/
- (CPColor)textColor
{
return [self valueForThemeAttribute:@"text-color"];
}
/*!
Sets the shadow color of the text for the receiver.
*/
- (void)setTextShadowColor:(CPColor)aColor
{
[self setValue:aColor forThemeAttribute:@"text-shadow-color"];
}
/*!
Returns the shadow color of the text for the control.
*/
- (CPColor)textShadowColor
{
return [self valueForThemeAttribute:@"text-shadow-color"];
}
/*!
Sets the shadow offset for the text.
@param offset - a CGSize with the x and y offsets.
*/
- (void)setTextShadowOffset:(CGSize)offset
{
[self setValue:offset forThemeAttribute:@"text-shadow-offset"];
}
/*!
Returns the text shadow offset of the receiver.
*/
- (CGSize)textShadowOffset
{
return [self valueForThemeAttribute:@"text-shadow-offset"];
}
/*!
Sets the font of the control.
*/
- (void)setFont:(CPFont)aFont
{
[self setValue:aFont forThemeAttribute:@"font"];
}
/*!
Returns the font of the control.
*/
- (CPFont)font
{
return [self valueForThemeAttribute:@"font"];
}
/*!
Sets the image position of the control.
<pre>
CPNoImage
CPImageOnly
CPImageLeft
CPImageRight
CPImageBelow
CPImageAbove
CPImageOverlaps
</pre>
*/
- (void)setImagePosition:(CPCellImagePosition)position
{
[self setValue:position forThemeAttribute:@"image-position"];
}
/*!
Returns the image position of the receiver.
*/
- (CPCellImagePosition)imagePosition
{
return [self valueForThemeAttribute:@"image-position"];
}
/*!
Sets the image scaling of the control.
<pre>
CPScaleProportionally
CPScaleToFit
CPScaleNone
</pre>
*/
- (void)setImageScaling:(CPImageScaling)scaling
{
[self setValue:scaling forThemeAttribute:@"image-scaling"];
}
/*!
Returns the image scaling of the control.
*/
- (CPImageScaling)imageScaling
{
return [self valueForThemeAttribute:@"image-scaling"];
}
/*!
Sets the enabled status of the control.
Controls that are not enabled can not be used by the user and obtain the CPThemeStateDisabled theme state.
@param BOOL - YES if the control should be enabled, otherwise NO.
*/
- (void)setEnabled:(BOOL)isEnabled
{
if (isEnabled)
@@ -783,29 +542,16 @@ var CPControlBlackColor = [CPColor blackColor];
[self setThemeState:CPThemeStateDisabled];
}
/*!
Returns YES if the receiver is enabled, otherwise NO.
*/
- (BOOL)isEnabled
{
return ![self hasThemeState:CPThemeStateDisabled];
}
/*!
Highlights the receiver.
@param BOOL - YES if the receiver should be highlighted, otherwise NO.
*/
- (void)highlight:(BOOL)shouldHighlight
{
[self setHighlighted:shouldHighlight];
}
/*!
Highlights the receiver.
@param BOOL - YES if the receiver should be highlighted, otherwise NO.
*/
- (void)setHighlighted:(BOOL)isHighlighted
{
if (isHighlighted)
@@ -814,9 +560,6 @@ var CPControlBlackColor = [CPColor blackColor];
[self unsetThemeState:CPThemeStateHighlighted];
}
/*!
Returns YES if the control is highlighted, otherwise NO.
*/
- (BOOL)isHighlighted
{
return [self hasThemeState:CPThemeStateHighlighted];
@@ -827,7 +570,7 @@ var CPControlBlackColor = [CPColor blackColor];
var CPControlValueKey = "CPControlValueKey",
CPControlControlStateKey = @"CPControlControlStateKey",
CPControlIsEnabledKey = "CPControlIsEnabledKey",
CPControlTargetKey = "CPControlTargetKey",
CPControlActionKey = "CPControlActionKey",
CPControlSendActionOnKey = "CPControlSendActionOnKey",
@@ -840,7 +583,6 @@ var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
/*
Initializes the control by unarchiving it from a coder.
@param aCoder the coder from which to unarchive the control
@return the initialized control
*/
@@ -858,13 +600,12 @@ var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
[self sendActionOn:[aCoder decodeIntForKey:CPControlSendActionOnKey]];
[self setSendsActionOnEndEditing:[aCoder decodeBoolForKey:CPControlSendsActionOnEndEditingKey]];
}
return self;
}
/*
Archives the control to the provided coder.
@param aCoder the coder to which the control will be archived.
*/
- (void)encodeWithCoder:(CPCoder)aCoder
@@ -874,10 +615,8 @@ var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
if (_sendsActionOnEndEditing)
[aCoder encodeBool:_sendsActionOnEndEditing forKey:CPControlSendsActionOnEndEditingKey];
var objectValue = [self objectValue];
if (objectValue !== nil)
[aCoder encodeObject:objectValue forKey:CPControlValueKey];
if (_value !== nil)
[aCoder encodeObject:_value forKey:CPControlValueKey];
if (_target !== nil)
[aCoder encodeConditionalObject:_target forKey:CPControlTargetKey];
@@ -897,7 +636,7 @@ var _CPControlSizeIdentifiers = [],
_CPControlSizeIdentifiers[CPRegularControlSize] = "Regular";
_CPControlSizeIdentifiers[CPSmallControlSize] = "Small";
_CPControlSizeIdentifiers[CPMiniControlSize] = "Mini";
function _CPControlIdentifierForControlSize(aControlSize)
{
return _CPControlSizeIdentifiers[aControlSize];
@@ -908,21 +647,21 @@ function _CPControlColorWithPatternImage(sizes, aClassName)
var index = 1,
count = arguments.length,
identifier = "";
for (; index < count; ++index)
identifier += arguments[index];
var color = _CPControlCachedColorWithPatternImages[identifier];
if (!color)
{
var bundle = [CPBundle bundleForClass:[CPControl class]];
color = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:aClassName + "/" + identifier + ".png"] size:sizes[identifier]]];
_CPControlCachedColorWithPatternImages[identifier] = color;
}
return color;
}
@@ -931,17 +670,17 @@ function _CPControlThreePartImagePattern(isVertical, sizes, aClassName)
var index = 2,
count = arguments.length,
identifier = "";
for (; index < count; ++index)
identifier += arguments[index];
var color = _CPControlCachedThreePartImagePattern[identifier];
if (!color)
{
var bundle = [CPBundle bundleForClass:[CPControl class]],
path = aClassName + "/" + identifier;
sizes = sizes[identifier];
color = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:[
@@ -949,9 +688,9 @@ function _CPControlThreePartImagePattern(isVertical, sizes, aClassName)
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:path + "1.png"] size:sizes[1]],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:path + "2.png"] size:sizes[2]]
] isVertical:isVertical]];
_CPControlCachedThreePartImagePattern[identifier] = color;
}
return color;
}
-88
View File
@@ -1,88 +0,0 @@
//
// CPController.j
// AppKit
//
// Created by Ross Boucher 1/15/09
// Copyright 280 North
//
// Adapted from GNUStep
// Copyright (C) 2007 Free Software Foundation, Inc
// Released under the LGPL.
//
@import <Foundation/CPObject.j>
var CPControllerDeclaredKeysKey = @"CPControllerDeclaredKeysKey";
@implementation CPController : CPObject
{
CPArray _editors;
CPArray _declaredKeys;
}
- (id)init
{
self = [super init];
if (self)
{
_editors = [];
_declaredKeys = [];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
if ([_declaredKeys count] > 0)
[aCoder encodeObject:_declaredKeys forKey:CPControllerDeclaredKeysKey];
}
- (id)initWithCoder:(CPCoder)aDecoder
{
self = [super init];
if (self)
{
_editors = [];
_declaredKeys = [aDecoder decodeObjectForKey:CPControllerDeclaredKeysKey] || [];
}
return self;
}
- (BOOL)isEditing
{
return [_editors count] > 0;
}
- (BOOL)commitEditing
{
var index = 0,
count = _editors.length;
for (; index < count; ++index)
if (![[_editors objectAtIndex:i] commitEditing])
return NO;
return YES;
}
- (void)discardEditing
{
[_editors makeObjectsPerformSelector:@selector(discardEditing)];
}
- (void)objectDidBeginEditing:(id)anEditor
{
[_editors addObject:anEditor];
}
- (void)objectDidEndEditing:(id)anEditor
{
[_editors removeObject:anEditor];
}
@end
+20 -29
View File
@@ -24,7 +24,7 @@
@import <Foundation/CPString.j>
/*!
/*!
@ingroup appkit
@class CPCookie
CPCookie is the Cappuccino interface to a web browser cookie. You can set the name
@@ -33,7 +33,7 @@
{
CPString _cookieName;
CPString _cookieValue;
CPString _expires;
}
@@ -44,7 +44,7 @@
- (id)initWithName:(CPString)aName
{
self = [super init];
_cookieName = aName;
_cookieValue = [self _readCookieValue];
@@ -83,39 +83,30 @@
*/
- (void)setValue:(CPString)value expires:(CPDate)date domain:(CPString)domain
{
if (date)
var expires = "; expires=" + date.toGMTString();
else
if(date)
var expires = "; expires="+date.toGMTString();
else
var expires = "";
if (domain)
domain = "; domain=" + domain;
else
if(domain)
domain = "; domain="+domain;
else
domain = "";
#if PLATFORM(DOM)
document.cookie = _cookieName+"="+value+expires+"; path=/"+domain;
#else
_cookieValue = value;
_expires = expires;
#endif
document.cookie = _cookieName+"="+value+expires+"; path=/"+domain;
}
/* @ignore */
- (CPString)_readCookieValue
{
#if PLATFORM(DOM)
var nameEQ = _cookieName + "=",
ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++)
{
var c = ca[i];
while (c.charAt(0) == ' ') c = c.substring(1, c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
}
#endif
return "";
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 "";
}
@end
+200 -176
View File
@@ -1,41 +1,36 @@
/*
Cursor support by browser:
OS X 10.6/Chrome 8 : All
OS X 10.6/Safari 5 : All
OS X 10.6/Firefox 3 : All except disappearingItemCursor (no url() support)
OS X 10.6/Firefox 3.5 : All except disappearingItemCursor (no url() support)
OS X 10.6/Firefox 3.6 : All except disappearingItemCursor, contextualMenuCursor, dragLinkCursor, dragCopyCursor, operationNotAllowedCursor (no url() support)
OS X 10.6/Firefox 4.0b10 : All
OS X/Opera 9 : All except disappearingItemCursor, closedHandCursor, openHandCursor, contextualMenuCursor, dragLinkCursor, dragCopyCursor, operationNotAllowedCursor, resizeUpDownCursor, resizeLeftRightCursor (no url() support)
OS X/Opera 10 : All except disappearingItemCursor, closedHandCursor, contextualMenuCursor, dragLinkCursor, dragCopyCursor, operationNotAllowedCursor (no url() support)
OS X/Opera 11 : All except disappearingItemCursor, closedHandCursor, contextualMenuCursor, dragLinkCursor, dragCopyCursor, operationNotAllowedCursor (no url() support)
Win XP/Chrome 8 : All
Win XP/Safari 5 : All
Win XP/Firefox 3 : All
Win XP/Firefox 3.5 : All
Win XP/Firefox 3.6 : All
Win XP/Firefox 4.0b10 : All
Win XP/Opera 10 : All except disappearingItemCursor, closedHandCursor, openHandCursor, contextualMenuCursor, dragLinkCursor, dragCopyCursor, operationNotAllowedCursor, resizeUpDownCursor, resizeLeftRightCursor (no url() support)
Win XP/Opera 11 : All except disappearingItemCursor, closedHandCursor, openHandCursor, contextualMenuCursor, dragLinkCursor, dragCopyCursor, operationNotAllowedCursor, resizeUpDownCursor, resizeLeftRightCursor (no url() support)
Win XP/IE 7 : All
Win XP/IE 8 : All
Testing browsers:
WebKit r50235 (Safari 4.0.3+)
FireFox 3.5
Opera 10.0.0
Implemented class methods:
Webkit : All
IE : All
FireFox Win : All
FireFox Mac : All except closedHandCursor disappearingItemCursor // Firefox mac does not support url cursors
Opera : All except resizeLeftRightCursor resizeUpDownCursor operationNotAllowedCursor dragCopyCursor dragLinkCursor contextualMenuCursor openHandCursor closedHandCursor disappearingItemCursor // Opera does not support url cursors so these won't work with images
*/
@import <Foundation/CPObject.j>
#include "Platform/Platform.h"
var currentCursor = nil,
cursorStack = [],
cursors = {};
cursors = {},
cursorURLFormat = nil;
@implementation CPCursor : CPObject
{
CPString _cssString @accessors(readonly);
CPString _hotSpot @accessors(readonly, getter=hotSpot);
CPImage _image @accessors(readonly, getter=image);
CPString _cssString;
BOOL _isSetOnMouseEntered @accessors(readwrite, getter=isSetOnMouseEntered, setter=setOnMouseEntered:);
BOOL _isSetOnMouseExited @accessors(readwrite, getter=isSetOnMouseExited, setter=setOnMouseExited:);
}
+ (CPCursor)currentCursor
{
return currentCursor;
}
- (id)initWithCSSString:(CPString)aString
{
if (self = [super init])
@@ -44,18 +39,151 @@ var currentCursor = nil,
return self;
}
// hotspot is supported in CSS3 (but not IE).
- (id)initWithImage:(CPImage)image hotSpot:(CPPoint)hotSpot
+ (CPCursor)cursorWithCSSString:(CPString)cssString
{
_hotSpot = hotSpot;
_image = image;
return [self initWithCSSString:"url(" + [_image filename] + ")" + hotSpot.x + " " + hotSpot.y + ", auto"];
var cursor = cursors[cssString];
if (typeof cursor == 'undefined')
{
cursor = [[CPCursor alloc] initWithCSSString:cssString];
cursors[cssString] = cursor;
}
return cursor;
}
// foregroundColor and backgroundColor are ignored in Cocoa as well. See http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/NSCursor_Class/Reference/Reference.html
- (id)initWithImage:(CPImage)image foregroundColorHint:(CPColor)foregroundColor backgroundColorHint:(CPColor)backgroundColor hotSpot:(CPPoint)aHotSpot
+ (CPCursor)cursorWithImageNamed:(CPString)imageName
{
return [self initWithImage:image hotSpot:hotSpot];
if (!cursorURLFormat)
{
cursorURLFormat = @"url(" + [[CPBundle bundleForClass:self] resourcePath] + @"/CPCursor/%@.cur)";
if (CPBrowserIsEngine(CPGeckoBrowserEngine))
cursorURLFormat += ", default";
}
var url = [CPString stringWithFormat:cursorURLFormat, imageName];
return [[CPCursor alloc] initWithCSSString:url];
}
- (CPString)_cssString
{
return _cssString;
}
+ (CPCursor)arrowCursor
{
return [CPCursor cursorWithCSSString:@"default"]; // WebKit | FF | opera | IE
}
+ (CPCursor)crosshairCursor
{
return [CPCursor cursorWithCSSString:@"crosshair"]; // WebKit | FF | opera | IE
}
+ (CPCursor)IBeamCursor
{
return [CPCursor cursorWithCSSString:@"text"]; // WebKit | FF | opera | IE
}
+ (CPCursor)pointingHandCursor
{
return [CPCursor cursorWithCSSString:@"pointer"]; // WebKit | FF | opera | IE
}
+ (CPCursor)resizeDownCursor
{
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)];
return [CPCursor cursorWithCSSString:"s-resize"]; // WebKit | FF | opera
}
+ (CPCursor)resizeUpCursor
{
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)];
return [CPCursor cursorWithCSSString:@"n-resize"]; // WebKit | FF | opera
}
+ (CPCursor)resizeLeftCursor
{
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)];
return [CPCursor cursorWithCSSString:@"w-resize"]; // WebKit | FF | opera
}
+ (CPCursor)resizeRightCursor
{
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)];
return [CPCursor cursorWithCSSString:@"e-resize"]; // WebKit | FF | opera
}
+ (CPCursor)resizeLeftRightCursor
{
return [CPCursor cursorWithCSSString:@"col-resize"]; // WebKit | FF | IE
}
+ (CPCursor)resizeUpDownCursor
{
return [CPCursor cursorWithCSSString:@"row-resize"]; // WebKit | FF | IE
}
+ (CPCursor)operationNotAllowedCursor
{
return [CPCursor cursorWithCSSString:@"not-allowed"]; // WebKit | FF | IE
}
+ (CPCursor)dragCopyCursor
{
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)];
return [CPCursor cursorWithCSSString:@"copy"]; // WebKit | FF
}
+ (CPCursor)dragLinkCursor
{
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)];
return [CPCursor cursorWithCSSString:@"alias"]; // WebKit | FF
}
+ (CPCursor)contextualMenuCursor
{
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)];
return [CPCursor cursorWithCSSString:@"context-menu"]; // WebKit | FF Mac . Not impl FF Win.
}
+ (CPCursor)openHandCursor
{
if (CPBrowserIsEngine(CPWebKitBrowserEngine))
return [CPCursor cursorWithCSSString:@"-webkit-grab"];
else if (CPBrowserIsEngine(CPGeckoBrowserEngine) || CPBrowserIsEngine(CPOperaBrowserEngine))
return [CPCursor cursorWithCSSString:@"move"];
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)]; // WebKit only. move in FFMac|Opera
}
+ (CPCursor)closedHandCursor
{
if (CPBrowserIsEngine(CPWebKitBrowserEngine))
return [CPCursor cursorWithCSSString:@"-webkit-grabbing"];
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)]; // WebKit only
}
+ (CPCursor)disappearingItemCursor
{
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)]; // None
}
+ (void)hide
@@ -65,7 +193,7 @@ var currentCursor = nil,
+ (void)unhide
{
[self _setCursorCSS:[currentCursor _cssString]];
[self _setCursorCSS:[currentCursor _cssString]]
}
+ (void)setHiddenUntilMouseMoves:(BOOL)flag
@@ -76,6 +204,43 @@ var currentCursor = nil,
[CPCursor unhide];
}
- (id)initWithImage:(CPImage)image hotSpot:(CPPoint)hotSpot
{
return [self initWithCSSString:"url(" + [image filename] + ")"];
}
- (void)mouseEntered:(CPEvent)event
{
}
- (void)mouseExited:(CPEvent)event
{
}
- (void)set
{
currentCursor = self;
#if PLATFORM(DOM)
[[self class] _setCursorCSS:_cssString];
#endif
}
+ (void)_setCursorCSS:(CPString)aString
{
#if PLATFORM(DOM)
var platformWindows = [[CPPlatformWindow visiblePlatformWindows] allObjects];
for (var i = 0, count = [platformWindows count]; i < count; i++)
platformWindows[i]._DOMBodyElement.style.cursor = aString;
#endif
}
- (void)push
{
currentCursor = cursorStack.push(self);
}
- (void)pop
{
[CPCursor pop];
@@ -90,148 +255,6 @@ var currentCursor = nil,
}
}
- (void)push
{
currentCursor = cursorStack.push(self);
}
- (void)set
{
currentCursor = self;
#if PLATFORM(DOM)
[[self class] _setCursorCSS:_cssString];
#endif
}
- (void)mouseEntered:(CPEvent)event
{
}
- (void)mouseExited:(CPEvent)event
{
}
+ (CPCursor)currentCursor
{
return currentCursor;
}
+ (void)_setCursorCSS:(CPString)aString
{
#if PLATFORM(DOM)
var platformWindows = [[CPPlatformWindow visiblePlatformWindows] allObjects];
for (var i = 0, count = [platformWindows count]; i < count; i++)
platformWindows[i]._DOMBodyElement.style.cursor = aString;
#endif
}
// Internal method that is used to return the system cursors. Caches the system cursors for performance.
+ (CPCursor)_systemCursorWithName:(CPString)cursorName cssString:(CPString)aString hasImage:(BOOL)doesHaveImage
{
var cursor = cursors[cursorName];
if (typeof cursor === 'undefined')
{
var cssString;
if (doesHaveImage)
cssString = @"url(" + [[CPBundle bundleForClass:self] resourcePath] + @"/CPCursor/" + cursorName + ".cur), " + aString;
else
cssString = aString
cursor = [[CPCursor alloc] initWithCSSString:cssString];
cursors[cursorName] = cursor;
}
return cursor;
}
+ (CPCursor)arrowCursor
{
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:"default" hasImage:NO];
}
+ (CPCursor)crosshairCursor
{
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"crosshair" hasImage:NO];
}
+ (CPCursor)IBeamCursor
{
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"text" hasImage:NO];
}
+ (CPCursor)pointingHandCursor
{
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"pointer" hasImage:NO];
}
+ (CPCursor)resizeDownCursor
{
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"s-resize" hasImage:NO];
}
+ (CPCursor)resizeUpCursor
{
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"n-resize" hasImage:NO];
}
+ (CPCursor)resizeLeftCursor
{
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"w-resize" hasImage:NO];
}
+ (CPCursor)resizeRightCursor
{
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"e-resize" hasImage:NO];
}
+ (CPCursor)resizeLeftRightCursor
{
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"col-resize" hasImage:NO];
}
+ (CPCursor)resizeUpDownCursor
{
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"row-resize" hasImage:NO];
}
+ (CPCursor)operationNotAllowedCursor
{
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"not-allowed" hasImage:NO];
}
+ (CPCursor)dragCopyCursor
{
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"copy" hasImage:YES];
}
+ (CPCursor)dragLinkCursor
{
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"alias" hasImage:YES];
}
+ (CPCursor)contextualMenuCursor
{
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"context-menu" hasImage:YES];
}
+ (CPCursor)openHandCursor
{
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"move" hasImage:YES];
}
+ (CPCursor)closedHandCursor
{
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"-moz-grabbing" hasImage:YES];
}
+ (CPCursor)disappearingItemCursor
{
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"auto" hasImage:YES];
}
@end
@implementation CPCursor(CPCoding)
- (id)initWithCoder:(CPCoder)coder
{
if (self = [super init])
@@ -246,3 +269,4 @@ var currentCursor = nil,
}
@end
+52 -53
View File
@@ -23,7 +23,6 @@
@import <Foundation/CPString.j>
@import <Foundation/CPArray.j>
@import "CPApplication.j"
@import "CPResponder.j"
@import "CPSavePanel.j"
@import "CPViewController.j"
@@ -83,12 +82,12 @@ CPDocumentDidFailToSaveNotification = @"CPDocumentDidFailToSaveNotification";
var CPDocumentUntitledCount = 0;
/*!
/*!
@ingroup appkit
@class CPDocument
CPDocument is used to represent a document/file in a Cappuccino application.
In a document-based application, generally multiple documents are open simultaneously
In a document-based application, generally multiple documents are open simutaneously
(multiple text documents, slide presentations, spreadsheets, etc.), and multiple
CPDocuments should be used to represent this.
*/
@@ -121,7 +120,7 @@ var CPDocumentUntitledCount = 0;
- (id)init
{
self = [super init];
if (self)
{
_windowControllers = [];
@@ -132,7 +131,7 @@ var CPDocumentUntitledCount = 0;
[self setNextResponder:CPApp];
}
return self;
}
@@ -145,10 +144,10 @@ var CPDocumentUntitledCount = 0;
- (id)initWithType:(CPString)aType error:({CPError})anError
{
self = [self init];
if (self)
[self setFileType:aType];
return self;
}
@@ -166,7 +165,7 @@ var CPDocumentUntitledCount = 0;
- (id)initWithContentsOfURL:(CPURL)anAbsoluteURL ofType:(CPString)aType delegate:(id)aDelegate didReadSelector:(SEL)aDidReadSelector contextInfo:(id)aContextInfo
{
self = [self init];
if (self)
{
[self setFileURL:anAbsoluteURL];
@@ -174,7 +173,7 @@ var CPDocumentUntitledCount = 0;
[self readFromURL:anAbsoluteURL ofType:aType delegate:aDelegate didReadSelector:aDidReadSelector contextInfo:aContextInfo];
}
return self;
}
@@ -191,7 +190,7 @@ var CPDocumentUntitledCount = 0;
- (id)initForURL:(CPURL)anAbsoluteURL withContentsOfURL:(CPURL)absoluteContentsURL ofType:(CPString)aType delegate:(id)aDelegate didReadSelector:(SEL)aDidReadSelector contextInfo:(id)aContextInfo
{
self = [self init];
if (self)
{
[self setFileURL:anAbsoluteURL];
@@ -199,7 +198,7 @@ var CPDocumentUntitledCount = 0;
[self readFromURL:absoluteContentsURL ofType:aType delegate:aDelegate didReadSelector:aDidReadSelector contextInfo:aContextInfo];
}
return self;
}
@@ -208,7 +207,7 @@ var CPDocumentUntitledCount = 0;
throws an exception.
@param aType the format of the data
@param anError not used
@throws CPUnsupportedMethodException if this method hasn't been overridden by the subclass
@throws CPUnsupportedMethodException if this method hasn't been overriden by the subclass
@return the document data
*/
- (CPData)dataOfType:(CPString)aType error:({CPError})anError
@@ -282,7 +281,7 @@ var CPDocumentUntitledCount = 0;
{
var view = [viewController view],
viewFrame = [view frame];
viewFrame.origin = CGPointMake(50, 50);
var theWindow = [[CPWindow alloc] initWithContentRect:viewFrame styleMask:CPTitledWindowMask | CPClosableWindowMask | CPMiniaturizableWindowMask | CPResizableWindowMask];
@@ -382,14 +381,14 @@ var CPDocumentUntitledCount = 0;
{
if (_fileURL)
return [_fileURL lastPathComponent];
if (!_untitledDocumentIndex)
_untitledDocumentIndex = ++CPDocumentUntitledCount;
if (_untitledDocumentIndex == 1)
return @"Untitled";
if (_untitledDocumentIndex == 1)
return @"Untitled";
return @"Untitled " + _untitledDocumentIndex;
return @"Untitled " + _untitledDocumentIndex;
}
- (CPString)viewCibName
@@ -458,7 +457,7 @@ var CPDocumentUntitledCount = 0;
return;
_fileURL = aFileURL;
[_windowControllers makeObjectsPerformSelector:@selector(synchronizeWindowTitleWithDocumentName)];
}
@@ -510,21 +509,21 @@ var CPDocumentUntitledCount = 0;
// If we got this far and it wasn't an HTTP request, then everything is fine.
if (![aResponse isKindOfClass:[CPHTTPURLResponse class]])
return;
var statusCode = [aResponse statusCode];
// Nothing to do if everything is hunky dory.
if (statusCode === 200)
return;
var session = aConnection.session;
if (aConnection == _readConnection)
{
[aConnection cancel];
alert("There was an error retrieving the document.");
objj_msgSend(session.delegate, session.didReadSelector, self, NO, session.contextInfo);
}
else
@@ -533,23 +532,23 @@ var CPDocumentUntitledCount = 0;
if (statusCode == 409)
{
[aConnection cancel];
if (confirm("There already exists a file with that name, would you like to overwrite it?"))
{
[_writeRequest setValue:@"true" forHTTPHeaderField:@"x-cappuccino-overwrite"];
[aConnection start];
}
else
else
{
if (session.saveOperation != CPSaveToOperation)
{
_changeCount += session.changeCount;
[_windowControllers makeObjectsPerformSelector:@selector(setDocumentEdited:) withObject:[self isDocumentEdited]];
}
_writeRequest = nil;
objj_msgSend(session.delegate, session.didSaveSelector, self, NO, session.contextInfo);
[self _sendDocumentSavedNotification:NO];
}
@@ -564,7 +563,7 @@ var CPDocumentUntitledCount = 0;
- (void)connection:(CPURLConnection)aConnection didReceiveData:(CPString)aData
{
var session = aConnection.session;
// READ
if (aConnection == _readConnection)
{
@@ -576,9 +575,9 @@ var CPDocumentUntitledCount = 0;
{
if (session.saveOperation != CPSaveToOperation)
[self setFileURL:session.absoluteURL];
_writeRequest = nil;
objj_msgSend(session.delegate, session.didSaveSelector, self, YES, session.contextInfo);
[self _sendDocumentSavedNotification:YES];
}
@@ -591,17 +590,17 @@ var CPDocumentUntitledCount = 0;
- (void)connection:(CPURLConnection)aConnection didFailWithError:(CPError)anError
{
var session = aConnection.session;
if (_readConnection == aConnection)
objj_msgSend(session.delegate, session.didReadSelector, self, NO, session.contextInfo);
else
{
{
if (session.saveOperation != CPSaveToOperation)
{
_changeCount += session.changeCount;
[_windowControllers makeObjectsPerformSelector:@selector(setDocumentEdited:) withObject:[self isDocumentEdited]];
}
}
_writeRequest = nil;
@@ -644,9 +643,9 @@ var CPDocumentUntitledCount = 0;
else if (aChangeType == CPChangeCleared)
_changeCount = 0;
/*else if (aChangeType == CPCHangeReadOtherContents)
else if (aChangeType == CPChangeAutosaved)*/
else if (aChangeType == CPChangeAutosaved)*/
[_windowControllers makeObjectsPerformSelector:@selector(setDocumentEdited:) withObject:[self isDocumentEdited]];
}
@@ -686,9 +685,9 @@ var CPDocumentUntitledCount = 0;
{
if (_hasUndoManager == aFlag)
return;
_hasUndoManager = aFlag;
if (!_hasUndoManager)
[self setUndoManager:nil];
}
@@ -697,7 +696,7 @@ var CPDocumentUntitledCount = 0;
- (void)_undoManagerWillCloseGroup:(CPNotification)aNotification
{
var undoManager = [aNotification object];
if ([undoManager isUndoing] || [undoManager isRedoing])
return;
@@ -724,13 +723,13 @@ var CPDocumentUntitledCount = 0;
- (void)setUndoManager:(CPUndoManager)anUndoManager
{
var defaultCenter = [CPNotificationCenter defaultCenter];
if (_undoManager)
{
[defaultCenter removeObserver:self
name:CPUndoManagerDidUndoChangeNotification
object:_undoManager];
[defaultCenter removeObserver:self
name:CPUndoManagerDidRedoChangeNotification
object:_undoManager];
@@ -739,17 +738,17 @@ var CPDocumentUntitledCount = 0;
name:CPUndoManagerWillCloseUndoGroupNotification
object:_undoManager];
}
_undoManager = anUndoManager;
if (_undoManager)
{
[defaultCenter addObserver:self
selector:@selector(_undoManagerDidUndoChange:)
name:CPUndoManagerDidUndoChangeNotification
object:_undoManager];
[defaultCenter addObserver:self
selector:@selector(_undoManagerDidRedoChange:)
name:CPUndoManagerDidRedoChangeNotification
@@ -775,7 +774,7 @@ var CPDocumentUntitledCount = 0;
return _undoManager;
}
/*
Implemented as a delegate of a CPWindow
@ignore
@@ -804,7 +803,7 @@ var CPDocumentUntitledCount = 0;
[[CPNotificationCenter defaultCenter]
postNotificationName:CPDocumentWillSaveNotification
object:self];
[self saveToURL:_fileURL ofType:[self fileType] forSaveOperation:CPSaveOperation delegate:delegate didSaveSelector:didSaveSelector contextInfo:contextInfo];
}
else
@@ -862,7 +861,7 @@ var CPDocumentUntitledCount = 0;
[[CPDocumentController sharedDocumentController] removeDocument:self];
}
- (void)shouldCloseWindowController:(CPWindowController)controller delegate:(id)delegate shouldCloseSelector:(SEL)selector contextInfo:(Object)info
- (void)shouldCloseWindowController:(CPWindowController)controller delegate:(id)delegate shouldCloseSelector:(SEL)selector contextInfo:(Object)info
{
if ([controller shouldCloseDocument] || ([_windowControllers count] < 2 && [_windowControllers indexOfObject:controller] !== CPNotFound))
[self canCloseDocumentWithDelegate:self shouldCloseSelector:@selector(_document:shouldClose:context:) contextInfo:{delegate:delegate, selector:selector, context:info}];
@@ -879,7 +878,7 @@ var CPDocumentUntitledCount = 0;
objj_msgSend(context.delegate, context.selector, aDocument, shouldClose, context.context);
}
- (void)canCloseDocumentWithDelegate:(id)aDelegate shouldCloseSelector:(SEL)aSelector contextInfo:(Object)context
- (void)canCloseDocumentWithDelegate:(id)aDelegate shouldCloseSelector:(SEL)aSelector contextInfo:(Object)context
{
if (![self isDocumentEdited])
return [aDelegate respondsToSelector:aSelector] && objj_msgSend(aDelegate, aSelector, self, YES, context);
+27 -28
View File
@@ -24,12 +24,12 @@
@import <Foundation/CPBundle.j>
@import "CPDocument.j"
@import "CPOpenPanel.j"
@import "CPOpenPanel.j";
var CPSharedDocumentController = nil;
/*!
/*!
@ingroup appkit
@class CPDocumentController
This class is responsible for managing an application's open documents.
@@ -41,7 +41,7 @@ var CPSharedDocumentController = nil;
}
/*!
Returns the singleton instance of the application's document controller. If it has not
Returns the singleton instance of the application's document controller. If it has not
been created yet, it will be created then returned.
@return a CPDocumentController
*/
@@ -49,7 +49,7 @@ var CPSharedDocumentController = nil;
{
if (!CPSharedDocumentController)
[[self alloc] init];
return CPSharedDocumentController;
}
@@ -59,11 +59,11 @@ var CPSharedDocumentController = nil;
- (id)init
{
self = [super init];
if (self)
{
_documents = [[CPArray alloc] init];
if (!CPSharedDocumentController)
CPSharedDocumentController = self;
@@ -85,16 +85,16 @@ var CPSharedDocumentController = nil;
{
var index = 0,
count = [_documents count];
for (; index < count; ++index)
for (; index < count; ++index)
{
var theDocument = _documents[index];
if ([[theDocument fileURL] isEqual:aURL])
return theDocument;
if ([[theDocument fileURL] isEqual:aURL])
return theDocument;
}
return nil;
return nil;
}
/*!
@@ -105,10 +105,10 @@ var CPSharedDocumentController = nil;
- (void)openUntitledDocumentOfType:(CPString)aType display:(BOOL)shouldDisplay
{
var theDocument = [self makeUntitledDocumentOfType:aType error:nil];
if (theDocument)
[self addDocument:theDocument];
if (shouldDisplay)
{
[theDocument makeWindowControllers];
@@ -177,7 +177,7 @@ var CPSharedDocumentController = nil;
@param aType the document type
@param aDelegate the delegate to notify
@param aSelector the selector to notify with
@param aContextInfo the context information passed to the delegate
@param aContextInfo the context infomration passed to the delegate
*/
- (CPDocument)makeDocumentWithContentsOfURL:(CPURL)anAbsoluteURL ofType:(CPString)aType delegate:(id)aDelegate didReadSelector:(SEL)aSelector contextInfo:(id)aContextInfo
{
@@ -210,7 +210,7 @@ var CPSharedDocumentController = nil;
return;
[aDocument makeWindowControllers];
if ([aContextInfo objectForKey:@"shouldDisplay"])
[aDocument showWindows];
}
@@ -224,7 +224,7 @@ var CPSharedDocumentController = nil;
[self openUntitledDocumentOfType:[[_documentTypes objectAtIndex:0] objectForKey:@"CPBundleTypeName"] display:YES];
}
- (void)openDocument:(id)aSender
-(void)openDocument:(id)aSender
{
var openPanel = [CPOpenPanel openPanel];
@@ -276,17 +276,17 @@ var CPSharedDocumentController = nil;
{
var index = 0,
count = _documentTypes.length,
extension = [[anAbsoluteURL pathExtension] lowercaseString],
starType = nil;
for (; index < count; ++index)
{
var documentType = _documentTypes[index],
extensions = [documentType objectForKey:@"CFBundleTypeExtensions"],
extensionIndex = 0,
extensionCount = extensions.length;
for (; extensionIndex < extensionCount; ++extensionIndex)
{
var thisExtension = [extensions[extensionIndex] lowercaseString];
@@ -312,11 +312,11 @@ var CPSharedDocumentController = nil;
for (;i < count; ++i)
{
var documentType = _documentTypes[i];
if ([documentType objectForKey:@"CPBundleTypeName"] == aType)
return documentType;
}
return nil;
}
@@ -336,7 +336,7 @@ var CPSharedDocumentController = nil;
@implementation CPDocumentController (Closing)
- (void)closeAllDocumentsWithDelegate:(id)aDelegate didCloseAllSelector:(SEL)didCloseSelector contextInfo:(Object)info
- (void)closeAllDocumentsWithDelegate:(id)aDelegate didCloseAllSelector:(SEL)didCloseSelector contextInfo:(Object)info
{
var context = {
delegate: aDelegate,
@@ -390,14 +390,13 @@ var CPSharedDocumentController = nil;
- (void)noteNewRecentDocument:(CPDocument)aDocument
{
[self noteNewRecentDocumentURL:[aDocument fileURL]];
[self noteNewRecentDocumentURL:[[aDocument fileURL] absoluteString]];
}
- (void)noteNewRecentDocumentURL:(CPURL)aURL
- (void)noteNewRecentDocumentURL:(CPString)aURL
{
var urlAsString = [aURL isKindOfClass:CPString] ? aURL : [aURL absoluteString];
if (typeof window["cpNoteNewRecentDocumentPath"] === 'function')
window.cpNoteNewRecentDocumentPath(urlAsString);
window.cpNoteNewRecentDocumentPath(aURL);
[self _updateRecentDocumentsMenu];
}
+34 -37
View File
@@ -20,21 +20,22 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPApplication.j"
@import "CPEvent.j"
@import "CPImageView.j"
@import "CPPasteboard.j"
@import "CPView.j"
@import "CPWindow.j"
@import <AppKit/CPView.j>
@import <AppKit/CPEvent.j>
@import <AppKit/CPPasteboard.j>
@import <AppKit/CPImageView.j>
#import "CoreGraphics/CGGeometry.h"
#import "Platform/Platform.h"
CPDragOperationNone = 0;
CPDragOperationCopy = 1 << 1;
CPDragOperationLink = 1 << 1;
CPDragOperationGeneric = 1 << 2;
CPDragOperationPrivate = 1 << 3;
CPDragOperationMove = 1 << 4;
CPDragOperationDelete = 1 << 5;
CPDragOperationNone = 0,
CPDragOperationCopy = 1 << 1,
CPDragOperationLink = 1 << 1,
CPDragOperationGeneric = 1 << 2,
CPDragOperationPrivate = 1 << 3,
CPDragOperationMove = 1 << 4,
CPDragOperationDelete = 1 << 5,
CPDragOperationEvery = -1;
#define DRAGGING_WINDOW(anObject) ([anObject isKindOfClass:[CPWindow class]] ? anObject : [anObject window])
@@ -44,8 +45,8 @@ var CPDragServerPreviousEvent = nil,
var CPSharedDragServer = nil;
var CPDragServerSource = nil,
CPDragServerDraggingInfo = nil;
var CPDragServerSource = nil;
var CPDragServerDraggingInfo = nil;
/*
CPDraggingInfo is a container of information about a specific dragging session.
@@ -220,14 +221,14 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
[_draggingUpdateTimer invalidate];
_draggingUpdateTimer = nil;
var dragOperation = CPDragOperationCopy,
var dragOperation = CPDragOperationCopy;
// We have to convert base to bridge since the drag event comes from the source window, not the drag window.
draggingDestination = [aPlatformWindow _dragHitTest:aLocation pasteboard:[CPDragServerDraggingInfo draggingPasteboard]];
var draggingDestination = [aPlatformWindow _dragHitTest:aLocation pasteboard:[CPDragServerDraggingInfo draggingPasteboard]];
if (draggingDestination)
_draggingLocation = [DRAGGING_WINDOW(draggingDestination) convertPlatformWindowToBase:aLocation];
if (draggingDestination !== _draggingDestination)
if(draggingDestination !== _draggingDestination)
{
if ([_draggingDestination respondsToSelector:@selector(draggingExited:)])
[_draggingDestination draggingExited:CPDragServerDraggingInfo];
@@ -261,7 +262,7 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
{
var contentView = [scrollView contentView],
bounds = [contentView bounds],
insetBounds = CGRectInset(bounds, 30, 30),
insetBounds = CGRectInset(bounds, 10, 10)
eventLocation = [contentView convertPoint:_draggingLocation fromView:nil],
deltaX = 0,
deltaY = 0;
@@ -270,10 +271,10 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
{
if ([scrollView hasVerticalScroller])
{
if (eventLocation.y < _CGRectGetMinY(insetBounds))
deltaY = _CGRectGetMinY(insetBounds) - eventLocation.y;
else if (eventLocation.y > _CGRectGetMaxY(insetBounds))
deltaY = _CGRectGetMaxY(insetBounds) - eventLocation.y;
if (eventLocation.y < CGRectGetMinY(insetBounds))
deltaY = CGRectGetMinY(insetBounds) - eventLocation.y;
else if (eventLocation.y > CGRectGetMaxY(insetBounds))
deltaY = CGRectGetMaxY(insetBounds) - eventLocation.y;
if (deltaY < -insetBounds.size.height)
deltaY = -insetBounds.size.height;
if (deltaY > insetBounds.size.height)
@@ -282,21 +283,17 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
if ([scrollView hasHorizontalScroller])
{
if (eventLocation.x < _CGRectGetMinX(insetBounds))
deltaX = _CGRectGetMinX(insetBounds) - eventLocation.x;
else if (eventLocation.x > _CGRectGetMaxX(insetBounds))
deltaX = _CGRectGetMaxX(insetBounds) - eventLocation.x;
if (eventLocation.x < CGRectGetMinX(insetBounds))
deltaX = CGRectGetMinX(insetBounds) - eventLocation.x;
else if (eventLocation.x > CGRectGetMaxX(insetBounds))
deltaX = CGRectGetMaxX(insetBounds) - eventLocation.x;
if (deltaX < -insetBounds.size.width)
deltaX = -insetBounds.size.width;
if (deltaX > insetBounds.size.width)
deltaX = insetBounds.size.width;
}
var scrollPoint = _CGPointMake(bounds.origin.x - deltaX, bounds.origin.y - deltaY);
[contentView scrollToPoint:scrollPoint];
[[scrollView _headerView] scrollPoint:scrollPoint];
[contentView scrollToPoint:CGPointMake(bounds.origin.x - deltaX, bounds.origin.y - deltaY)];
}
}
}
@@ -307,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"]];
}
@@ -331,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];
@@ -460,8 +457,8 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
}
else if (type === CPKeyDown)
{
var characters = [anEvent characters];
if (characters === CPEscapeFunctionKey)
var keyCode = [anEvent keyCode];
if (keyCode === CPEscapeKeyCode)
{
_dragOperation = CPDragOperationNone;
[self draggingEndedInPlatformWindow:platformWindow globalLocation:CGPointMakeZero() operation:_dragOperation];
+52 -196
View File
@@ -21,7 +21,8 @@
*/
@import <Foundation/CPObject.j>
@import "CPText.j"
#include "CoreGraphics/CGGeometry.h"
CPLeftMouseDown = 1;
@@ -40,7 +41,7 @@ CPAppKitDefined = 13;
CPSystemDefined = 14;
CPApplicationDefined = 15;
CPPeriodic = 16;
CPCursorUpdate = 17;
CPCursorUpdate = 17;
CPScrollWheel = 22;
CPOtherMouseDown = 25;
CPOtherMouseUp = 26;
@@ -51,7 +52,8 @@ CPTouchStart = 28;
CPTouchMove = 29;
CPTouchEnd = 30;
CPTouchCancel = 31;
CPAlphaShiftKeyMask = 1 << 16;
CPShiftKeyMask = 1 << 17;
CPControlKeyMask = 1 << 18;
@@ -85,89 +87,13 @@ CPPeriodicMask = 1 << CPPeriodic;
CPScrollWheelMask = 1 << CPScrollWheel;
CPAnyEventMask = 0xffffffff;
CPUpArrowFunctionKey = "\uF700";
CPDownArrowFunctionKey = "\uF701";
CPLeftArrowFunctionKey = "\uF702";
CPRightArrowFunctionKey = "\uF703";
CPF1FunctionKey = "\uF704";
CPF2FunctionKey = "\uF705";
CPF3FunctionKey = "\uF706";
CPF4FunctionKey = "\uF707";
CPF5FunctionKey = "\uF708";
CPF6FunctionKey = "\uF709";
CPF7FunctionKey = "\uF70A";
CPF8FunctionKey = "\uF70B";
CPF9FunctionKey = "\uF70C";
CPF10FunctionKey = "\uF70D";
CPF11FunctionKey = "\uF70E";
CPF12FunctionKey = "\uF70F";
CPF13FunctionKey = "\uF710";
CPF14FunctionKey = "\uF711";
CPF15FunctionKey = "\uF712";
CPF16FunctionKey = "\uF713";
CPF17FunctionKey = "\uF714";
CPF18FunctionKey = "\uF715";
CPF19FunctionKey = "\uF716";
CPF20FunctionKey = "\uF717";
CPF21FunctionKey = "\uF718";
CPF22FunctionKey = "\uF719";
CPF23FunctionKey = "\uF71A";
CPF24FunctionKey = "\uF71B";
CPF25FunctionKey = "\uF71C";
CPF26FunctionKey = "\uF71D";
CPF27FunctionKey = "\uF71E";
CPF28FunctionKey = "\uF71F";
CPF29FunctionKey = "\uF720";
CPF30FunctionKey = "\uF721";
CPF31FunctionKey = "\uF722";
CPF32FunctionKey = "\uF723";
CPF33FunctionKey = "\uF724";
CPF34FunctionKey = "\uF725";
CPF35FunctionKey = "\uF726";
CPInsertFunctionKey = "\uF727";
CPDeleteFunctionKey = "\uF728";
CPHomeFunctionKey = "\uF729";
CPBeginFunctionKey = "\uF72A";
CPEndFunctionKey = "\uF72B";
CPPageUpFunctionKey = "\uF72C";
CPPageDownFunctionKey = "\uF72D";
CPPrintScreenFunctionKey = "\uF72E";
CPScrollLockFunctionKey = "\uF72F";
CPPauseFunctionKey = "\uF730";
CPSysReqFunctionKey = "\uF731";
CPBreakFunctionKey = "\uF732";
CPResetFunctionKey = "\uF733";
CPStopFunctionKey = "\uF734";
CPMenuFunctionKey = "\uF735";
CPUserFunctionKey = "\uF736";
CPSystemFunctionKey = "\uF737";
CPPrintFunctionKey = "\uF738";
CPClearLineFunctionKey = "\uF739";
CPClearDisplayFunctionKey = "\uF73A";
CPInsertLineFunctionKey = "\uF73B";
CPDeleteLineFunctionKey = "\uF73C";
CPInsertCharFunctionKey = "\uF73D";
CPDeleteCharFunctionKey = "\uF73E";
CPPrevFunctionKey = "\uF73F";
CPNextFunctionKey = "\uF740";
CPSelectFunctionKey = "\uF741";
CPExecuteFunctionKey = "\uF742";
CPUndoFunctionKey = "\uF743";
CPRedoFunctionKey = "\uF744";
CPFindFunctionKey = "\uF745";
CPHelpFunctionKey = "\uF746";
CPModeSwitchFunctionKey = "\uF747";
CPEscapeFunctionKey = "\u001B";
CPSpaceFunctionKey = "\u0020";
CPDOMEventDoubleClick = "dblclick";
CPDOMEventMouseDown = "mousedown";
CPDOMEventMouseUp = "mouseup";
CPDOMEventMouseMoved = "mousemove";
CPDOMEventMouseDragged = "mousedrag";
CPDOMEventKeyUp = "keyup";
CPDOMEventKeyDown = "keydown";
CPDOMEventDoubleClick = "dblclick",
CPDOMEventMouseDown = "mousedown",
CPDOMEventMouseUp = "mouseup",
CPDOMEventMouseMoved = "mousemove",
CPDOMEventMouseDragged = "mousedrag",
CPDOMEventKeyUp = "keyup",
CPDOMEventKeyDown = "keydown",
CPDOMEventKeyPress = "keypress";
CPDOMEventCopy = "copy";
CPDOMEventPaste = "paste";
@@ -178,10 +104,9 @@ CPDOMEventTouchEnd = "touchend";
CPDOMEventTouchCancel = "touchcancel";
var _CPEventPeriodicEventPeriod = 0,
_CPEventPeriodicEventTimer = nil,
_CPEventUpperCaseRegex = new RegExp("[A-Z]");
_CPEventPeriodicEventTimer = nil;
/*!
/*!
@ingroup appkit
@class CPEvent
CPEvent encapsulates the details of a Cappuccino keyboard or mouse event.
@@ -211,7 +136,6 @@ var _CPEventPeriodicEventPeriod = 0,
/*!
Creates a new keyboard event.
@param anEventType the event type. Must be one of CPKeyDown, CPKeyUp or CPFlagsChanged
@param aPoint the location of the cursor in the window specified by \c aWindowNumber
@param modifierFlags a bitwise combination of the modifiers specified in the CPEvent globals
@@ -231,13 +155,12 @@ var _CPEventPeriodicEventPeriod = 0,
characters:(CPString)characters charactersIgnoringModifiers:(CPString)unmodCharacters isARepeat:(BOOL)repeatKey keyCode:(unsigned short)code
{
return [[self alloc] _initKeyEventWithType:anEventType location:aPoint modifierFlags:modifierFlags
timestamp:aTimestamp windowNumber:aWindowNumber context:aGraphicsContext
timestamp:aTimestamp windowNumber:aWindowNumber context:aGraphicsContext
characters:characters charactersIgnoringModifiers:unmodCharacters isARepeat:repeatKey keyCode:code];
}
/*!
Creates a new mouse event.
Creates a new mouse event
@param anEventType the event type
@param aPoint the location of the cursor in the window specified by \c aWindowNumber
@param modifierFlags a bitwise combination of the modifiers specified in the CPEvent globals
@@ -250,7 +173,7 @@ var _CPEventPeriodicEventPeriod = 0,
@throws CPInternalInconsistencyException if an invalid event type is provided
@return the new mouse event
*/
+ (id)mouseEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned)modifierFlags
+ (id)mouseEventWithType:(CPEventType)anEventType location:(CGPoint)aPoint modifierFlags:(unsigned)modifierFlags
timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
eventNumber:(int)anEventNumber clickCount:(int)aClickCount pressure:(float)aPressure
{
@@ -259,8 +182,7 @@ var _CPEventPeriodicEventPeriod = 0,
}
/*!
Creates a new custom event.
Creates a new custom event
@param anEventType the event type. Must be one of CPAppKitDefined, CPSystemDefined, CPApplicationDefined or CPPeriodic
@param aLocation the location of the cursor in the window specified by \c aWindowNumber
@param modifierFlags a bitwise combination of the modifiers specified in the CPEvent globals
@@ -281,28 +203,16 @@ var _CPEventPeriodicEventPeriod = 0,
timestamp:aTimestamp windowNumber:aWindowNumber context:aGraphicsContext subtype:aSubtype data1:aData1 data2:aData2];
}
- (id)_initWithType:(CPEventType)anEventType
{
if (self = [super init])
{
_type = anEventType;
// Make sure these are 0 rather than nil.
_deltaX = 0;
_deltaY = 0;
_deltaZ = 0;
}
return self;
}
/* @ignore */
- (id)_initMouseEventWithType:(CPEventType)anEventType location:(CPPoint)aPoint modifierFlags:(unsigned)modifierFlags
- (id)_initMouseEventWithType:(CPEventType)anEventType location:(CPPoint)aPoint modifierFlags:(unsigned)modifierFlags
timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
eventNumber:(int)anEventNumber clickCount:(int)aClickCount pressure:(float)aPressure
{
if (self = [self _initWithType:anEventType])
self = [super init];
if (self)
{
_type = anEventType;
_location = CPPointCreateCopy(aPoint);
_modifierFlags = modifierFlags;
_timestamp = aTimestamp;
@@ -312,7 +222,7 @@ var _CPEventPeriodicEventPeriod = 0,
_pressure = aPressure;
_window = [CPApp windowWithWindowNumber:aWindowNumber];
}
return self;
}
@@ -321,8 +231,11 @@ var _CPEventPeriodicEventPeriod = 0,
timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
characters:(CPString)characters charactersIgnoringModifiers:(CPString)unmodCharacters isARepeat:(BOOL)isARepeat keyCode:(unsigned short)code
{
if (self = [self _initWithType:anEventType])
self = [super init];
if (self)
{
_type = anEventType;
_location = CPPointCreateCopy(aPoint);
_modifierFlags = modifierFlags;
_timestamp = aTimestamp;
@@ -333,7 +246,7 @@ var _CPEventPeriodicEventPeriod = 0,
_keyCode = code;
_windowNumber = aWindowNumber;
}
return self;
}
@@ -342,8 +255,11 @@ var _CPEventPeriodicEventPeriod = 0,
timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
subtype:(short)aSubtype data1:(int)aData1 data2:(int)aData2
{
if (self = [self _initWithType:anEventType])
self = [super init];
if (self)
{
_type = anEventType;
_location = CPPointCreateCopy(aPoint);
_modifierFlags = modifierFlags;
_timestamp = aTimestamp;
@@ -351,17 +267,17 @@ var _CPEventPeriodicEventPeriod = 0,
_subtype = aSubtype;
_data1 = aData1;
_data2 = aData2;
}
}
return self;
}
/*!
Returns the location of the mouse (for mouse events).
If the receiver is not a mouse event, it returns \c nil.
If \c window returns \c nil, then the mouse coordinates will be based on the screen coordinates.
If this is not a mouse event, it returns \c nil.
If \c window returns \c nil, then
the mouse coordinates will be based on the screen coordinates.
Otherwise, the coordinates are relative to the window's coordinates.
@return the location of the mouse, or \c nil for non-mouse events.
*/
- (CGPoint)locationInWindow
@@ -381,7 +297,7 @@ var _CPEventPeriodicEventPeriod = 0,
}
/*!
Returns event information as a bit mask.
Returns event information as a bit mask
*/
- (unsigned)modifierFlags
{
@@ -389,7 +305,7 @@ var _CPEventPeriodicEventPeriod = 0,
}
/*!
Returns the time the event occurred.
Returns the time the event occurred
*/
- (CPTimeInterval)timestamp
{
@@ -405,7 +321,7 @@ var _CPEventPeriodicEventPeriod = 0,
}
/*!
Returns the event's associated window.
Returns the event's associated window
*/
- (CPWindow)window
{
@@ -436,7 +352,7 @@ var _CPEventPeriodicEventPeriod = 0,
}
/*!
Returns the number of clicks that caused this event (mouse only).
Returns the number of clicks that caused this event. (mouse only)
*/
- (int)clickCount
{
@@ -444,8 +360,7 @@ var _CPEventPeriodicEventPeriod = 0,
}
/*!
Returns the characters associated with this event (keyboard only).
Returns the characters associated with this event (keyboard only)
@throws CPInternalInconsistencyException if this method is called on a non-key event
*/
- (CPString)characters
@@ -455,7 +370,6 @@ var _CPEventPeriodicEventPeriod = 0,
/*!
Returns the character ignoring any modifiers (except shift).
@throws CPInternalInconsistencyException if this method is called on a non-key event
*/
- (CPString)charactersIgnoringModifiers
@@ -465,7 +379,6 @@ var _CPEventPeriodicEventPeriod = 0,
/*!
Returns \c YES if the keyboard event was caused by the key being held down.
@throws CPInternalInconsistencyException if this method is called on a non-key event
*/
- (BOOL)isARepeat
@@ -475,7 +388,6 @@ var _CPEventPeriodicEventPeriod = 0,
/*!
Returns the key's key code.
@throws CPInternalInconsistencyException if this method is called on a non-key event
*/
- (unsigned short)keyCode
@@ -508,7 +420,7 @@ var _CPEventPeriodicEventPeriod = 0,
return _DOMEvent;
}
// Getting Scroll Wheel Event Information
// Getting Scroll Wheel Event Infomration
/*!
Returns the change in the x-axis for a mouse event.
*/
@@ -533,94 +445,37 @@ var _CPEventPeriodicEventPeriod = 0,
return _deltaZ;
}
- (BOOL)_triggersKeyEquivalent:(CPString)aKeyEquivalent withModifierMask:aKeyEquivalentModifierMask
{
if (!aKeyEquivalent)
return NO;
if (_CPEventUpperCaseRegex.test(aKeyEquivalent))
aKeyEquivalentModifierMask |= CPShiftKeyMask;
// Windows and Linux don't have command keys, so just switch it to ctrl.
if (!CPBrowserIsOperatingSystem(CPMacOperatingSystem) && (aKeyEquivalentModifierMask & CPCommandKeyMask))
{
aKeyEquivalentModifierMask |= CPControlKeyMask;
aKeyEquivalentModifierMask &= ~CPCommandKeyMask;
}
if ((_modifierFlags & (CPShiftKeyMask | CPAlternateKeyMask | CPCommandKeyMask | CPControlKeyMask)) !== aKeyEquivalentModifierMask)
return NO;
// Treat \r and \n as the same key equivalent. See issue #710.
if (_characters === CPNewlineCharacter || _characters === CPCarriageReturnCharacter)
return CPNewlineCharacter === aKeyEquivalent || CPCarriageReturnCharacter === aKeyEquivalent;
return [_characters caseInsensitiveCompare:aKeyEquivalent] === CPOrderedSame;
}
- (BOOL)_couldBeKeyEquivalent
{
if (_type !== CPKeyDown)
return NO;
var characterCount = _characters.length;
if (!characterCount)
return NO;
if (_modifierFlags & (CPCommandKeyMask | CPControlKeyMask))
return YES;
// Cocoa does not consider space, backspace, or escape a key equivalent
// if the first responder is a text field (presumably a subclass of NSText).
var firstResponderIsText = [[_window firstResponder] isKindOfClass:[CPTextField class]];
for (var i = 0; i < characterCount; i++)
{
var c = _characters.charAt(i);
if ((c >= CPUpArrowFunctionKey && c <= CPModeSwitchFunctionKey) ||
c === CPEnterCharacter ||
c === CPNewlineCharacter ||
c === CPCarriageReturnCharacter ||
c === CPEscapeFunctionKey ||
(!firstResponderIsText &&
(c === CPSpaceFunctionKey ||
c === CPDeleteCharacter ||
c === CPBackspaceCharacter)))
{
return YES;
}
}
// FIXME: More cases?
return NO;
// FIXME: More cases? Space?
return _type === CPKeyDown &&
_modifierFlags & (CPCommandKeyMask | CPControlKeyMask) &&
[_characters length] > 0;
}
/*!
Generates periodic events every \c aPeriod seconds.
@param aDelay the number of seconds before the first event
@param aPeriod the length of time in seconds between successive events
*/
+ (void)startPeriodicEventsAfterDelay:(CPTimeInterval)aDelay withPeriod:(CPTimeInterval)aPeriod
{
_CPEventPeriodicEventPeriod = aPeriod;
// FIXME: OH TIMERS!!!
_CPEventPeriodicEventTimer = window.setTimeout(function() { _CPEventPeriodicEventTimer = window.setInterval(_CPEventFirePeriodEvent, aPeriod * 1000.0); }, aDelay * 1000.0);
}
/*!
Stops the periodic events from being generated.
Stops the periodic events from being generated
*/
+ (void)stopPeriodicEvents
{
if (_CPEventPeriodicEventTimer === nil)
return;
window.clearTimeout(_CPEventPeriodicEventTimer);
_CPEventPeriodicEventTimer = nil;
}
@@ -650,3 +505,4 @@ function _CPEventFromNativeMouseEvent(aNativeEvent, anEventType, aPoint, modifie
return aNativeEvent;
}
+3 -4
View File
@@ -22,8 +22,7 @@
@import <Foundation/CPObject.j>
/*!
/*!
@ingroup appkit
@class CPFlashMovie
@@ -52,10 +51,10 @@
- (id)initWithFile:(CPString)aFilename
{
self = [super init];
if (self)
_filename = aFilename;
return self;
}
+24 -26
View File
@@ -23,6 +23,7 @@
@import "CPFlashMovie.j"
@import "CPView.j"
#include "Platform/Platform.h"
var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
@@ -32,10 +33,10 @@ var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
@implementation CPFlashView : CPView
{
CPFlashMovie _flashMovie;
CPDictionary _params;
CPDictionary _paramElements;
#if PLATFORM(DOM)
#if PLATFORM(DOM)
DOMElement _DOMParamElement;
DOMElement _DOMObjectElement;
DOMElement _DOMInnerObjectElement;
@@ -45,7 +46,7 @@ var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
#if PLATFORM(DOM)
@@ -58,24 +59,24 @@ var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
_DOMObjectElement.style.left = @"0px";
_DOMObjectElement.type = @"application/x-shockwave-flash";
_DOMObjectElement.setAttribute(@"classid", IEFlashCLSID);
_DOMParamElement = document.createElement(@"param");
_DOMParamElement.name = @"movie";
_DOMInnerObjectElement = document.createElement(@"object");
_DOMInnerObjectElement.width = @"100%";
_DOMInnerObjectElement.height = @"100%";
_DOMObjectElement.appendChild(_DOMParamElement);
_DOMObjectElement.appendChild(_DOMInnerObjectElement);
_DOMElement.appendChild(_DOMObjectElement);
}
else
[self _rebuildIEObjects];
#endif
}
return self;
}
@@ -83,7 +84,7 @@ var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
{
if (_flashMovie == aFlashMovie)
return;
_flashMovie = aFlashMovie;
#if PLATFORM(DOM)
if (!CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
@@ -105,14 +106,14 @@ var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
{
var varString = @"",
enumerator = [aDictionary keyEnumerator];
var key;
while (key = [enumerator nextObject])
varString = [varString stringByAppendingFormat:@"&%@=%@", key, [aDictionary objectForKey:key]];
if (!_params)
_params = [CPDictionary dictionary];
[_params setObject:varString forKey:@"flashvars"];
[self setParameters:_params];
}
@@ -129,31 +130,28 @@ var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
{
var elements = [_paramElements allValues],
count = [elements count];
for (var i = 0; i < count; i++)
_DOMObjectElement.removeChild([elements objectAtIndex:i]);
}
#endif
if (!_params)
_params = aDictionary;
else
[_params addEntriesFromDictionary:aDictionary];
_params = aDictionary;
#if PLATFORM(DOM)
if (!CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
{
_paramElements = [CPDictionary dictionary];
var enumerator = [_params keyEnumerator],
key;
while (_DOMObjectElement && (key = [enumerator nextObject]))
while (key = [enumerator nextObject] && _DOMObjectElement)
{
var param = document.createElement(@"param");
param.name = key;
param.value = [_params objectForKey:key];
_DOMObjectElement.appendChild(param);
[_paramElements setObject:param forKey:key];
}
}
@@ -173,17 +171,17 @@ var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
_DOMElement.innerHTML = @"";
if (![_flashMovie filename])
return;
var paramString = [CPString stringWithFormat:@"<param name='movie' value='%@' />", [_flashMovie filename]],
paramEnumerator = [_params keyEnumerator],
key;
while (key = [paramEnumerator nextObject])
paramString = [paramString stringByAppendingFormat:@"<param name='%@' value='%@' />", key, [_params objectForKey:key]];
_DOMObjectElement = document.createElement(@"object");
_DOMElement.appendChild(_DOMObjectElement);
_DOMObjectElement.outerHTML = [CPString stringWithFormat:@"<object classid=%@ width=%@ height=%@>%@</object>", IEFlashCLSID, CGRectGetWidth([self bounds]), CGRectGetHeight([self bounds]), paramString];
}
#endif
+33 -255
View File
@@ -20,254 +20,94 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPObject.j>
@import <Foundation/CPBundle.j>
@import "CPView.j"
CPFontDefaultSystemFontFace = @"Arial, sans-serif";
CPFontDefaultSystemFontSize = 12;
var _CPFonts = {},
_CPFontSystemFontFace = CPFontDefaultSystemFontFace,
_CPFontSystemFontSize = 12,
_CPFontFallbackFaces = CPFontDefaultSystemFontFace.split(", "),
_CPFontStripRegExp = new RegExp("(^\\s*[\"']?|[\"']?\\s*$)", "g");
var _CPFonts = {},
_CPFontSystemFontFace = @"Arial, sans-serif",
_CPWrapRegExp = new RegExp("\\s*,\\s*", "g");
#define _CPFontNormalizedNames(aName) _CPFontNormalizedNameArray(aName).join(", ")
#define _CPCachedFont(aName, aSize, isBold, isItalic) _CPFonts[_CPFontCreateCSSString(_CPFontNormalizedNames(aName), aSize, isBold, isItalic)]
#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
The CPFont class allows control of the fonts used for displaying text anywhere on the screen.
The primary method for getting a particular font is through one of the class methods that take
a name and/or size as arguments, and return the appropriate CPFont.
By default the system font face/size is Arial 12px, with a fallback to sans-serif. You may
configure this at runtime in two ways:
- By sending [CPFont @link CPFont::setSystemFontFace: setSystemFontFace:@endlink] and/or [CPFont @link CPFont::setSystemFontSize: setSystemFontSize:@endlink].
- By configuring Info.plist for your application or for AppKit. You can set the font face
by adding a CPSystemFontFace string item to the Info.plist, and you can set the font size
by adding a CPSystemFontSize integer item to the Info.plist.
Note that in either case, you can specify a comma-delimited list of fonts as the font face.
The browser will use the first available font in the list. CPFont always ensures that Arial
and sans-serif are in the generated CSS string, so there is no need to add them to the end
of your font list.
If you are using nib2cib, you should use the second method (using Info.plist),
and be sure to run nib2cib again any time you modify the CPSystemFontFace or CPSystemFontSize items.
For example, you might add this to your application's Info.plist to set the system font to Lucida Grande,
with an automatic fallback to Arial or sans-serif:
@code
<key>CPSystemFontFace</key>
<string>Lucida Grande</string>
@endcode
The CPFont class allows control of the fonts used for displaying text anywhere on the screen. The primary method for getting a particular font is through one of the class methods that take a name and/or size as arguments, and return the appropriate CPFont.
*/
@implementation CPFont : CPObject
{
CPString _name;
float _size;
float _ascender;
float _descender;
float _lineHeight;
BOOL _isBold @accessors(readonly, getter=isBold);
BOOL _isItalic @accessors(readonly, getter=isItalic);
BOOL _isBold;
CPString _cssString;
}
+ (void)initialize
{
var systemFontFace = [[CPBundle mainBundle] objectForInfoDictionaryKey:@"CPSystemFontFace"];
if (!systemFontFace)
systemFontFace = [[CPBundle bundleForClass:[CPView class]] objectForInfoDictionaryKey:@"CPSystemFontFace"];
if (systemFontFace)
[self setSystemFontFace:systemFontFace];
var systemFontSize = [[CPBundle mainBundle] objectForInfoDictionaryKey:@"CPSystemFontSize"];
if (!systemFontSize)
systemFontSize = [[CPBundle bundleForClass:[CPView class]] objectForInfoDictionaryKey:@"CPSystemFontSize"];
if (systemFontSize)
_CPFontSystemFontSize = systemFontSize;
}
/*!
Returns the default system font face, which may consist of several comma-separated family names.
*/
+ (CPString)systemFontFace
{
return _CPFontSystemFontFace;
}
/*!
Sets the default system font face, which may consist of several comma-separated family names.
*/
+ (CPString)setSystemFontFace:(CPString)aFace
{
_CPFontSystemFontFace = _CPFontNormalizedNames(aFace);
}
/*!
Returns the default system font size.
*/
+ (float)systemFontSize
{
return _CPFontSystemFontSize;
}
/*!
Sets the default system font size.
*/
+ (float)setSystemFontSize:(float)size
{
if (size > 0)
_CPFontSystemFontSize = size;
}
/*!
Returns a font with the specified name and size.
@param aName the name of the font
@param aSize the size of the font (in px)
@param aSize the size of the font (in points)
@return the requested font
*/
+ (CPFont)fontWithName:(CPString)aName size:(float)aSize
{
return _CPCachedFont(aName, aSize, NO, NO) || [[CPFont alloc] _initWithName:aName size:aSize bold:NO italic:NO];
}
/*!
Returns a font with the specified name, size and style.
@param aName the name of the font
@param aSize the size of the font (in px)
@param italic whether the font should be italicized
@return the requested font
*/
+ (CPFont)fontWithName:(CPString)aName size:(float)aSize italic:(BOOL)italic
{
return _CPCachedFont(aName, aSize, NO, NO) || [[CPFont alloc] _initWithName:aName size:aSize bold:NO italic:italic];
return _CPCachedFont(aName, aSize, NO) || [[CPFont alloc] _initWithName:aName size:aSize bold:NO];
}
/*!
Returns a bold font with the specified name and size.
@param aName the name of the font
@param aSize the size of the font (in px)
@param aSize the size of the font (in points)
@return the requested bold font
*/
+ (CPFont)boldFontWithName:(CPString)aName size:(float)aSize
{
return _CPCachedFont(aName, aSize, YES, NO) || [[CPFont alloc] _initWithName:aName size:aSize bold:YES italic:NO];
}
/*!
Returns a bold font with the specified name, size and style.
@param aName the name of the font
@param aSize the size of the font (in px)
@param italic whether the font should be italicized
@return the requested font
*/
+ (CPFont)boldFontWithName:(CPString)aName size:(float)aSize italic:(BOOL)italic
{
return _CPCachedFont(aName, aSize, NO, NO) || [[CPFont alloc] _initWithName:aName size:aSize bold:YES italic:italic];
return _CPCachedFont(aName, aSize, YES) || [[CPFont alloc] _initWithName:aName size:aSize bold:YES];
}
/*!
Returns the system font scaled to the specified size
@param aSize the size of the font (in px)
@param aSize the size of the font (in points)
@return the requested system font
*/
+ (CPFont)systemFontOfSize:(CPSize)aSize
{
return _CPCachedFont(_CPFontSystemFontFace, aSize, NO, NO) || [[CPFont alloc] _initWithName:_CPFontSystemFontFace size:aSize bold:NO italic:NO];
return _CPCachedFont(_CPFontSystemFontFace, aSize, NO) || [[CPFont alloc] _initWithName:_CPFontSystemFontFace size:aSize bold:NO];
}
/*!
Returns the bold system font scaled to the specified size
@param aSize the size of the font (in px)
@param aSize the size of the font (in points)
@return the requested bold system font
*/
+ (CPFont)boldSystemFontOfSize:(CPSize)aSize
{
return _CPCachedFont(_CPFontSystemFontFace, aSize, YES, NO) || [[CPFont alloc] _initWithName:_CPFontSystemFontFace size:aSize bold:YES italic:NO];
return _CPCachedFont(_CPFontSystemFontFace, aSize, YES) || [[CPFont alloc] _initWithName:_CPFontSystemFontFace size:aSize bold:YES];
}
/* FIXME Font Descriptor
@ignore
*/
- (id)_initWithName:(CPString)aName size:(float)aSize bold:(BOOL)isBold
{
return [self _initWithName:aName size:aSize bold:isBold italic:NO];
}
- (id)_initWithName:(CPString)aName size:(float)aSize bold:(BOOL)isBold italic:(BOOL)isItalic
{
{
self = [super init];
if (self)
{
_name = _CPFontNormalizedNames(aName);
_name = aName;
_size = aSize;
_ascender = 0;
_descender = 0;
_lineHeight = 0;
_isBold = isBold;
_isItalic = isItalic;
_cssString = _CPFontCreateCSSString(_name, _size, _isBold, _isItalic);
_cssString = _CPCreateCSSString(_name, _size, _isBold);
_CPFonts[_cssString] = self;
}
return self;
}
/*!
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 px 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)
Returns the font size (in points)
*/
- (float)size
{
@@ -292,34 +132,19 @@ var _CPFonts = {},
- (BOOL)isEqual:(id)anObject
{
return [anObject isKindOfClass:[CPFont class]] && [anObject cssString] === _cssString;
return [anObject isKindOfClass:[CPFont class]] && [anObject cssString] === [self cssString];
}
- (CPString)description
{
return [CPString stringWithFormat:@"%@ %@", [super description], [self cssString]];
}
- (id)copy
{
return [[CPFont alloc] _initWithName:_name size:_size bold:_isBold italic:_isItalic];
}
- (void)_getMetrics
{
var metrics = [CPString metricsOfFont:self];
_ascender = [metrics objectForKey:@"ascender"];
_descender = [metrics objectForKey:@"descender"];
_lineHeight = [metrics objectForKey:@"lineHeight"];
return [CPString stringWithFormat:@"%@ %@ %f pt.", [super description], [self familyName], [self size]];
}
@end
var CPFontNameKey = @"CPFontNameKey",
CPFontSizeKey = @"CPFontSizeKey",
CPFontIsBoldKey = @"CPFontIsBoldKey",
CPFontIsItalicKey = @"CPFontIsItalicKey";
var CPFontNameKey = @"CPFontNameKey",
CPFontSizeKey = @"CPFontSizeKey",
CPFontIsBoldKey = @"CPFontIsBoldKey";
@implementation CPFont (CPCoding)
@@ -330,12 +155,9 @@ var CPFontNameKey = @"CPFontNameKey",
*/
- (id)initWithCoder:(CPCoder)aCoder
{
var fontName = [aCoder decodeObjectForKey:CPFontNameKey],
size = [aCoder decodeFloatForKey:CPFontSizeKey],
isBold = [aCoder decodeBoolForKey:CPFontIsBoldKey],
isItalic = [aCoder decodeBoolForKey:CPFontIsItalicKey];
return [self _initWithName:fontName size:size bold:isBold italic:isItalic];
return [self _initWithName:[aCoder decodeObjectForKey:CPFontNameKey]
size:[aCoder decodeFloatForKey:CPFontSizeKey]
bold:[aCoder decodeBoolForKey:CPFontIsBoldKey]];
}
/*!
@@ -347,50 +169,6 @@ var CPFontNameKey = @"CPFontNameKey",
[aCoder encodeObject:_name forKey:CPFontNameKey];
[aCoder encodeFloat:_size forKey:CPFontSizeKey];
[aCoder encodeBool:_isBold forKey:CPFontIsBoldKey];
[aCoder encodeBool:_isItalic forKey:CPFontIsItalicKey];
}
@end
// aName must be normalized
var _CPFontCreateCSSString = function(aName, aSize, isBold, isItalic)
{
var properties = (isItalic ? "italic " : "") + (isBold ? "bold " : "") + aSize + "px ";
return properties + _CPFontConcatNameWithFallback(aName);
};
var _CPFontConcatNameWithFallback = function(aName)
{
var names = _CPFontNormalizedNameArray(aName),
fallbackFaces = _CPFontFallbackFaces.slice(0);
// Remove the fallback names used in the names passed in
for (var i = 0; i < names.length; ++i)
{
for (var j = 0; j < fallbackFaces.length; ++j)
{
if (names[i].toLowerCase() === fallbackFaces[j].toLowerCase())
{
fallbackFaces.splice(j, 1);
break;
}
}
if (names[i].indexOf(" ") > 0)
names[i] = '"' + names[i] + '"';
}
return names.concat(fallbackFaces).join(", ");
};
var _CPFontNormalizedNameArray = function(aName)
{
var names = aName.split(",");
for (var i = 0; i < names.length; ++i)
names[i] = names[i].replace(_CPFontStripRegExp, "");
return names;
};
+33 -39
View File
@@ -22,7 +22,7 @@
@import <Foundation/CPObject.j>
@import "CPFont.j"
@import <AppKit/CPFont.j>
var CPSharedFontManager = nil,
@@ -45,7 +45,7 @@ var CPSharedFontManager = nil,
{
if (!CPSharedFontManager)
CPSharedFontManager = [[CPFontManagerFactory alloc] init];
return CPSharedFontManager;
}
@@ -65,7 +65,7 @@ var CPSharedFontManager = nil,
- (CPArray)availableFonts
{
if (!_availableFonts)
{
{
_CPFontDetectSpan = document.createElement("span");
_CPFontDetectSpan.fontSize = "24px";
_CPFontDetectSpan.appendChild(document.createTextNode("mmmmmmmmmml"));
@@ -74,14 +74,13 @@ var CPSharedFontManager = nil,
div.style.top = "-1000px";
div.appendChild(_CPFontDetectSpan);
document.getElementsByTagName("body")[0].appendChild(div);
_CPFontDetectReferenceFonts = _CPFontDetectPickTwoDifferentFonts(["monospace", "serif", "sans-serif", "cursive"]);
_CPFontDetectReferenceFonts = _CPFontDetectPickTwoDifferentFonts(["monospace", "serif", "sans-serif", "cursive"]);
_availableFonts = [];
for (var i = 0; i < _CPFontDetectAllFonts.length; i++)
{
for (var i = 0; i < _CPFontDetectAllFonts.length; i++) {
var available = _CPFontDetectFontAvailable(_CPFontDetectAllFonts[i]);
if (available)
if (available)
_availableFonts.push(_CPFontDetectAllFonts[i]);
}
}
@@ -102,8 +101,8 @@ var CPSharedFontManager = nil,
var _CPFontDetectSpan,
_CPFontDetectReferenceFonts,
_CPFontDetectAllFonts = [
/* "04b_21","A Charming Font","Abadi MT Condensed","Abadi MT Condensed Extra Bold","Abadi MT Condensed Light","Academy Engraved LET","Agency FB","Alba","Alba Matter","Alba Super","Algerian",*/
"American Typewriter",
/* "04b_21","A Charming Font","Abadi MT Condensed","Abadi MT Condensed Extra Bold","Abadi MT Condensed Light","Academy Engraved LET","Agency FB","Alba","Alba Matter","Alba Super","Algerian",*/
"American Typewriter",
/* "Andale Mono","Andale Mono IPA","Andy", */
"Apple Chancery","Arial","Arial Black","Arial Narrow","Arial Rounded MT Bold","Arial Unicode MS",
/* "Avant Garde","Avantgarde","Baby Kruffy","Base 02","Baskerville","Baskerville Old Face","Bauhaus 93","Beesknees ITC","Bell MT","Berlin Sans FB","Berlin Sans FB Demi","Bernard MT Condensed","Bickley Script",*/
@@ -123,8 +122,8 @@ var _CPFontDetectSpan,
/* "GlooGun","Gloucester MT Extra Condensed","Goudy Old Style","Goudy Stout","Haettenschweiler","Harlow Solid Italic","Harrington",*/
"Helvetica","Helvetica Narrow","Helvetica Neue","Herculanum","High Tower Text","Highlight LET","Hoefler Text","Impact","Imprint MT Shadow",
/* "Informal Roman","Jenkins v2.0","John Handy LET","Jokerman","Jokerman LET","Jokewood","Juice ITC","Kabel Ult BT","Kartika","Kino MT","Kristen ITC","Kunstler Script","La Bamba LET", */
"Lucida","Lucida Bright","Lucida Calligraphy","Lucida Console","Lucida Fax","Lucida Grande","Lucida Handwriting","Lucida Sans","Lucida Sans Typewriter","Lucida Sans Unicode",
/* "Luxi Mono","Luxi Sans","Luxi Serif","MARKETPRO","MS Reference Sans Serif","MS Reference Serif","Magneto","Maiandra GD", */
"Lucida","Lucida Bright","Lucida Calligraphy","Lucida Console","Lucida Fax","Lucida Grande","Lucida Handwriting","Lucida Sans","Lucida Sans Typewriter","Lucida Sans Unicode",
/* "Luxi Mono","Luxi Sans","Luxi Serif","MARKETPRO","MS Reference Sans Serif","MS Reference Serif","Magneto","Maiandra GD", */
"Marker Felt",
/* "Matisse ITC","Matura MT Script Capitals","Mead Bold","Mekanik LET","Mercurius Script MT Bold", */
"Microsoft Sans Serif","Milano LET","Minion Web","MisterEarl BT","Mistral","Monaco","Monotype Corsiva","Monotype.com","New Century Schoolbook","New York","News Gothic MT",
@@ -137,44 +136,39 @@ var _CPFontDetectSpan,
"Zapfino"];
// Compare against the reference fonts. Return true if it produces a different size than at least one of them.
var _CPFontDetectFontAvailable = function(font)
{
for (var i = 0; i < _CPFontDetectReferenceFonts.length; i++)
if (_CPFontDetectCompareFonts(_CPFontDetectReferenceFonts[i], font))
return true;
return false;
var _CPFontDetectFontAvailable = function(font) {
for (var i = 0; i < _CPFontDetectReferenceFonts.length; i++)
if (_CPFontDetectCompareFonts(_CPFontDetectReferenceFonts[i], font))
return true;
return false;
}
var _CPFontDetectCache = {};
// Compares two given fonts. Returns true if they produce different sizes (i.e. fontA didn't fallback to fontB)
var _CPFontDetectCompareFonts = function(fontA, fontB)
{
var _CPFontDetectCompareFonts = function(fontA, fontB) {
var a;
if (_CPFontDetectCache[fontA])
if (_CPFontDetectCache[fontA]) {
a = _CPFontDetectCache[fontA];
else
{
_CPFontDetectSpan.style.fontFamily = '"' + fontA + '"';
} else {
_CPFontDetectSpan.style.fontFamily = '"' + fontA + '"';
_CPFontDetectCache[fontA] = a = { w: _CPFontDetectSpan.offsetWidth, h: _CPFontDetectSpan.offsetHeight };
}
_CPFontDetectSpan.style.fontFamily = '"' + fontB + '", "' + fontA + '"';
var bWidth = _CPFontDetectSpan.offsetWidth,
bHeight = _CPFontDetectSpan.offsetHeight;
return (a.w != bWidth || a.h != bHeight);
_CPFontDetectSpan.style.fontFamily= '"' + fontB + '", "' + fontA + '"';
var bWidth = _CPFontDetectSpan.offsetWidth;
var bHeight = _CPFontDetectSpan.offsetHeight;
return (a.w != bWidth || a.h != bHeight);
}
// Test the candidate fonts pairwise until we find two that are different. Otherwise return the first.
var _CPFontDetectPickTwoDifferentFonts = function(candidates)
{
for (var i = 0; i < candidates.length; i++)
for (var j = 0; j < i; j++)
if (_CPFontDetectCompareFonts(candidates[i], candidates[j]))
return [candidates[i], candidates[j]];
return [candidates[0]];
var _CPFontDetectPickTwoDifferentFonts = function(candidates) {
for (var i = 0; i < candidates.length; i++)
for (var j = 0; j < i; j++)
if (_CPFontDetectCompareFonts(candidates[i], candidates[j]))
return [candidates[i], candidates[j]];
return [candidates[0]];
}
[CPFontManager setFontManagerFactory:[CPFontManager class]];
+16 -30
View File
@@ -70,8 +70,8 @@ function CPPointMake(x, y)
*/
function CPRectInset(aRect, dX, dY)
{
return CPRectMake( aRect.origin.x + dX, aRect.origin.y + dY,
aRect.size.width - 2 * dX, aRect.size.height - 2 * 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,20 +380,6 @@ 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
@@ -448,7 +434,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) };
}
@@ -461,7 +447,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) };
}
@@ -474,7 +460,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)) };
}
@@ -518,6 +504,6 @@ function CPPointMakeZero()
return CPPointMake(0, 0, 0);
}
/*!
/*!
@}
*/
-108
View File
@@ -1,108 +0,0 @@
/*
* CPGraphics.j
* AppKit
*
* Created by Francisco Tolmasky.
* Copyright 2010, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPColor.j"
@import "CPGraphicsContext.j"
function CPDrawTiledRects(
/* CGRect */ boundsRect,
/* CGRect */ clipRect,
/* CPRectEdge[] */ sides,
/* float[] */ grays)
{
if (sides.length != grays.length)
[CPException raise:CPInvalidArgumentException reason:@"sides (length: " + sides.length + ") and grays (length: " + grays.length + ") must have the same length."];
var colors = [];
for (var i = 0; i < grays.length; ++i)
colors.push([CPColor colorWithCalibratedWhite:grays[i] alpha:1.0]);
return CPDrawColorTiledRects(boundsRect, clipRect, sides, colors);
}
function CPDrawColorTiledRects(
/* CGRect */ boundsRect,
/* CGRect */ clipRect,
/* CPRectEdge[] */ sides,
/* CPColor[] */ colors)
{
if (sides.length != colors.length)
[CPException raise:CPInvalidArgumentException reason:@"sides (length: " + sides.length + ") and colors (length: " + colors.length + ") must have the same length."];
var resultRect = _CGRectMakeCopy(boundsRect),
slice = _CGRectMakeZero(),
remainder = _CGRectMakeZero(),
context = [[CPGraphicsContext currentContext] graphicsPort];
CGContextSaveGState(context);
CGContextSetLineWidth(context, 1.0);
for (var sideIndex = 0; sideIndex < sides.length; ++sideIndex)
{
var side = sides[sideIndex];
CGRectDivide(resultRect, slice, remainder, 1.0, side);
resultRect = remainder;
slice = CGRectIntersection(slice, clipRect);
// Cocoa docs say that only slices that are within the clipRect are actually drawn
if (_CGRectIsEmpty(slice))
continue;
var minX, maxX, minY, maxY;
if (side == CPMinXEdge || side == CPMaxXEdge)
{
// Make sure we have at least 1 pixel to draw a line
if (_CGRectGetWidth(slice) < 1.0)
continue;
minX = _CGRectGetMinX(slice) + 0.5;
maxX = minX;
minY = _CGRectGetMinY(slice);
maxY = _CGRectGetMaxY(slice);
}
else // CPMinYEdge || CPMaxYEdge
{
// Make sure we have at least 1 pixel to draw a line
if (_CGRectGetHeight(slice) < 1.0)
continue;
minX = _CGRectGetMinX(slice);
maxX = _CGRectGetMaxX(slice);
minY = _CGRectGetMinY(slice) + 0.5;
maxY = minY;
}
CGContextBeginPath(context);
CGContextMoveToPoint(context, minX, minY);
CGContextAddLineToPoint(context, maxX, maxY);
CGContextSetStrokeColor(context, colors[sideIndex]);
CGContextStrokePath(context);
}
CGContextRestoreGState(context);
return resultRect;
}
+4 -9
View File
@@ -20,12 +20,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPObject.j>
@import "CGContext.j"
var CPGraphicsContextCurrent = nil;
var CPGraphicsContextCurrent = nil;
/*!
@ingroup appkit
@@ -33,7 +28,7 @@ var CPGraphicsContextCurrent = nil;
*/
@implementation CPGraphicsContext : CPObject
{
CGContext _graphicsPort;
CPContext _graphicsPort;
}
/*!
@@ -71,10 +66,10 @@ var CPGraphicsContextCurrent = nil;
- (id)initWithGraphicsPort:(CPContext)aGraphicsPort
{
self = [super init];
if (self)
_graphicsPort = aGraphicsPort;
return self;
}
+9 -31
View File
@@ -28,6 +28,8 @@
@import "CPGeometry.j"
#include "Platform/Platform.h"
CPImageLoadStatusInitialized = 0;
CPImageLoadStatusLoading = 1;
@@ -44,8 +46,7 @@ CPImageNameColorPanel = @"CPImageNameColorPanel";
CPImageNameColorPanelHighlighted = @"CPImageNameColorPanelHighlighted";
var imagesForNames = { },
AppKitImageForNames = { },
ImageDescriptionFormat = "%s {\n filename: \"%s\",\n size: { width:%f, height:%f }\n}";
AppKitImageForNames = { };
AppKitImageForNames[CPImageNameColorPanel] = CGSizeMake(26.0, 29.0);
AppKitImageForNames[CPImageNameColorPanelHighlighted] = CGSizeMake(26.0, 29.0);
@@ -66,7 +67,7 @@ function CPAppKitImage(aFilename, aSize)
return CPImageInBundle(aFilename, aSize, [CPBundle bundleForClass:[CPView class]]);
}
/*!
/*!
@ingroup appkit
@class CPImage
@@ -74,7 +75,7 @@ function CPAppKitImage(aFilename, aSize)
all image types supported by the browser.
@par Delegate Methods
@delegate -(void)imageDidLoad:(CPImage)image;
Called when the specified image has finished loading.
@param image the image that loaded
@@ -192,9 +193,6 @@ function CPAppKitImage(aFilename, aSize)
var imageOrSize = AppKitImageForNames[aName];
if (!imageOrSize)
return nil;
if (!imageOrSize.isa)
{
imageOrSize = CPAppKitImage("CPImage/" + aName + ".png", imageOrSize);
@@ -207,19 +205,17 @@ function CPAppKitImage(aFilename, aSize)
return imageOrSize;
}
- (BOOL)setName:(CPString)aName
- (void)setName:(CPString)aName
{
if (_name === aName)
return YES;
return;
if (imagesForNames[aName])
return NO;
if (imagesForNames[aName] === self)
imagesForNames[aName] = nil;
_name = aName;
imagesForNames[aName] = self;
return YES;
}
- (CPString)name
@@ -325,24 +321,6 @@ function CPAppKitImage(aFilename, aSize)
return NO;
}
- (CPString)description
{
var filename = [self filename],
size = [self size];
if (filename.indexOf("data:") === 0)
{
var index = filename.indexOf(",");
if (index > 0)
filename = [CPString stringWithFormat:@"%s,%s...%s", filename.substr(0, index), filename.substr(index + 1, 10), filename.substr(filename.length - 10)];
else
filename = "data:<unknown type>";
}
return [CPString stringWithFormat:ImageDescriptionFormat, [super description], filename, size.width, size.height];
}
/* @ignore */
- (void)_derefFromImage
{
+51 -131
View File
@@ -26,24 +26,17 @@
@import "CPImage.j"
@import "CPShadowView.j"
#include "Platform/Platform.h"
#include "Platform/DOM/CPDOMDisplayServer.h"
#include "CoreGraphics/CGGeometry.h"
CPScaleProportionally = 0;
CPScaleToFit = 1;
CPScaleNone = 2;
CPImageAlignCenter = 0;
CPImageAlignTop = 1;
CPImageAlignTopLeft = 2;
CPImageAlignTopRight = 3;
CPImageAlignLeft = 4;
CPImageAlignBottom = 5;
CPImageAlignBottomLeft = 6;
CPImageAlignBottomRight = 7;
CPImageAlignRight = 8;
var CPImageViewShadowBackgroundColor = nil,
CPImageViewEmptyPlaceholderImage = nil;
var CPImageViewShadowBackgroundColor = nil;
var LEFT_SHADOW_INSET = 3.0,
RIGHT_SHADOW_INSET = 3.0,
TOP_SHADOW_INSET = 3.0,
@@ -51,7 +44,7 @@ var LEFT_SHADOW_INSET = 3.0,
VERTICAL_SHADOW_INSET = TOP_SHADOW_INSET + BOTTOM_SHADOW_INSET,
HORIZONTAL_SHADOW_INSET = LEFT_SHADOW_INSET + RIGHT_SHADOW_INSET;
/*!
/*!
@ingroup appkit
@class CPImageView
@@ -59,28 +52,20 @@ 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;
CPImageAlignment _imageAlignment;
}
+ (void)initialize
{
var bundle = [CPBundle bundleForClass:[CPView class]];
CPImageViewEmptyPlaceholderImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"empty.png"]];
CGRect _imageRect;
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
#if PLATFORM(DOM)
@@ -96,11 +81,11 @@ var LEFT_SHADOW_INSET = 3.0,
}
CPDOMDisplayServerAppendChild(_DOMElement, _DOMImageElement);
_DOMImageElement.style.visibility = "hidden";
#endif
}
return self;
}
@@ -121,29 +106,29 @@ var LEFT_SHADOW_INSET = 3.0,
- (void)setObjectValue:(CPImage)anImage
{
var oldImage = [self objectValue];
if (oldImage === anImage)
return;
[super setObjectValue:anImage];
var defaultCenter = [CPNotificationCenter defaultCenter];
if (oldImage)
[defaultCenter removeObserver:self name:CPImageDidLoadNotification object:oldImage];
var newImage = [self objectValue];
#if PLATFORM(DOM)
_DOMImageElement.src = newImage ? [newImage filename] : [CPImageViewEmptyPlaceholderImage filename];
_DOMImageElement.src = newImage ? [newImage filename] : "";
#endif
var size = [newImage size];
if (size && size.width === -1 && size.height === -1)
{
[defaultCenter addObserver:self selector:@selector(imageDidLoad:) name:CPImageDidLoadNotification object:newImage];
#if PLATFORM(DOM)
_DOMImageElement.width = 0;
_DOMImageElement.height = 0;
@@ -162,7 +147,7 @@ var LEFT_SHADOW_INSET = 3.0,
- (void)imageDidLoad:(CPNotification)aNotification
{
[self hideOrDisplayContents];
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
@@ -184,52 +169,28 @@ var LEFT_SHADOW_INSET = 3.0,
{
if (_hasShadow == shouldHaveShadow)
return;
_hasShadow = shouldHaveShadow;
if (_hasShadow)
{
_shadowView = [[CPShadowView alloc] initWithFrame:[self bounds]];
[self addSubview:_shadowView];
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
else
{
[_shadowView removeFromSuperview];
_shadowView = nil;
}
[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.
@@ -238,14 +199,14 @@ var LEFT_SHADOW_INSET = 3.0,
- (void)setImageScaling:(CPImageScaling)anImageScaling
{
[super setImageScaling:anImageScaling];
#if PLATFORM(DOM)
if ([self currentValueForThemeAttribute:@"image-scaling"] === CPScaleToFit)
{
CPDOMDisplayServerSetStyleLeftTop(_DOMImageElement, NULL, 0.0, 0.0);
}
#endif
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
@@ -314,7 +275,7 @@ var LEFT_SHADOW_INSET = 3.0,
else
{
var size = [image size];
if (size.width == -1 && size.height == -1)
return;
@@ -331,7 +292,7 @@ var LEFT_SHADOW_INSET = 3.0,
{
var imageRatio = size.width / size.height,
viewRatio = width / height;
if (viewRatio > imageRatio)
width = height * imageRatio;
else
@@ -348,7 +309,7 @@ var LEFT_SHADOW_INSET = 3.0,
width = size.width;
height = size.height;
}
if (imageScaling == CPScaleNone)
{
#if PLATFORM(DOM)
@@ -357,46 +318,8 @@ var LEFT_SHADOW_INSET = 3.0,
#endif
}
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;
}
var x = (boundsWidth - width) / 2.0,
y = (boundsHeight - height) / 2.0;
#if PLATFORM(DOM)
CPDOMDisplayServerSetStyleLeftTop(_DOMImageElement, NULL, x, y);
@@ -404,7 +327,7 @@ var LEFT_SHADOW_INSET = 3.0,
}
_imageRect = _CGRectMake(x, y, width, height);
if (_hasShadow)
[_shadowView setFrame:_CGRectMake(x - LEFT_SHADOW_INSET, y - TOP_SHADOW_INSET, width + insetWidth, height + insetHeight)];
}
@@ -451,17 +374,16 @@ var LEFT_SHADOW_INSET = 3.0,
[self setImage:images[0]];
[self sendAction:[self action] to:[self target]];
}
return YES;
}
@end
var CPImageViewImageKey = @"CPImageViewImageKey",
CPImageViewImageScalingKey = @"CPImageViewImageScalingKey",
CPImageViewImageAlignmentKey = @"CPImageViewImageAlignmentKey",
CPImageViewHasShadowKey = @"CPImageViewHasShadowKey",
CPImageViewIsEditableKey = @"CPImageViewIsEditableKey";
var CPImageViewImageKey = @"CPImageViewImageKey",
CPImageViewImageScalingKey = @"CPImageViewImageScalingKey",
CPImageViewHasShadowKey = @"CPImageViewHasShadowKey",
CPImageViewIsEditableKey = @"CPImageViewIsEditableKey";
@implementation CPImageView (CPCoding)
@@ -486,7 +408,7 @@ var CPImageViewImageKey = @"CPImageViewImageKey",
#endif
self = [super initWithCoder:aCoder];
if (self)
{
#if PLATFORM(DOM)
@@ -494,15 +416,14 @@ var CPImageViewImageKey = @"CPImageViewImageKey",
#endif
[self setHasShadow:[aCoder decodeBoolForKey:CPImageViewHasShadowKey]];
[self setImageAlignment:[aCoder decodeIntForKey:CPImageViewImageAlignmentKey]];
if ([aCoder decodeBoolForKey:CPImageViewIsEditableKey] || NO)
[self setEditable:YES];
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
return self;
}
@@ -513,23 +434,22 @@ var CPImageViewImageKey = @"CPImageViewImageKey",
*/
- (void)encodeWithCoder:(CPCoder)aCoder
{
// We do this in order to avoid encoding the _shadowView, which
// We do this in order to avoid encoding the _shadowView, which
// should just automatically be created programmatically as needed.
if (_shadowView)
{
var actualSubviews = _subviews;
_subviews = [_subviews copy];
[_subviews removeObjectIdenticalTo:_shadowView];
}
[super encodeWithCoder:aCoder];
if (_shadowView)
_subviews = actualSubviews;
[aCoder encodeBool:_hasShadow forKey:CPImageViewHasShadowKey];
[aCoder encodeInt:_imageAlignment forKey:CPImageViewImageAlignmentKey];
if (_isEditable)
[aCoder encodeBool:_isEditable forKey:CPImageViewIsEditableKey];
-263
View File
@@ -1,263 +0,0 @@
/*
* CPKeyBinding.j
* AppKit
*
* Created by Nicholas Small.
* Copyright 2010, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPObject.j>
@import "CPEvent.j"
CPStandardKeyBindings = {
@"@.": @"cancelOperation:",
@"^a": @"moveToBeginningOfParagraph:",
@"^$a": @"moveToBeginningOfParagraphAndModifySelection:",
@"^b": @"moveBackward:",
@"^$b": @"moveBackwardAndModifySelection:",
@"^~b": @"moveWordBackward:",
@"^~$b": @"moveWordBackwardAndModifySelection:",
@"^d": @"deleteForward:",
@"^e": @"moveToEndOfParagraph:",
@"^$e": @"moveToEndOfParagraphAndModifySelection:",
@"^f": @"moveForward:",
@"^$f": @"moveForwardAndModifySelection:",
@"^~f": @"moveWordForward:",
@"^~$f": @"moveWordForwardAndModifySelection:",
@"^h": @"deleteBackward:",
@"^k": @"deleteToEndOfParagraph:",
@"^l": @"centerSelectionInVisibleArea:",
@"^n": @"moveDown:",
@"^$n": @"moveDownAndModifySelection:",
@"^o": [@"insertNewlineIgnoringFieldEditor:", @"moveBackward:"],
@"^p": @"moveUp:",
@"^$p": @"moveUpAndModifySelection:",
@"^t": @"transpose:",
@"^v": @"pageDown:",
@"^$v": @"pageDownAndModifySelection:",
@"^y": @"yank:"
};
CPStandardKeyBindings[CPNewlineCharacter] = @"insertNewline:";
CPStandardKeyBindings[CPCarriageReturnCharacter] = @"insertNewline:";
CPStandardKeyBindings[CPEnterCharacter] = @"insertNewline:";
CPStandardKeyBindings[@"~" + CPNewlineCharacter] = @"insertNewlineIgnoringFieldEditor:";
CPStandardKeyBindings[@"~" + CPCarriageReturnCharacter] = @"insertNewlineIgnoringFieldEditor:";
CPStandardKeyBindings[@"~" + CPEnterCharacter] = @"insertNewlineIgnoringFieldEditor:";
CPStandardKeyBindings[@"^" + CPNewlineCharacter] = @"insertLineBreak:";
CPStandardKeyBindings[@"^" + CPCarriageReturnCharacter] = @"insertLineBreak:";
CPStandardKeyBindings[@"^" + CPEnterCharacter] = @"insertLineBreak:";
CPStandardKeyBindings[CPBackspaceCharacter] = @"deleteBackward:";
CPStandardKeyBindings[@"~" + CPBackspaceCharacter] = @"deleteWordBackward:";
CPStandardKeyBindings[CPDeleteCharacter] = @"deleteBackward:";
CPStandardKeyBindings[@"@" + CPDeleteCharacter] = @"deleteToBeginningOfLine:";
CPStandardKeyBindings[@"~" + CPDeleteCharacter] = @"deleteWordBackward:";
CPStandardKeyBindings[@"^" + CPDeleteCharacter] = @"deleteBackwardByDecomposingPreviousCharacter:";
CPStandardKeyBindings[@"^~" + CPDeleteCharacter] = @"deleteWordBackward:";
CPStandardKeyBindings[CPDeleteFunctionKey] = @"deleteForward:";
CPStandardKeyBindings[@"~" + CPDeleteFunctionKey] = @"deleteWordForward:";
CPStandardKeyBindings[CPTabCharacter] = @"insertTab:";
CPStandardKeyBindings[@"~" + CPTabCharacter] = @"insertTabIgnoringFieldEditor:";
CPStandardKeyBindings[@"^" + CPTabCharacter] = @"selectNextKeyView:";
CPStandardKeyBindings[CPBackTabCharacter] = @"insertBacktab:";
CPStandardKeyBindings[@"^" + CPBackTabCharacter] = @"selectPreviousKeyView:";
CPStandardKeyBindings[CPEscapeFunctionKey] = @"cancelOperation:";
CPStandardKeyBindings[@"~" + CPEscapeFunctionKey] = @"complete:";
CPStandardKeyBindings[CPF5FunctionKey] = @"complete:";
CPStandardKeyBindings[CPLeftArrowFunctionKey] = @"moveLeft:";
CPStandardKeyBindings[@"~" + CPLeftArrowFunctionKey] = @"moveWordLeft:";
CPStandardKeyBindings[@"^" + CPLeftArrowFunctionKey] = @"moveToLeftEndOfLine:";
CPStandardKeyBindings[@"@" + CPLeftArrowFunctionKey] = @"moveToLeftEndOfLine:";
CPStandardKeyBindings[@"$" + CPLeftArrowFunctionKey] = @"moveLeftAndModifySelection:";
CPStandardKeyBindings[@"$~" + CPLeftArrowFunctionKey] = @"moveWordLeftAndModifySelection:";
CPStandardKeyBindings[@"$^" + CPLeftArrowFunctionKey] = @"moveToLeftEndOfLineAndModifySelection:";
CPStandardKeyBindings[@"$@" + CPLeftArrowFunctionKey] = @"moveToLeftEndOfLineAndModifySelection:";
CPStandardKeyBindings[@"@^" + CPLeftArrowFunctionKey] = @"makeBaseWritingDirectionRightToLeft:";
CPStandardKeyBindings[@"@^~" + CPLeftArrowFunctionKey] = @"makeTextWritingDirectionRightToLeft:";
CPStandardKeyBindings[CPRightArrowFunctionKey] = @"moveRight:";
CPStandardKeyBindings[@"~" + CPRightArrowFunctionKey] = @"moveWordRight:";
CPStandardKeyBindings[@"^" + CPRightArrowFunctionKey] = @"moveToRightEndOfLine:";
CPStandardKeyBindings[@"@" + CPRightArrowFunctionKey] = @"moveToRightEndOfLine:";
CPStandardKeyBindings[@"$" + CPRightArrowFunctionKey] = @"moveRightAndModifySelection:";
CPStandardKeyBindings[@"$~" + CPRightArrowFunctionKey] = @"moveWordRightAndModifySelection:";
CPStandardKeyBindings[@"$^" + CPRightArrowFunctionKey] = @"moveToRightEndOfLineAndModifySelection:";
CPStandardKeyBindings[@"$@" + CPRightArrowFunctionKey] = @"moveToRightEndOfLineAndModifySelection:";
CPStandardKeyBindings[@"@^" + CPRightArrowFunctionKey] = @"makeBaseWritingDirectionLeftToRight:";
CPStandardKeyBindings[@"@^~" + CPRightArrowFunctionKey] = @"makeTextWritingDirectionLeftToRight:";
CPStandardKeyBindings[CPUpArrowFunctionKey] = @"moveUp:";
CPStandardKeyBindings[@"~" + CPUpArrowFunctionKey] = [@"moveBackward:", @"moveToBeginningOfParagraph:"];
CPStandardKeyBindings[@"^" + CPUpArrowFunctionKey] = @"scrollPageUp:";
CPStandardKeyBindings[@"@" + CPUpArrowFunctionKey] = @"moveToBeginningOfDocument:";
CPStandardKeyBindings[@"$" + CPUpArrowFunctionKey] = @"moveUpAndModifySelection:";
CPStandardKeyBindings[@"$~" + CPUpArrowFunctionKey] = @"moveParagraphBackwardAndModifySelection:";
CPStandardKeyBindings[@"$@" + CPUpArrowFunctionKey] = @"moveToBeginningOfDocumentAndModifySelection:";
CPStandardKeyBindings[CPDownArrowFunctionKey] = @"moveDown:";
CPStandardKeyBindings[@"~" + CPDownArrowFunctionKey] = [@"moveForward:", @"moveToEndOfParagraph:"];
CPStandardKeyBindings[@"^" + CPDownArrowFunctionKey] = @"scrollPageDown:";
CPStandardKeyBindings[@"@" + CPDownArrowFunctionKey] = @"moveToEndOfDocument:";
CPStandardKeyBindings[@"$" + CPDownArrowFunctionKey] = @"moveDownAndModifySelection:";
CPStandardKeyBindings[@"$~" + CPDownArrowFunctionKey] = @"moveParagraphForwardAndModifySelection:";
CPStandardKeyBindings[@"$@" + CPDownArrowFunctionKey] = @"moveToEndOfDocumentAndModifySelection:";
CPStandardKeyBindings[@"@^" + CPDownArrowFunctionKey] = @"makeBaseWritingDirectionNatural:";
CPStandardKeyBindings[@"@^~" + CPDownArrowFunctionKey] = @"makeTextWritingDirectionNatural:";
CPStandardKeyBindings[CPHomeFunctionKey] = @"scrollToBeginningOfDocument:";
CPStandardKeyBindings[@"$" + CPHomeFunctionKey] = @"moveToBeginningOfDocumentAndModifySelection:";
CPStandardKeyBindings[CPEndFunctionKey] = @"scrollToEndOfDocument:";
CPStandardKeyBindings[@"$" + CPEndFunctionKey] = @"moveToEndOfDocumentAndModifySelection:";
CPStandardKeyBindings[CPPageUpFunctionKey] = @"scrollPageUp:";
CPStandardKeyBindings[@"~" + CPPageUpFunctionKey] = @"pageUp:";
CPStandardKeyBindings[@"$" + CPPageUpFunctionKey] = @"pageUpAndModifySelection:";
CPStandardKeyBindings[CPPageDownFunctionKey] = @"scrollPageDown:";
CPStandardKeyBindings[@"~" + CPPageDownFunctionKey] = @"pageDown:";
CPStandardKeyBindings[@"$" + CPPageDownFunctionKey] = @"pageDownAndModifySelection:";
var CPKeyBindingCache = {};
@implementation CPKeyBinding : CPObject
{
CPString _key;
unsigned _modifierFlags;
CPArray _selectors;
CPString _cacheName;
}
+ (void)initialize
{
if ([self class] !== CPKeyBinding)
return;
[self createKeyBindingsFromJSObject:CPStandardKeyBindings];
}
+ (void)createKeyBindingsFromJSObject:(JSObject)anObject
{
var binding;
for (binding in anObject)
[self cacheKeyBinding:[[CPKeyBinding alloc] initWithPhysicalKeyString:binding selectors:anObject[binding]]];
}
+ (void)cacheKeyBinding:(CPKeyBinding)aBinding
{
if (!aBinding)
return;
CPKeyBindingCache[[aBinding _cacheName]] = aBinding;
}
+ (CPKeyBinding)keyBindingForKey:(CPString)aKey modifierFlags:(unsigned)aFlag
{
var tempBinding = [[self alloc] initWithKey:aKey modifierFlags:aFlag selectors:nil];
return CPKeyBindingCache[[tempBinding _cacheName]];
}
+ (CPArray)selectorsForKey:(CPString)aKey modifierFlags:(unsigned)aFlag
{
return [[self keyBindingForKey:aKey modifierFlags:aFlag] selectors];
}
- (id)initWithPhysicalKeyString:(CPString)binding selectors:(CPArray)selectors
{
var components = binding.split(@""),
modifierFlags = ([components containsObject:@"$"] ? CPShiftKeyMask : 0) |
([components containsObject:@"^"] ? CPControlKeyMask : 0) |
([components containsObject:@"~"] ? CPAlternateKeyMask : 0) |
([components containsObject:@"@"] ? CPCommandKeyMask : 0);
if (![selectors isKindOfClass:CPArray])
selectors = [selectors];
return [self initWithKey:[components lastObject] modifierFlags:modifierFlags selectors:selectors];
}
- (id)initWithKey:(CPString)aKey modifierFlags:(unsigned)aFlag selectors:(CPArray)selectors
{
self = [super init];
if (self)
{
_key = aKey;
_modifierFlags = aFlag;
_selectors = selectors;
// We normalize our key binding string in order to properly cache it.
// We want to ensure the modifiers are always in the same order.
var cacheName = [];
if (_modifierFlags & CPCommandKeyMask)
cacheName.push(@"@");
if (_modifierFlags & CPControlKeyMask)
cacheName.push(@"^");
if (_modifierFlags & CPAlternateKeyMask)
cacheName.push(@"~");
if (_modifierFlags & CPShiftKeyMask)
cacheName.push(@"$");
cacheName.push(_key);
_cacheName = cacheName.join(@"");
}
return self;
}
- (CPString)key
{
return _key;
}
- (unsigned)modifierFlags
{
return _modifierFlags;
}
- (CPArray)selectors
{
return _selectors;
}
- (CPString)_cacheName
{
return _cacheName;
}
- (BOOL)isEqual:(CPKeyBinding)rhs
{
return _key === [rhs key] && _modifierFlags === [rhs modifierFlags];
}
- (CPString)description
{
return [CPString stringWithFormat:@"<KeyBinding string: '%@' modifierFlags: 0x%lx selectors: %@>", _key, _modifierFlags, _selectors];
}
@end
-477
View File
@@ -1,477 +0,0 @@
/*
* CPKeyValueBinding.j
* AppKit
*
* Created by Ross Boucher 1/13/09
* Copyright 280 North, Inc.
*
* Adapted from GNUStep
* Released under the LGPL.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPObject.j>
@import <Foundation/CPArray.j>
@import <Foundation/CPDictionary.j>
@import <Foundation/CPValueTransformer.j>
var exposedBindingsMap = [CPDictionary new],
bindingsMap = [CPDictionary new];
var CPBindingOperationAnd = 0,
CPBindingOperationOr = 1;
@implementation CPBinder : CPObject
{
CPDictionary _info;
id _source;
}
+ (void)exposeBinding:(CPString)aBinding forClass:(Class)aClass
{
var bindings = [exposedBindingsMap objectForKey:[aClass UID]];
if (!bindings)
{
bindings = [];
[exposedBindingsMap setObject:bindings forKey:[aClass UID]];
}
bindings.push(aBinding);
}
+ (CPArray)exposedBindingsForClass:(Class)aClass
{
return [[exposedBindingsMap objectForKey:[aClass UID]] copy];
}
+ (CPBinder)getBinding:(CPString)aBinding forObject:(id)anObject
{
return [[bindingsMap objectForKey:[anObject UID]] objectForKey:aBinding];
}
+ (CPDictionary)infoForBinding:(CPString)aBinding forObject:(id)anObject
{
var theBinding = [self getBinding:aBinding forObject:anObject];
if (theBinding)
return theBinding._info;
return nil;
}
+ (CPDictionary)allBindingsForObject:(id)anObject
{
return [bindingsMap objectForKey:[anObject UID]];
}
+ (void)unbind:(CPString)aBinding forObject:(id)anObject
{
var bindings = [bindingsMap objectForKey:[anObject UID]];
if (!bindings)
return;
var theBinding = [bindings objectForKey:aBinding];
if (!theBinding)
return;
var infoDictionary = theBinding._info,
observedObject = [infoDictionary objectForKey:CPObservedObjectKey],
keyPath = [infoDictionary objectForKey:CPObservedKeyPathKey];
[observedObject removeObserver:theBinding forKeyPath:keyPath];
[bindings removeObjectForKey:aBinding];
}
+ (void)unbindAllForObject:(id)anObject
{
var bindings = [bindingsMap objectForKey:[anObject UID]];
if (!bindings)
return;
var allKeys = [bindings allKeys],
count = allKeys.length;
while (count--)
[anObject unbind:[bindings objectForKey:allKeys[count]]];
[bindingsMap removeObjectForKey:[anObject UID]];
}
- (id)initWithBinding:(CPString)aBinding name:(CPString)aName to:(id)aDestination keyPath:(CPString)aKeyPath options:(CPDictionary)options from:(id)aSource
{
self = [super init];
if (self)
{
_source = aSource;
_info = [CPDictionary dictionaryWithObjects:[aDestination, aKeyPath] forKeys:[CPObservedObjectKey, CPObservedKeyPathKey]];
if (options)
[_info setObject:options forKey:CPOptionsKey];
[aDestination addObserver:self forKeyPath:aKeyPath options:CPKeyValueObservingOptionNew context:aBinding];
var bindings = [bindingsMap objectForKey:[_source UID]];
if (!bindings)
{
bindings = [CPDictionary new];
[bindingsMap setObject:bindings forKey:[_source UID]];
}
[bindings setObject:self forKey:aName];
[self setValueFor:aBinding];
}
return self;
}
- (void)setValueFor:(CPString)aBinding
{
var destination = [_info objectForKey:CPObservedObjectKey],
keyPath = [_info objectForKey:CPObservedKeyPathKey],
options = [_info objectForKey:CPOptionsKey],
newValue = [destination valueForKeyPath:keyPath];
newValue = [self transformValue:newValue withOptions:options];
[_source setValue:newValue forKey:aBinding];
}
- (void)reverseSetValueFor:(CPString)aBinding
{
var destination = [_info objectForKey:CPObservedObjectKey],
keyPath = [_info objectForKey:CPObservedKeyPathKey],
options = [_info objectForKey:CPOptionsKey],
newValue = [_source valueForKeyPath:aBinding];
newValue = [self reverseTransformValue:newValue withOptions:options];
[destination setValue:newValue forKeyPath:keyPath];
}
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)changes context:(id)context
{
if (!changes)
return;
[self setValueFor:context];
}
- (id)transformValue:(id)aValue withOptions:(CPDictionary)options
{
var valueTransformerName = [options objectForKey:CPValueTransformerNameBindingOption],
valueTransformer;
if (valueTransformerName)
{
valueTransformer = [CPValueTransformer valueTransformerForName:valueTransformerName];
if (!valueTransformer)
{
var valueTransformerClass = CPClassFromString(valueTransformerName);
if (valueTransformerClass)
{
valueTransformer = [[valueTransformerClass alloc] init];
[valueTransformerClass setValueTransformer:valueTransformer forName:valueTransformerName];
}
}
}
else
valueTransformer = [options objectForKey:CPValueTransformerBindingOption];
if (valueTransformer)
aValue = [valueTransformer transformedValue:aValue];
if (aValue === undefined || aValue === nil || aValue === [CPNull null])
aValue = [options objectForKey:CPNullPlaceholderBindingOption] || nil;
return aValue;
}
- (id)reverseTransformValue:(id)aValue withOptions: (CPDictionary)options
{
var valueTransformerName = [options objectForKey:CPValueTransformerNameBindingOption],
valueTransformer;
if (valueTransformerName)
valueTransformer = [CPValueTransformer valueTransformerForName:valueTransformerName];
else
valueTransformer = [options objectForKey:CPValueTransformerBindingOption];
if (valueTransformer && [[valueTransformer class] allowsReverseTransformation])
aValue = [valueTransformer reverseTransformedValue:aValue];
return aValue;
}
- (BOOL)continuouslyUpdatesValue
{
var options = [_info objectForKey:CPOptionsKey];
return [[options objectForKey:CPContinuouslyUpdatesValueBindingOption] boolValue];
}
@end
@implementation CPObject (KeyValueBindingCreation)
+ (void)exposeBinding:(CPString)aBinding
{
[CPBinder exposeBinding:aBinding forClass:[self class]];
}
+ (Class)_binderClassForBinding:(CPString)theBinding
{
return [CPBinder class];
}
- (CPArray)exposedBindings
{
var exposedBindings = [],
theClass = [self class];
while (theClass)
{
var temp = [CPBinder exposedBindingsForClass:theClass];
if (temp)
[exposedBindings addObjectsFromArray:temp];
theClass = [theClass superclass];
}
return exposedBindings;
}
- (Class)valueClassForBinding:(CPString)binding
{
return [CPString class];
}
- (void)bind:(CPString)aBinding toObject:(id)anObject withKeyPath:(CPString)aKeyPath options:(CPDictionary)options
{
if (!anObject || !aKeyPath)
return CPLog.error("Invalid object or path on "+self+" for "+aBinding);
//if (![[self exposedBindings] containsObject:aBinding])
// CPLog.warn("No binding exposed on "+self+" for "+aBinding);
var binderClass = [[self class] _binderClassForBinding:aBinding];
[self unbind:aBinding];
[[binderClass alloc] initWithBinding:[self _replacementKeyPathForBinding:aBinding] name:aBinding to:anObject keyPath:aKeyPath options:options from:self];
}
- (CPDictionary)infoForBinding:(CPString)aBinding
{
return [CPBinder infoForBinding:aBinding forObject:self];
}
- (void)unbind:(CPString)aBinding
{
var binderClass = [[self class] _binderClassForBinding:aBinding];
[binderClass unbind:aBinding forObject:self];
}
- (id)_replacementKeyPathForBinding:(CPString)binding
{
return binding;
}
@end
/*!
@ignore
Provides stub implementations that simply call super for the "objectValue" binding
This class should not be necessary but assures backwards compliance with our old way of doing bindings
Every class with a value binding should implement a subclass to handle it's specific value binding logic
*/
@implementation _CPValueBinder : CPBinder
{
}
- (void)setValueFor:(CPString)theBinding
{
[super setValueFor:@"objectValue"];
}
- (void)reverseSetValueFor:(CPString)theBinding
{
[super reverseSetValueFor:@"objectValue"];
}
@end
@implementation _CPKeyValueOrBinding : CPBinder
{
}
- (void)setValueFor:(CPString)aBinding
{
var bindings = [bindingsMap valueForKey:[_source UID]];
if (!bindings)
return;
[_source setValue:resolveMultipleValues(aBinding, bindings, CPBindingOperationOr) forKey:aBinding];
}
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)changes context:(id)context
{
[self setValueFor:context];
}
@end
@implementation _CPKeyValueAndBinding : CPBinder
{
}
- (void)setValueFor:(CPString)aBinding
{
var bindings = [bindingsMap objectForKey:[_source UID]];
if (!bindings)
return;
[_source setValue:resolveMultipleValues(aBinding, bindings, CPBindingOperationAnd) forKey:aBinding];
}
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObejct change:(CPDictionary)changes context:(id)context
{
[self setValueFor:context];
}
@end
var resolveMultipleValues = function resolveMultipleValues(/*CPString*/key, /*CPDictionary*/bindings, /*GSBindingOperationKind*/operation)
{
var bindingName = key,
theBinding,
count = 1;
while (theBinding = [bindings objectForKey:bindingName])
{
var infoDictionary = theBinding._info,
object = [infoDictionary objectForKey:CPObservedObjectKey],
keyPath = [infoDictionary objectForKey:CPObservedKeyPathKey],
options = [infoDictionary objectForKey:CPOptionsKey];
var value = [theBinding transformValue:[object valueForKeyPath:keyPath] withOptions:options];
if (value == operation)
return operation;
bindingName = [CPString stringWithFormat:@"%@%i", key, ++count];
}
return !operation;
}
var invokeAction = function invokeAction(/*CPString*/targetKey, /*CPString*/argumentKey, /*CPDictionary*/bindings)
{
var theBinding = [bindings objectForKey:targetKey],
infoDictionary = theBinding._info,
object = [infoDictionary objectForKey:CPObservedObjectKey],
keyPath = [infoDictionary objectForKey:CPObservedKeyPathKey],
options = [infoDictionary objectForKey:CPOptionsKey],
target = [object valueForKeyPath:keyPath],
selector = [options objectForKey:CPSelectorNameBindingOption];
if (!target || !selector)
return;
var invocation = [CPInvocation invocationWithMethodSignature:[target methodSignatureForSelector:selector]];
[invocation setSelector:selector];
var bindingName = argumentKey,
count = 1;
while (theBinding = [bindings objectForKey:bindingName])
{
infoDictionary = theBinding._info;
keyPath = [infoDictionary objectForKey:CPObserverKeyPathKey];
object = [[infoDictionary objectForKey:CPObservedObjectKey] valueForKeyPath:keyPath];
if (object)
[invocation setArgument:object atIndex:++count];
bindingName = [CPString stringWithFormat:@"%@%i", argumentKey, count];
}
[invocation invoke];
}
// Keys in options dictionary
// Keys in dictionary returned by infoForBinding
CPObservedObjectKey = @"CPObservedObjectKey";
CPObservedKeyPathKey = @"CPObservedKeyPathKey";
CPOptionsKey = @"CPOptionsKey";
// special markers
CPMultipleValuesMarker = @"CPMultipleValuesMarker";
CPNoSelectionMarker = @"CPNoSelectionMarker";
CPNotApplicableMarker = @"CPNotApplicableMarker";
CPNullMarker = @"CPNullMarker";
// Binding name constants
CPAlignmentBinding = @"alignment";
CPEditableBinding = @"editable";
CPEnabledBinding = @"enabled";
CPFontBinding = @"font";
CPHiddenBinding = @"hidden";
CPSelectedIndexBinding = @"selectedIndex";
CPTextColorBinding = @"textColor";
CPToolTipBinding = @"toolTip";
CPValueBinding = @"value";
//Binding options constants
CPAllowsEditingMultipleValuesSelectionBindingOption = @"CPAllowsEditingMultipleValuesSelection";
CPAllowsNullArgumentBindingOption = @"CPAllowsNullArgument";
CPConditionallySetsEditableBindingOption = @"CPConditionallySetsEditable";
CPConditionallySetsEnabledBindingOption = @"CPConditionallySetsEnabled";
CPConditionallySetsHiddenBindingOption = @"CPConditionallySetsHidden";
CPContinuouslyUpdatesValueBindingOption = @"CPContinuouslyUpdatesValue";
CPCreatesSortDescriptorBindingOption = @"CPCreatesSortDescriptor";
CPDeletesObjectsOnRemoveBindingsOption = @"CPDeletesObjectsOnRemove";
CPDisplayNameBindingOption = @"CPDisplayName";
CPDisplayPatternBindingOption = @"CPDisplayPattern";
CPHandlesContentAsCompoundValueBindingOption = @"CPHandlesContentAsCompoundValue";
CPInsertsNullPlaceholderBindingOption = @"CPInsertsNullPlaceholder";
CPInvokesSeparatelyWithArrayObjectsBindingOption = @"CPInvokesSeparatelyWithArrayObjects";
CPMultipleValuesPlaceholderBindingOption = @"CPMultipleValuesPlaceholder";
CPNoSelectionPlaceholderBindingOption = @"CPNoSelectionPlaceholder";
CPNotApplicablePlaceholderBindingOption = @"CPNotApplicablePlaceholder";
CPNullPlaceholderBindingOption = @"CPNullPlaceholder";
CPPredicateFormatBindingOption = @"CPPredicateFormat";
CPRaisesForNotApplicableKeysBindingOption = @"CPRaisesForNotApplicableKeys";
CPSelectorNameBindingOption = @"CPSelectorName";
CPSelectsAllWhenSettingContentBindingOption = @"CPSelectsAllWhenSettingContent";
CPValidatesImmediatelyBindingOption = @"CPValidatesImmediately";
CPValueTransformerNameBindingOption = @"CPValueTransformerName";
CPValueTransformerBindingOption = @"CPValueTransformer";
CPIsControllerMarker = function(/*id*/anObject)
{
return anObject === CPMultipleValuesMarker || anObject === CPNoSelectionMarker || anObject === CPNotApplicableMarker || anObject === CPNullMarker;
}
-403
View File
@@ -1,403 +0,0 @@
/*
* CPLevelIndicator.j
* AppKit
*
* Created by Alexander Ljungberg.
* Copyright 2011, WireLoad 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 "CPControl.j"
CPTickMarkBelow = 0;
CPTickMarkAbove = 1;
CPTickMarkLeft = CPTickMarkAbove;
CPTickMarkRight = CPTickMarkBelow;
CPRelevancyLevelIndicatorStyle = 0;
CPContinuousCapacityLevelIndicatorStyle = 1;
CPDiscreteCapacityLevelIndicatorStyle = 2;
CPRatingLevelIndicatorStyle = 3;
var _CPLevelIndicatorBezelColor = nil,
_CPLevelIndicatorSegmentEmptyColor = nil,
_CPLevelIndicatorSegmentNormalColor = nil,
_CPLevelIndicatorSegmentWarningColor = nil,
_CPLevelIndicatorSegmentCriticalColor = nil,
_CPLevelIndicatorSpacing = 1;
/*!
@ingroup appkit
@class CPLevelIndicator
CPLevelIndicator is a control which indicates a value visually on a scale.
*/
@implementation CPLevelIndicator : CPControl
{
CPLevelIndicator _levelIndicatorStyle @accessors(property=levelIndicatorStyle);
double _minValue @accessors(property=minValue);
double _maxValue @accessors(property=maxValue);
double _warningValue @accessors(property=warningValue);
double _criticalValue @accessors(property=criticalValue);
CPTickMarkPosition _tickMarkPosition @accessors(property=tickMarkPosition);
int _numberOfTickMarks @accessors(property=numberOfTickMarks);
int _numberOfMajorTickMarks @accessors(property=numberOfMajorTickMarks);
BOOL _isEditable;
BOOL _isTracking;
}
+ (void)initialize
{
var bundle = [CPBundle bundleForClass:CPLevelIndicator];
_CPLevelIndicatorBezelColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-bezel-left.png"] size:CGSizeMake(3.0, 18.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-bezel-center.png"] size:CGSizeMake(1.0, 18.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-bezel-right.png"] size:CGSizeMake(3.0, 18.0)]
]
isVertical:NO
]];
_CPLevelIndicatorSegmentEmptyColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-empty-left.png"] size:CGSizeMake(3.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-empty-center.png"] size:CGSizeMake(1.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-empty-right.png"] size:CGSizeMake(3.0, 17.0)]
]
isVertical:NO
]];
_CPLevelIndicatorSegmentNormalColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-normal-left.png"] size:CGSizeMake(3.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-normal-center.png"] size:CGSizeMake(1.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-normal-right.png"] size:CGSizeMake(3.0, 17.0)]
]
isVertical:NO
]];
_CPLevelIndicatorSegmentWarningColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-warning-left.png"] size:CGSizeMake(3.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-warning-center.png"] size:CGSizeMake(1.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-warning-right.png"] size:CGSizeMake(3.0, 17.0)]
]
isVertical:NO
]];
_CPLevelIndicatorSegmentCriticalColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-critical-left.png"] size:CGSizeMake(3.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-critical-center.png"] size:CGSizeMake(1.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-critical-right.png"] size:CGSizeMake(3.0, 17.0)]
]
isVertical:NO
]];
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
_levelIndicatorStyle = CPDiscreteCapacityLevelIndicatorStyle;
_maxValue = 2;
_warningValue = 2;
_criticalValue = 2;
[self _init];
}
return self;
}
- (void)_init
{
}
- (void)layoutSubviews
{
var bezelView = [self layoutEphemeralSubviewNamed:"bezel"
positioned:CPWindowBelow
relativeToEphemeralSubviewNamed:nil];
// TODO Make themable.
[bezelView setBackgroundColor:_CPLevelIndicatorBezelColor];
var segmentCount = _maxValue - _minValue;
if (segmentCount <= 0)
return;
var filledColor = _CPLevelIndicatorSegmentNormalColor,
value = [self doubleValue];
if (value < _criticalValue)
filledColor = _CPLevelIndicatorSegmentCriticalColor;
else if (value < _warningValue)
filledColor = _CPLevelIndicatorSegmentWarningColor;
for (var i = 0; i < segmentCount; i++)
{
var segmentView = [self layoutEphemeralSubviewNamed:"segment-bezel-" + i
positioned:CPWindowAbove
relativeToEphemeralSubviewNamed:bezelView];
[segmentView setBackgroundColor:(_minValue + i) < value ? filledColor : _CPLevelIndicatorSegmentEmptyColor];
}
}
- (CPView)createEphemeralSubviewNamed:(CPString)aName
{
return [[CPView alloc] initWithFrame:_CGRectMakeZero()];
}
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aViewName
{
// TODO Put into theme attributes.
var bezelHeight = 18,
segmentHeight = 17,
bounds = _CGRectCreateCopy([self bounds]);
if (aViewName == "bezel")
{
bounds.origin.y = (_CGRectGetHeight(bounds) - bezelHeight) / 2.0;
bounds.size.height = bezelHeight;
return bounds;
}
else if (aViewName.indexOf("segment-bezel") === 0)
{
var segment = parseInt(aViewName.substring("segment-bezel-".length), 10),
segmentCount = _maxValue - _minValue;
if (segment >= segmentCount)
return _CGRectMakeZero();
var basicSegmentWidth = bounds.size.width / segmentCount,
segmentFrame = CGRectCreateCopy([self bounds]);
segmentFrame.origin.y = (_CGRectGetHeight(bounds) - bezelHeight) / 2.0;
segmentFrame.origin.x = FLOOR(segment * basicSegmentWidth);
segmentFrame.size.width = (segment == segmentCount - 1) ? bounds.size.width - segmentFrame.origin.x : FLOOR(((segment + 1) * basicSegmentWidth)) - FLOOR((segment * basicSegmentWidth)) - _CPLevelIndicatorSpacing;
segmentFrame.size.height = segmentHeight;
return segmentFrame;
}
return _CGRectMakeZero();
}
/*!
Sets whether or not the receiver level indicator can be edited.
*/
- (void)setEditable:(BOOL)shouldBeEditable
{
if (_isEditable === shouldBeEditable)
return;
_isEditable = shouldBeEditable;
}
/*!
Returns \c YES if the textfield is currently editable by the user.
*/
- (BOOL)isEditable
{
return _isEditable;
}
- (void)mouseDown:(CPEvent)anEvent
{
if (![self isEditable] || ![self isEnabled])
return;
[self _trackMouse:anEvent];
}
- (void)_trackMouse:(CPEvent)anEvent
{
var type = [anEvent type];
if (type == CPLeftMouseDown || type == CPLeftMouseDragged)
{
var segmentCount = _maxValue - _minValue;
if (segmentCount <= 0)
return;
var location = [self convertPoint:[anEvent locationInWindow] fromView:nil],
bounds = [self bounds],
oldValue = [self doubleValue];
newValue = oldValue;
// Moving the mouse outside of the widget to the left sets it
// to its minimum, and moving outside on the right sets it to
// its maximum.
if (type == CPLeftMouseDragged && location.x < 0)
{
newValue = _minValue;
}
else if (type == CPLeftMouseDragged && location.x > bounds.size.width)
{
newValue = _maxValue;
}
else
{
for (var i = 0; i < segmentCount; i++)
{
var rect = [self rectForEphemeralSubviewNamed:"segment-bezel-" + i];
// Once we're tracking the mouse, we only care about horizontal mouse movement.
if (location.x >= CGRectGetMinX(rect) && location.x < CGRectGetMaxX(rect))
{
newValue = (_minValue + i + 1);
break;
}
}
}
if (newValue != oldValue)
[self setDoubleValue:newValue];
// Track the mouse to support click and slide value editing.
_isTracking = YES;
[CPApp setTarget:self selector:@selector(_trackMouse:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
if ([self isContinuous])
[self sendAction:[self action] to:[self target]];
}
else if (_isTracking)
{
_isTracking = NO;
[self sendAction:[self action] to:[self target]];
}
}
/*
- (CPLevelIndicatorStyle)style;
- (void)setLevelIndicatorStyle:(CPLevelIndicatorStyle)style;
*/
- (void)setMinValue:(double)minValue
{
if (_minValue === minValue)
return;
_minValue = minValue;
[self setNeedsLayout];
}
- (void)setMaxValue:(double)maxValue
{
if (_maxValue === maxValue)
return;
_maxValue = maxValue;
[self setNeedsLayout];
}
- (void)setWarningValue:(double)warningValue;
{
if (_warningValue === warningValue)
return;
_warningValue = warningValue;
[self setNeedsLayout];
}
- (void)setCriticalValue:(double)criticalValue;
{
if (_criticalValue === criticalValue)
return;
_criticalValue = criticalValue;
[self setNeedsLayout];
}
/*
- (CPTickMarkPosition)tickMarkPosition;
- (void)setTickMarkPosition:(CPTickMarkPosition)position;
- (int)numberOfTickMarks;
- (void)setNumberOfTickMarks:(int)count;
- (int)numberOfMajorTickMarks;
- (void)setNumberOfMajorTickMarks:(int)count;
- (double)tickMarkValueAtIndex:(int)index;
- (CGRect)rectOfTickMarkAtIndex:(int)index;
*/
@end
var CPLevelIndicatorStyleKey = "CPLevelIndicatorStyleKey",
CPLevelIndicatorMinValueKey = "CPLevelIndicatorMinValueKey",
CPLevelIndicatorMaxValueKey = "CPLevelIndicatorMaxValueKey",
CPLevelIndicatorWarningValueKey = "CPLevelIndicatorWarningValueKey",
CPLevelIndicatorCriticalValueKey = "CPLevelIndicatorCriticalValueKey",
CPLevelIndicatorTickMarkPositionKey = "CPLevelIndicatorTickMarkPositionKey",
CPLevelIndicatorNumberOfTickMarksKey = "CPLevelIndicatorNumberOfTickMarksKey",
CPLevelIndicatorNumberOfMajorTickMarksKey = "CPLevelIndicatorNumberOfMajorTickMarksKey",
CPLevelIndicatorIsEditableKey = "CPLevelIndicatorIsEditableKey";
@implementation CPLevelIndicator (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
_levelIndicatorStyle = [aCoder decodeIntForKey:CPLevelIndicatorStyleKey];
_minValue = [aCoder decodeDoubleForKey:CPLevelIndicatorMinValueKey];
_maxValue = [aCoder decodeDoubleForKey:CPLevelIndicatorMaxValueKey];
_warningValue = [aCoder decodeDoubleForKey:CPLevelIndicatorWarningValueKey];
_criticalValue = [aCoder decodeDoubleForKey:CPLevelIndicatorCriticalValueKey];
_tickMarkPosition = [aCoder decodeIntForKey:CPLevelIndicatorTickMarkPositionKey];
_numberOfTickMarks = [aCoder decodeIntForKey:CPLevelIndicatorNumberOfTickMarksKey];
_numberOfMajorTickMarks = [aCoder decodeIntForKey:CPLevelIndicatorNumberOfMajorTickMarksKey];
_isEditable = [aCoder decodeBoolForKey:CPLevelIndicatorIsEditableKey];
[self _init];
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeInt:_levelIndicatorStyle forKey:CPLevelIndicatorStyleKey];
[aCoder encodeDouble:_minValue forKey:CPLevelIndicatorMinValueKey];
[aCoder encodeDouble:_maxValue forKey:CPLevelIndicatorMaxValueKey];
[aCoder encodeDouble:_warningValue forKey:CPLevelIndicatorWarningValueKey];
[aCoder encodeDouble:_criticalValue forKey:CPLevelIndicatorCriticalValueKey];
[aCoder encodeInt:_tickMarkPosition forKey:CPLevelIndicatorTickMarkPositionKey];
[aCoder encodeInt:_numberOfTickMarks forKey:CPLevelIndicatorNumberOfTickMarksKey];
[aCoder encodeInt:_numberOfMajorTickMarks forKey:CPLevelIndicatorNumberOfMajorTickMarksKey];
[aCoder encodeBool:_isEditable forKey:CPLevelIndicatorIsEditableKey];
}
@end
+104 -165
View File
@@ -31,6 +31,9 @@
@import "CPMenuItem.j"
@import "CPPanel.j"
#include "../CoreGraphics/CGGeometry.h"
#include "../Platform/Platform.h"
CPMenuDidAddItemNotification = @"CPMenuDidAddItemNotification";
CPMenuDidChangeItemNotification = @"CPMenuDidChangeItemNotification";
@@ -47,12 +50,12 @@ var _CPMenuBarVisible = NO,
_CPMenuBarAttributes = nil,
_CPMenuBarSharedWindow = nil;
/*!
/*!
@ingroup appkit
@class CPMenu
Menus provide the user with a list of actions and/or submenus. Submenus themselves are full fledged menus
and so a hierarchical structure appears.
Menus provide the user with a list of actions and/or submenus. Submenus themselves are full fledged menus
and so a heirarchical structure appears.
*/
@implementation CPMenu : CPObject
{
@@ -66,13 +69,13 @@ var _CPMenuBarVisible = NO,
float _minimumWidth;
CPMutableArray _items;
BOOL _autoenablesItems;
BOOL _showsStateColumn;
id _delegate;
int _highlightedIndex;
CPMenuItem _highlightedIndex;
_CPMenuWindow _menuWindow;
}
@@ -80,9 +83,6 @@ var _CPMenuBarVisible = NO,
+ (void)initialize
{
if (self !== CPMenu)
return;
[[self class] setMenuBarAttributes:[CPDictionary dictionary]];
}
@@ -95,7 +95,7 @@ var _CPMenuBarVisible = NO,
{
if (_CPMenuBarVisible === menuBarShouldBeVisible)
return;
_CPMenuBarVisible = menuBarShouldBeVisible;
if ([CPPlatform supportsNativeMainMenu])
@@ -105,13 +105,13 @@ var _CPMenuBarVisible = NO,
{
if (!_CPMenuBarSharedWindow)
_CPMenuBarSharedWindow = [[_CPMenuBarWindow alloc] init];
[_CPMenuBarSharedWindow setMenu:[CPApp mainMenu]];
[_CPMenuBarSharedWindow setTitle:_CPMenuBarTitle];
[_CPMenuBarSharedWindow setIconImage:_CPMenuBarIconImage];
[_CPMenuBarSharedWindow setIconImageAlphaValue:_CPMenuBarIconImageAlphaValue];
[_CPMenuBarSharedWindow setColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarBackgroundColor"]];
[_CPMenuBarSharedWindow setTextColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTextColor"]];
[_CPMenuBarSharedWindow setTitleColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarTitleColor"]];
@@ -120,12 +120,12 @@ var _CPMenuBarVisible = NO,
[_CPMenuBarSharedWindow setHighlightColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightColor"]];
[_CPMenuBarSharedWindow setHighlightTextColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightTextColor"]];
[_CPMenuBarSharedWindow setHighlightTextShadowColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarHighlightTextShadowColor"]];
[_CPMenuBarSharedWindow orderFront:self];
}
else
[_CPMenuBarSharedWindow orderOut:self];
// FIXME: There must be a better way to do this.
#if PLATFORM(DOM)
[[CPPlatformWindow primaryPlatformWindow] resizeEvent:nil];
@@ -159,9 +159,9 @@ var _CPMenuBarVisible = NO,
{
if (_CPMenuBarAttributes == attributes)
return;
_CPMenuBarAttributes = [attributes copy];
var textColor = [attributes objectForKey:@"CPMenuBarTextColor"],
titleColor = [attributes objectForKey:@"CPMenuBarTitleColor"],
textShadowColor = [attributes objectForKey:@"CPMenuBarTextShadowColor"],
@@ -169,40 +169,40 @@ var _CPMenuBarVisible = NO,
highlightColor = [attributes objectForKey:@"CPMenuBarHighlightColor"],
highlightTextColor = [attributes objectForKey:@"CPMenuBarHighlightTextColor"],
highlightTextShadowColor = [attributes objectForKey:@"CPMenuBarHighlightTextShadowColor"];
if (!textColor && titleColor)
[_CPMenuBarAttributes setObject:titleColor forKey:@"CPMenuBarTextColor"];
else if (textColor && !titleColor)
[_CPMenuBarAttributes setObject:textColor forKey:@"CPMenuBarTitleColor"];
else if (!textColor && !titleColor)
{
[_CPMenuBarAttributes setObject:[CPColor colorWithRed:0.051 green:0.2 blue:0.275 alpha:1.0] forKey:@"CPMenuBarTextColor"];
[_CPMenuBarAttributes setObject:[CPColor colorWithRed:0.051 green:0.2 blue:0.275 alpha:1.0] forKey:@"CPMenuBarTitleColor"];
}
if (!textShadowColor && titleShadowColor)
[_CPMenuBarAttributes setObject:titleShadowColor forKey:@"CPMenuBarTextShadowColor"];
else if (textShadowColor && !titleShadowColor)
[_CPMenuBarAttributes setObject:textShadowColor forKey:@"CPMenuBarTitleShadowColor"];
else if (!textShadowColor && !titleShadowColor)
{
[_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarTextShadowColor"];
[_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarTitleShadowColor"];
}
if (!highlightColor)
[_CPMenuBarAttributes setObject:[CPColor colorWithCalibratedRed:94.0 / 255.0 green:130.0 / 255.0 blue:186.0 / 255.0 alpha:1.0] forKey:@"CPMenuBarHighlightColor"];
[_CPMenuBarAttributes setObject:[CPColor colorWithCalibratedRed:94.0/255.0 green:130.0/255.0 blue:186.0/255.0 alpha:1.0] forKey:@"CPMenuBarHighlightColor"];
if (!highlightTextColor)
[_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarHighlightTextColor"];
if (!highlightTextShadowColor)
[_CPMenuBarAttributes setObject:[CPColor blackColor] forKey:@"CPMenuBarHighlightTextShadowColor"];
if (_CPMenuBarSharedWindow)
{
[_CPMenuBarSharedWindow setColor:[_CPMenuBarAttributes objectForKey:@"CPMenuBarBackgroundColor"]];
@@ -231,7 +231,7 @@ var _CPMenuBarVisible = NO,
{
if (self === [CPApp mainMenu])
return MENUBAR_HEIGHT;
return 0.0;
}
@@ -249,18 +249,18 @@ var _CPMenuBarVisible = NO,
- (id)initWithTitle:(CPString)aTitle
{
self = [super init];
if (self)
{
_title = aTitle;
_items = [];
_autoenablesItems = YES;
_showsStateColumn = YES;
[self setMinimumWidth:0];
}
return self;
}
@@ -277,7 +277,22 @@ var _CPMenuBarVisible = NO,
*/
- (void)insertItem:(CPMenuItem)aMenuItem atIndex:(unsigned)anIndex
{
[self insertObject:aMenuItem inItemsAtIndex:anIndex];
var menu = [aMenuItem menu];
if (menu)
if (menu !== self)
[CPException raise:CPInternalInconsistencyException reason:@"Attempted to insert item into menu that was already in another menu."];
else
return;
[aMenuItem setMenu:self];
[_items insertObject:aMenuItem atIndex:anIndex];
[[CPNotificationCenter defaultCenter]
postNotificationName:CPMenuDidAddItemNotification
object:self
userInfo:[CPDictionary dictionaryWithObject:anIndex forKey:@"CPMenuItemIndex"]];
}
/*!
@@ -291,7 +306,7 @@ var _CPMenuBarVisible = NO,
- (CPMenuItem)insertItemWithTitle:(CPString)aTitle action:(SEL)anAction keyEquivalent:(CPString)aKeyEquivalent atIndex:(unsigned)anIndex
{
var item = [[CPMenuItem alloc] initWithTitle:aTitle action:anAction keyEquivalent:aKeyEquivalent];
[self insertItem:item atIndex:anIndex];
return item;
@@ -334,26 +349,16 @@ var _CPMenuBarVisible = NO,
*/
- (void)removeItemAtIndex:(unsigned)anIndex
{
[self removeObjectFromItemsAtIndex:anIndex];
}
/*!
Removes all the menu items in the receiver.
This method is more efficient than removing menu items individually.
Unlike the other remove methods, this method does not post CPMenuDidChangeItemNotification notifications.
*/
- (void)removeAllItems
{
var count = [_items count];
// Remove the connection to this menu in case
// someone else has a reference to the menu item.
while (count--)
[_items[count] setMenu:nil];
_items = [CPMutableArray array];
_highlightedIndex = CPNotFound;
if (anIndex < 0 || anIndex >= _items.length)
return;
[_items[anIndex] setMenu:nil];
[_items removeObjectAtIndex:anIndex];
[[CPNotificationCenter defaultCenter]
postNotificationName:CPMenuDidRemoveItemNotification
object:self
userInfo:[CPDictionary dictionaryWithObject:anIndex forKey:@"CPMenuItemIndex"]];
}
/*!
@@ -362,11 +367,9 @@ var _CPMenuBarVisible = NO,
*/
- (void)itemChanged:(CPMenuItem)aMenuItem
{
if ([aMenuItem menu] !== self)
if ([aMenuItem menu] != self)
return;
[aMenuItem setValue:[aMenuItem valueForKey:@"changeCount"] + 1 forKey:@"changeCount"];
[[CPNotificationCenter defaultCenter]
postNotificationName:CPMenuDidChangeItemNotification
object:self
@@ -382,10 +385,10 @@ var _CPMenuBarVisible = NO,
- (CPMenuItem)itemWithTag:(int)aTag
{
var index = [self indexOfItemWithTag:aTag];
if (index == CPNotFound)
return nil;
return _items[index];
}
@@ -397,10 +400,10 @@ var _CPMenuBarVisible = NO,
- (CPMenuItem)itemWithTitle:(CPString)aTitle
{
var index = [self indexOfItemWithTitle:aTitle];
if (index == CPNotFound)
return nil;
return _items[index];
}
@@ -439,7 +442,7 @@ var _CPMenuBarVisible = NO,
{
if ([aMenuItem menu] !== self)
return CPNotFound;
return [_items indexOfObjectIdenticalTo:aMenuItem];
}
@@ -452,7 +455,7 @@ var _CPMenuBarVisible = NO,
{
var index = 0,
count = _items.length;
for (; index < count; ++index)
if ([_items[index] title] === aTitle)
return index;
@@ -469,7 +472,7 @@ var _CPMenuBarVisible = NO,
{
var index = 0,
count = _items.length;
for (; index < count; ++index)
if ([_items[index] tag] == aTag)
return index;
@@ -487,11 +490,11 @@ var _CPMenuBarVisible = NO,
{
var index = 0,
count = _items.length;
for (; index < count; ++index)
{
var item = _items[index];
if ([item target] == aTarget && (!anAction || [item action] == anAction))
return index;
}
@@ -508,7 +511,7 @@ var _CPMenuBarVisible = NO,
{
var index = 0,
count = _items.length;
for (; index < count; ++index)
if ([[_items[index] representedObject] isEqual:anObject])
return index;
@@ -525,7 +528,7 @@ var _CPMenuBarVisible = NO,
{
var index = 0,
count = _items.length;
for (; index < count; ++index)
if ([_items[index] submenu] == aMenu)
return index;
@@ -543,7 +546,7 @@ var _CPMenuBarVisible = NO,
{
[aMenuItem setTarget:aMenuItem];
[aMenuItem setAction:@selector(submenuAction:)];
[aMenuItem setSubmenu:aMenu];
}
@@ -555,6 +558,7 @@ var _CPMenuBarVisible = NO,
*/
- (void)submenuAction:(id)aSender
{
}
/*!
@@ -602,34 +606,11 @@ var _CPMenuBarVisible = NO,
}
/*!
Enables or disables the receivers menu items.
If the target does not implement the menu item's action method the item is disabled.
If the target responsds to selector validateMenuItem: or validateUserInterfaceItem: (in that order) the return value is used.
Not implemented.
*/
- (void)update
{
if (![self autoenablesItems])
return;
var items = [self itemArray];
for (var i = 0; i < [items count]; i++)
{
var item = [items objectAtIndex:i];
if ([item hasSubmenu])
continue;
var validator = [CPApp targetForAction:[item action] to:[item target] from:item];
if (!validator || ![validator respondsToSelector:[item action]])
[item _setEnabled:NO];
else if ([validator respondsToSelector:@selector(validateMenuItem:)])
[item _setEnabled:[validator validateMenuItem:item]];
else if ([validator respondsToSelector:@selector(validateUserInterfaceItem:)])
[item _setEnabled:[validator validateUserInterfaceItem:item]];
}
[[_menuWindow _menuView] tile];
}
// Managing the Title
@@ -702,7 +683,7 @@ var _CPMenuBarVisible = NO,
itemIndex = [self indexOfItem:anItem];
if (itemIndex === CPNotFound)
throw "In call to popUpMenuPositioningItem:atLocation:inView:callback:, menu item " +
throw "In call to popUpMenuPositioningItem:atLocation:inView:callback:, menu item " +
anItem + " is not present in menu " + self;
}
@@ -714,7 +695,7 @@ var _CPMenuBarVisible = NO,
var delegate = [self delegate];
if ([delegate respondsToSelector:@selector(menuWillOpen:)])
[delegate menuWillOpen:self];
[delegate menuWillOpen:aMenu];
// Convert location to global coordinates if not already in them.
if (aView)
@@ -803,10 +784,10 @@ var _CPMenuBarVisible = NO,
+ (void)popUpContextMenu:(CPMenu)aMenu withEvent:(CPEvent)anEvent forView:(CPView)aView withFont:(CPFont)aFont
{
var delegate = [aMenu delegate];
if ([delegate respondsToSelector:@selector(menuWillOpen:)])
[delegate menuWillOpen:aMenu];
if (!aFont)
aFont = [CPFont systemFontOfSize:12.0];
@@ -892,7 +873,7 @@ var _CPMenuBarVisible = NO,
// Handling Tracking
/*!
Cancels tracking.
Cancels tracking.
*/
- (void)cancelTracking
{
@@ -952,12 +933,22 @@ var _CPMenuBarVisible = NO,
characters = [anEvent charactersIgnoringModifiers],
modifierFlags = [anEvent modifierFlags];
for (; index < count; ++index)
for(; index < count; ++index)
{
var item = _items[index],
modifierMask = [item keyEquivalentModifierMask];
if ([anEvent _triggersKeyEquivalent:[item keyEquivalent] withModifierMask:[item keyEquivalentModifierMask]])
if ([item keyEquivalent] === [[item keyEquivalent] uppercaseString])
modifierMask |= CPShiftKeyMask;
if (CPBrowserIsOperatingSystem(CPWindowsOperatingSystem) && (modifierMask & CPCommandKeyMask))
{
modifierMask |= CPControlKeyMask;
modifierMask &= ~CPCommandKeyMask;
}
if ((modifierFlags & (CPShiftKeyMask | CPAlternateKeyMask | CPCommandKeyMask | CPControlKeyMask)) == modifierMask &&
[characters caseInsensitiveCompare:[item keyEquivalent]] == CPOrderedSame)
{
if ([item isEnabled])
[self performActionForItemAtIndex:index];
@@ -965,7 +956,7 @@ var _CPMenuBarVisible = NO,
{
//beep?
}
return YES;
}
@@ -984,11 +975,19 @@ var _CPMenuBarVisible = NO,
- (void)performActionForItemAtIndex:(unsigned)anIndex
{
var item = _items[anIndex];
[CPApp sendAction:[item action] to:[item target] from:item];
}
//
/*
@ignore
*/
- (BOOL)_itemIsHighlighted:(CPMenuItem)aMenuItem
{
return _items[_highlightedIndex] == aMenuItem;
}
/*
@ignore
*/
@@ -1004,9 +1003,6 @@ var _CPMenuBarVisible = NO,
if (_highlightedIndex !== CPNotFound)
[[_items[_highlightedIndex] _menuItemView] highlight:YES];
if (_highlightedIndex !== CPNotFound && _menuWindow)
[_menuWindow._menuView scrollRectToVisible:[[_items[_highlightedIndex] _menuItemView] frame]];
}
- (void)_setMenuName:(CPString)aName
@@ -1052,61 +1048,6 @@ var _CPMenuBarVisible = NO,
@end
@implementation CPMenu (CPKeyValueCoding)
- (CPUInteger)countOfItems
{
return [_items count];
}
- (CPMenuItem)objectInItemsAtIndex:(CPUInteger)anIndex
{
return [_items objectAtIndex:anIndex];
}
- (CPArray)itemsAtIndexes:(CPIndexSet)indexes
{
return [_items objectsAtIndexes:indexes];
}
@end
@implementation CPMenu (CPKeyValueObserving)
- (void)insertObject:(CPMenuItem)aMenuItem inItemsAtIndex:(CPUInteger)anIndex
{
var menu = [aMenuItem menu];
if (menu)
if (menu !== self)
[CPException raise:CPInternalInconsistencyException reason:@"Attempted to insert item into menu that was already in another menu."];
else
return;
[aMenuItem setMenu:self];
[_items insertObject:aMenuItem atIndex:anIndex];
[[CPNotificationCenter defaultCenter]
postNotificationName:CPMenuDidAddItemNotification
object:self
userInfo:[CPDictionary dictionaryWithObject:anIndex forKey:@"CPMenuItemIndex"]];
}
- (void)removeObjectFromItemsAtIndex:(CPUInteger)anIndex
{
if (anIndex < 0 || anIndex >= [_items count])
return;
[[_items objectAtIndex:anIndex] setMenu:nil];
[_items removeObjectAtIndex:anIndex];
[[CPNotificationCenter defaultCenter]
postNotificationName:CPMenuDidRemoveItemNotification
object:self
userInfo:[CPDictionary dictionaryWithObject:anIndex forKey:@"CPMenuItemIndex"]];
}
@end
var CPMenuTitleKey = @"CPMenuTitleKey",
CPMenuNameKey = @"CPMenuNameKey",
@@ -1123,7 +1064,7 @@ var CPMenuTitleKey = @"CPMenuTitleKey",
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
if (self)
{
_title = [aCoder decodeObjectForKey:CPMenuTitleKey];
@@ -1133,11 +1074,9 @@ var CPMenuTitleKey = @"CPMenuTitleKey",
_showsStateColumn = ![aCoder containsValueForKey:CPMenuShowsStateColumnKey] || [aCoder decodeBoolForKey:CPMenuShowsStateColumnKey];
_autoenablesItems = YES;
[self setMinimumWidth:0];
}
return self;
}
+70 -67
View File
@@ -1,4 +1,7 @@
@import "CPPanel.j"
#include "../CoreGraphics/CGGeometry.h"
#include "../Platform/Platform.h"
@import "_CPMenuWindow.j"
@@ -15,18 +18,18 @@ var _CPMenuBarWindowBackgroundColor = nil,
CPMenu _menu;
CPView _highlightView;
CPArray _menuItemViews;
CPMenuItem _trackingMenuItem;
CPImageView _iconImageView;
CPTextField _titleField;
CPColor _textColor;
CPColor _titleColor;
CPColor _textShadowColor;
CPColor _titleShadowColor;
CPColor _highlightColor;
CPColor _highlightTextColor;
CPColor _highlightTextShadowColor;
@@ -36,9 +39,9 @@ var _CPMenuBarWindowBackgroundColor = nil,
{
if (self != [_CPMenuBarWindow class])
return;
var bundle = [CPBundle bundleForClass:self];
_CPMenuBarWindowFont = [CPFont boldSystemFontOfSize:12.0];
}
@@ -60,27 +63,27 @@ var _CPMenuBarWindowBackgroundColor = nil,
{
[self setLevel:CPMainMenuWindowLevel];
[self setAutoresizingMask:CPWindowWidthSizable];
var contentView = [self contentView];
[contentView setAutoresizesSubviews:NO];
[self setBecomesKeyOnlyIfNeeded:YES];
//
_iconImageView = [[CPImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, 16.0, 16.0)];
[contentView addSubview:_iconImageView];
_titleField = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
[_titleField setFont:[CPFont boldSystemFontOfSize:13.0]];
[_titleField setAlignment:CPCenterTextAlignment];
[_titleField setTextShadowOffset:CGSizeMake(0, 1)];
[contentView addSubview:_titleField];
}
return self;
}
@@ -99,7 +102,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
[_titleField setStringValue:aTitle];
[_titleField sizeToFit];
[self tile];
}
@@ -122,7 +125,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
{
if (!_CPMenuBarWindowBackgroundColor)
_CPMenuBarWindowBackgroundColor = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[_CPMenuBarWindow class]] pathForResource:@"_CPMenuBarWindow/_CPMenuBarWindowBackground.png"] size:CGSizeMake(1.0, 28.0)]];
[[self contentView] setBackgroundColor:_CPMenuBarWindowBackgroundColor];
}
else
@@ -133,9 +136,9 @@ var _CPMenuBarWindowBackgroundColor = nil,
{
if (_textColor == aColor)
return;
_textColor = aColor;
[_menuItemViews makeObjectsPerformSelector:@selector(setTextColor:) withObject:_textColor];
}
@@ -143,9 +146,9 @@ var _CPMenuBarWindowBackgroundColor = nil,
{
if (_titleColor == aColor)
return;
_titleColor = aColor;
[_titleField setTextColor:aColor ? aColor : [CPColor blackColor]];
}
@@ -153,9 +156,9 @@ var _CPMenuBarWindowBackgroundColor = nil,
{
if (_textShadowColor == aColor)
return;
_textShadowColor = aColor;
[_menuItemViews makeObjectsPerformSelector:@selector(setTextShadowColor:) withObject:_textShadowColor];
}
@@ -163,9 +166,9 @@ var _CPMenuBarWindowBackgroundColor = nil,
{
if (_titleShadowColor == aColor)
return;
_titleShadowColor = aColor;
[_titleField setTextShadowColor:aColor ? aColor : [CPColor whiteColor]];
}
@@ -173,7 +176,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
{
if (_highlightColor == aColor)
return;
_highlightColor = aColor;
}
@@ -181,7 +184,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
{
if (_highlightTextColor == aColor)
return;
_highlightTextColor = aColor;
// [_menuItemViews makeObjectsPerformSelector:@selector(setActivateColor:) withObject:_highlightTextColor];
@@ -191,9 +194,9 @@ var _CPMenuBarWindowBackgroundColor = nil,
{
if (_highlightTextShadowColor == aColor)
return;
_highlightTextShadowColor = aColor;
// [_menuItemViews makeObjectsPerformSelector:@selector(setActivateShadowColor:) withObject:_highlightTextShadowColor];
}
@@ -201,9 +204,9 @@ var _CPMenuBarWindowBackgroundColor = nil,
{
if (_menu == aMenu)
return;
var defaultCenter = [CPNotificationCenter defaultCenter];
if (_menu)
{
[defaultCenter
@@ -220,16 +223,16 @@ var _CPMenuBarWindowBackgroundColor = nil,
removeObserver:self
name:CPMenuDidRemoveItemNotification
object:_menu];
var items = [_menu itemArray],
count = items.length;
while (count--)
[[items[count] _menuItemView] removeFromSuperview];
}
_menu = aMenu;
if (_menu)
{
[defaultCenter
@@ -237,41 +240,41 @@ var _CPMenuBarWindowBackgroundColor = nil,
selector:@selector(menuDidAddItem:)
name:CPMenuDidAddItemNotification
object:_menu];
[defaultCenter
addObserver:self
selector:@selector(menuDidChangeItem:)
name:CPMenuDidChangeItemNotification
object:_menu];
[defaultCenter
addObserver:self
selector:@selector(menuDidRemoveItem:)
name:CPMenuDidRemoveItemNotification
object:_menu];
}
_menuItemViews = [];
var contentView = [self contentView],
items = [_menu itemArray],
count = items.length;
for (index = 0; index < count; ++index)
{
var item = items[index],
menuItemView = [item _menuItemView];
_menuItemViews.push(menuItemView);
[menuItemView setTextColor:_textColor];
[menuItemView setHidden:[item isHidden]];
[menuItemView synchronizeWithMenuItem];
[contentView addSubview:menuItemView];
}
[self tile];
}
@@ -282,7 +285,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
[menuItemView setHidden:[menuItem isHidden]];
[menuItemView synchronizeWithMenuItem];
[self tile];
}
@@ -298,9 +301,9 @@ var _CPMenuBarWindowBackgroundColor = nil,
[menuItemView setHidden:[menuItem isHidden]];
[menuItemView synchronizeWithMenuItem];
[[self contentView] addSubview:menuItemView];
[self tile];
}
@@ -312,7 +315,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
[_menuItemViews removeObjectAtIndex:index];
[menuItemView removeFromSuperview];
[self tile];
}
@@ -343,29 +346,29 @@ var _CPMenuBarWindowBackgroundColor = nil,
var items = [_menu itemArray],
index = 0,
count = items.length,
x = MENUBAR_LEFT_MARGIN,
y = 0.0,
isLeftAligned = YES;
for (; index < count; ++index)
{
var item = items[index];
if ([item isSeparatorItem])
{
x = CGRectGetWidth([self frame]) - MENUBAR_RIGHT_MARGIN;
isLeftAligned = NO;
continue;
}
if ([item isHidden])
continue;
var menuItemView = [item _menuItemView],
frame = [menuItemView frame];
if (isLeftAligned)
{
[menuItemView setFrame:CGRectMake(x, 0.0, CGRectGetWidth(frame), MENUBAR_HEIGHT)];
@@ -375,14 +378,14 @@ var _CPMenuBarWindowBackgroundColor = nil,
else
{
[menuItemView setFrame:CGRectMake(x - CGRectGetWidth(frame), 0.0, CGRectGetWidth(frame), MENUBAR_HEIGHT)];
x = CGRectGetMinX([menuItemView frame]);
}
}
var bounds = [[self contentView] bounds],
titleFrame = [_titleField frame];
if ([_iconImageView isHidden])
[_titleField setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth(titleFrame)) / 2.0, (CGRectGetHeight(bounds) - CGRectGetHeight(titleFrame)) / 2.0)];
else
@@ -390,7 +393,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
var iconFrame = [_iconImageView frame],
iconWidth = CGRectGetWidth(iconFrame),
totalWidth = iconWidth + CGRectGetWidth(titleFrame);
[_iconImageView setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - totalWidth) / 2.0, (CGRectGetHeight(bounds) - CGRectGetHeight(iconFrame)) / 2.0)];
[_titleField setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - totalWidth) / 2.0 + iconWidth, (CGRectGetHeight(bounds) - CGRectGetHeight(titleFrame)) / 2.0)];
}
@@ -505,38 +508,38 @@ var _CPMenuBarWindowBackgroundColor = nil,
for (; index < count; ++index)
{
var item = items[index];
if ([item isSeparatorItem])
{
x = CGRectGetWidth([self frame]) - MENUBAR_RIGHT_MARGIN;
isLeftAligned = NO;
continue;
}
if ([item isHidden])
continue;
var menuItemView = [item _menuItemView],
frame = [menuItemView frame];
if (isLeftAligned)
{
[menuItemView setFrameOrigin:CGPointMake(x, (MENUBAR_HEIGHT - 1.0 - CGRectGetHeight(frame)) / 2.0)];
x += CGRectGetWidth([menuItemView frame]) + MENUBAR_MARGIN;
}
else
{
[menuItemView setFrameOrigin:CGPointMake(x - CGRectGetWidth(frame), (MENUBAR_HEIGHT - 1.0 - CGRectGetHeight(frame)) / 2.0)];
x = CGRectGetMinX([menuItemView frame]) - MENUBAR_MARGIN;
}
}
var bounds = [[self contentView] bounds],
titleFrame = [_titleField frame];
if ([_iconImageView isHidden])
[_titleField setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth(titleFrame)) / 2.0, (CGRectGetHeight(bounds) - CGRectGetHeight(titleFrame)) / 2.0)];
else
@@ -544,7 +547,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
var iconFrame = [_iconImageView frame],
iconWidth = CGRectGetWidth(iconFrame),
totalWidth = iconWidth + CGRectGetWidth(titleFrame);
[_iconImageView setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - totalWidth) / 2.0, (CGRectGetHeight(bounds) - CGRectGetHeight(iconFrame)) / 2.0)];
[_titleField setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - totalWidth) / 2.0 + iconWidth, (CGRectGetHeight(bounds) - CGRectGetHeight(titleFrame)) / 2.0)];
}
+49 -334
View File
@@ -1,3 +1,6 @@
#include "../CoreGraphics/CGGeometry.h"
@import <Foundation/CPObject.j>
@@ -5,8 +8,9 @@ _CPMenuManagerScrollingStateUp = -1,
_CPMenuManagerScrollingStateDown = 1,
_CPMenuManagerScrollingStateNone = 0;
var STICKY_TIME_INTERVAL = 500,
SharedMenuManager = nil;
var STICKY_TIME_INTERVAL = 500;
var SharedMenuManager = nil;
@implementation _CPMenuManager: CPObject
{
@@ -20,11 +24,6 @@ var STICKY_TIME_INTERVAL = 500,
CPMutableArray _menuContainerStack;
Function _trackingCallback;
CPString _keyBuffer;
CPMenuItem _previousActiveItem;
int _showTimerID;
}
+ (_CPMenuManager)sharedMenuManager
@@ -40,7 +39,7 @@ var STICKY_TIME_INTERVAL = 500,
if (SharedMenuManager)
return SharedMenuManager;
return [super init];
return [super init];
}
- (id)trackingMenuContainer
@@ -71,13 +70,13 @@ var STICKY_TIME_INTERVAL = 500,
if (menu === [CPApp mainMenu])
{
var globalLocation = [anEvent globalLocation],
var globalLocation = [anEvent globalLocation];
// Find which menu window the mouse is currently on top of
menuLocation = [aMenuContainer convertGlobalToBase:globalLocation],
// Find which menu window the mouse is currently on top of
var menuLocation = [aMenuContainer convertGlobalToBase:globalLocation];
// Find out the item the mouse is currently on top of
activeItemIndex = [aMenuContainer itemIndexAtPoint:menuLocation],
// Find out the item the mouse is currently on top of
var activeItemIndex = [aMenuContainer itemIndexAtPoint:menuLocation],
activeItem = activeItemIndex !== CPNotFound ? [menu itemAtIndex:activeItemIndex] : nil;
_menuBarButtonItemIndex = activeItemIndex;
@@ -97,36 +96,9 @@ var STICKY_TIME_INTERVAL = 500,
// Close Menu Event.
if (type === CPAppKitDefined)
return [self completeTracking];
return [self completeTracking]
[CPApp setTarget:self selector:@selector(trackEvent:) forNextEventMatchingMask:CPKeyDownMask | CPPeriodicMask | CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPAppKitDefinedMask | CPScrollWheelMask untilDate:nil inMode:nil dequeue:YES];
if (type === CPKeyDown)
{
var menu = trackingMenu,
submenu = [[menu highlightedItem] submenu];
// get the current active menu
while (submenu && [submenu._menuWindow isVisible])
{
menu = submenu;
submenu = [[menu highlightedItem] submenu];
}
if ([menu numberOfItems])
[self interpretKeyEvent:anEvent forMenu:menu];
return;
}
if (_keyBuffer)
{
if (([CPDate date] - _startTime) > (STICKY_TIME_INTERVAL + [activeMenu numberOfItems] / 2))
[self selectNextItemBeginningWith:_keyBuffer inMenu:menu clearBuffer:YES];
if (type === CPPeriodic)
return;
}
[CPApp setTarget:self selector:@selector(trackEvent:) forNextEventMatchingMask:CPPeriodicMask | CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPAppKitDefinedMask untilDate:nil inMode:nil dequeue:YES];
// Periodic events don't have a valid location.
var globalLocation = type === CPPeriodic ? _lastGlobalLocation : [anEvent globalLocation];
@@ -134,16 +106,13 @@ var STICKY_TIME_INTERVAL = 500,
// Remember this for the next periodic event.
_lastGlobalLocation = globalLocation;
if (!_lastGlobalLocation)
return;
// Find which menu window the mouse is currently on top of
var activeMenuContainer = [self menuContainerForPoint:globalLocation],
activeMenu = [activeMenuContainer menu],
menuLocation = [activeMenuContainer convertGlobalToBase:globalLocation],
menuLocation = [activeMenuContainer convertGlobalToBase:globalLocation];
// Find out the item the mouse is currently on top of
activeItemIndex = activeMenuContainer ? [activeMenuContainer itemIndexAtPoint:menuLocation] : CPNotFound,
// Find out the item the mouse is currently on top of
var activeItemIndex = activeMenuContainer ? [activeMenuContainer itemIndexAtPoint:menuLocation] : CPNotFound,
activeItem = activeItemIndex !== CPNotFound ? [activeMenu itemAtIndex:activeItemIndex] : nil;
// If the item isn't enabled its as if we clicked on nothing.
@@ -155,13 +124,11 @@ var STICKY_TIME_INTERVAL = 500,
var mouseOverMenuView = [activeItem view];
if (type === CPScrollWheel)
[activeMenuContainer scrollByDelta:[anEvent deltaY]];
if (type === CPPeriodic)
{
if (_scrollingState === _CPMenuManagerScrollingStateUp)
[activeMenuContainer scrollUp];
else if (_scrollingState === _CPMenuManagerScrollingStateDown)
[activeMenuContainer scrollDown];
}
@@ -171,13 +138,13 @@ var STICKY_TIME_INTERVAL = 500,
{
if (!_lastMouseOverMenuView)
[activeMenu _highlightItemAtIndex:CPNotFound];
if (_lastMouseOverMenuView != mouseOverMenuView)
{
[mouseOverMenuView mouseExited:anEvent];
// FIXME: Possibly multiple of these?
[_lastMouseOverMenuView mouseEntered:anEvent];
_lastMouseOverMenuView = mouseOverMenuView;
}
@@ -187,15 +154,13 @@ var STICKY_TIME_INTERVAL = 500,
menuContainerWindow = [menuContainerWindow window];
[menuContainerWindow
sendEvent:[CPEvent mouseEventWithType:type
location:menuLocation
modifierFlags:[anEvent modifierFlags]
timestamp:[anEvent timestamp]
windowNumber:menuContainerWindow
context:nil
eventNumber:0
clickCount:[anEvent clickCount]
pressure:[anEvent pressure]]];
sendEvent:[CPEvent mouseEventWithType:type location:menuLocation modifierFlags:[anEvent modifierFlags]
timestamp:[anEvent timestamp]
windowNumber:menuContainerWindow
context:nil
eventNumber:0
clickCount:[anEvent clickCount]
pressure:[anEvent pressure]]];
}
else
{
@@ -204,10 +169,10 @@ var STICKY_TIME_INTERVAL = 500,
[_lastMouseOverMenuView mouseExited:anEvent];
_lastMouseOverMenuView = nil;
}
[activeMenu _highlightItemAtIndex:activeItemIndex];
if (type === CPMouseMoved || type === CPLeftMouseDragged || type === CPLeftMouseDown || type === CPPeriodic)
if (type === CPMouseMoved || type === CPLeftMouseDragged || type === CPLeftMouseDown)
{
var oldScrollingState = _scrollingState;
@@ -217,59 +182,34 @@ var STICKY_TIME_INTERVAL = 500,
{
if (_scrollingState === _CPMenuManagerScrollingStateNone)
[CPEvent stopPeriodicEvents];
else if (oldScrollingState === _CPMenuManagerScrollingStateNone)
[CPEvent startPeriodicEventsAfterDelay:0.0 withPeriod:0.04];
}
}
else if (type === CPLeftMouseUp && ([anEvent timestamp] - _startTime > (STICKY_TIME_INTERVAL + [activeMenu numberOfItems] * 5)))
else if (type === CPLeftMouseUp && ([anEvent timestamp] - _startTime > STICKY_TIME_INTERVAL))
[trackingMenu cancelTracking];
}
// Prevent previous selected menu items from opening by stopping the timer if a
// new item is selected before the timer runs out
if (_previousActiveItem !== activeItem)
{
clearTimeout(_showTimerID);
_showTimerID = undefined;
}
// If the item has a submenu, show it.
if ([activeItem hasSubmenu])// && [activeItem action] === @selector(submenuAction:))
{
var activeItemRect = [activeMenuContainer rectForItemAtIndex:activeItemIndex],
newMenuOrigin;
var activeItemRect = [activeMenuContainer rectForItemAtIndex:activeItemIndex];
if ([activeMenuContainer isMenuBar])
newMenuOrigin = CGPointMake(CGRectGetMinX(activeItemRect), CGRectGetMaxY(activeItemRect));
var newMenuOrigin = CGPointMake(CGRectGetMinX(activeItemRect), CGRectGetMaxY(activeItemRect));
else
newMenuOrigin = CGPointMake(CGRectGetMaxX(activeItemRect), CGRectGetMinY(activeItemRect));
var newMenuOrigin = CGPointMake(CGRectGetMaxX(activeItemRect), CGRectGetMinY(activeItemRect));
newMenuOrigin = [activeMenuContainer convertBaseToGlobal:newMenuOrigin];
// Only start a new timer if the previous was cancelled
if (_showTimerID === undefined)
{
// Close the current menu item because we are going to select a new one after a short delay
[self showMenu:nil fromMenu:activeMenu atPoint:CGPointMakeZero()];
if (![activeMenuContainer isMenuBar])
{
_showTimerID = setTimeout(function()
{
[self showMenu:[activeItem submenu] fromMenu:[activeItem menu] atPoint:newMenuOrigin];
}, 250);
}
else
[self showMenu:[activeItem submenu] fromMenu:[activeItem menu] atPoint:newMenuOrigin];
}
[self showMenu:[activeItem submenu] fromMenu:[activeItem menu] atPoint:newMenuOrigin];
}
// This handles both the case where we've moved away from the menu, and where
// This handles both the case where we've moved away from the menu, and where
// we've moved to an item without a submenu.
else
[self showMenu:nil fromMenu:activeMenu atPoint:CGPointMakeZero()];
_previousActiveItem = activeItem;
}
- (void)trackMenuBarButtonEvent:(CPEvent)anEvent
@@ -279,15 +219,16 @@ var STICKY_TIME_INTERVAL = 500,
if (type === CPAppKitDefined)
return [self completeTracking];
var globalLocation = [anEvent globalLocation],
var globalLocation = [anEvent globalLocation];
// Find which menu window the mouse is currently on top of
menu = [self trackingMenu],
// Find which menu window the mouse is currently on top of
var menu = [self trackingMenu],
trackingMenuContainer = [self trackingMenuContainer],
menuLocation = [trackingMenuContainer convertGlobalToBase:globalLocation];
if ([trackingMenuContainer itemIndexAtPoint:menuLocation] === _menuBarButtonItemIndex)
[menu _highlightItemAtIndex:_menuBarButtonItemIndex];
else
[menu _highlightItemAtIndex:CPNotFound];
@@ -304,6 +245,9 @@ var STICKY_TIME_INTERVAL = 500,
// Stop all periodic events at this point.
[CPEvent stopPeriodicEvents];
// Get the highlighted item from the original menu.
var highlightedItem = [trackingMenu highlightedItem];
// Hide all submenus.
[self showMenu:nil fromMenu:trackingMenu atPoint:nil];
@@ -315,8 +259,9 @@ var STICKY_TIME_INTERVAL = 500,
if (_trackingCallback)
_trackingCallback([self trackingMenuContainer], trackingMenu);
[[CPNotificationCenter defaultCenter] postNotificationName:CPMenuDidEndTrackingNotification
object:trackingMenu];
[[CPNotificationCenter defaultCenter]
postNotificationName:CPMenuDidEndTrackingNotification
object:trackingMenu];
CPApp._activeMenu = nil;
}
@@ -416,240 +361,10 @@ var STICKY_TIME_INTERVAL = 500,
if (baseMenu === [self trackingMenu] && [[self trackingMenuContainer] isMenuBar])
[menuWindow setBackgroundStyle:_CPMenuWindowMenuBarBackgroundStyle];
else
[menuWindow setBackgroundStyle:_CPMenuWindowPopUpBackgroundStyle];
[menuWindow setBackgroundStyle:_CPMenuWindowPopUpBackgroundStyle];
[menuWindow setFrameOrigin:aGlobalLocation];
[menuWindow orderFront:self];
}
/// handle keyboard navigation
- (void)interpretKeyEvent:(CPEvent)anEvent forMenu:(CPMenu)menu
{
var modifierFlags = [anEvent modifierFlags],
character = [anEvent charactersIgnoringModifiers],
selectorNames = [CPKeyBinding selectorsForKey:character modifierFlags:modifierFlags];
if (selectorNames)
{
var iter = [selectorNames objectEnumerator],
obj;
while (obj = [iter nextObject])
{
var aSelector = CPSelectorFromString(obj);
if ([self respondsToSelector:aSelector])
[self performSelector:aSelector withObject:menu];
}
}
else if (!(modifierFlags & (CPCommandKeyMask | CPControlKeyMask)))
{
if (!_keyBuffer)
{
_startTime = [CPDate date];
_keyBuffer = character;
[CPEvent stopPeriodicEvents];
[CPEvent startPeriodicEventsAfterDelay:0.1 withPeriod:0.1];
}
else
_keyBuffer += character;
[self selectNextItemBeginningWith:_keyBuffer inMenu:menu clearBuffer:NO];
_lastGlobalLocation = Nil;
}
}
- (void)selectNextItemBeginningWith:(CPString)characters inMenu:(CPMenu)menu clearBuffer:(BOOL)shouldClear
{
var iter = [[menu itemArray] objectEnumerator],
obj;
while (obj = [iter nextObject])
{
if ([obj isHidden] || ![obj isEnabled])
continue;
if ([[[obj title] commonPrefixWithString:characters options:CPCaseInsensitiveSearch] length] == [characters length])
{
[menu _highlightItemAtIndex:iter._index];
break;
}
}
if (shouldClear)
{
[CPEvent stopPeriodicEvents];
_keyBuffer = Nil;
}
else
_startTime = [CPDate date];
}
- (void)scrollToBeginningOfDocument:(CPMenu)menu
{
[menu _highlightItemAtIndex:0];
}
- (void)scrollToEndOfDocument:(CPMenu)menu
{
[menu _highlightItemAtIndex:[menu numberOfItems] - 1];
}
- (void)scrollPageDown:(CPMenu)menu
{
var menuWindow = menu._menuWindow,
menuClipView = menuWindow._menuClipView,
bottom = [menuClipView bounds].size.height,
first = [menuWindow itemIndexAtPoint:CGPointMake(1, 10)],
last = [menuWindow itemIndexAtPoint:CGPointMake(1, bottom)],
current = [menu indexOfItem:[menu highlightedItem]];
if (current == CPNotFound)
{
[menu _highlightItemAtIndex:0];
return;
}
next = current + (last - first);
if (next < [menu numberOfItems])
[menu _highlightItemAtIndex:next];
else
[menu _highlightItemAtIndex:[menu numberOfItems] - 1];
var item = [menu highlightedItem];
if ([item isSeparatorItem] || [item isHidden] || ![item isEnabled])
[self moveDown:menu];
}
- (void)scrollPageUp:(CPMenu)menu
{
var menuWindow = menu._menuWindow,
menuClipView = menuWindow._menuClipView,
bottom = [menuClipView bounds].size.height,
first = [menuWindow itemIndexAtPoint:CGPointMake(1, 10)],
last = [menuWindow itemIndexAtPoint:CGPointMake(1, bottom)],
current = [menu indexOfItem:[menu highlightedItem]];
if (current == CPNotFound)
{
[menu _highlightItemAtIndex:0];
return;
}
next = current - (last - first);
if (next < 0)
[menu _highlightItemAtIndex:0];
else
[menu _highlightItemAtIndex:next];
var item = [menu highlightedItem];
if ([item isSeparatorItem] || [item isHidden] || ![item isEnabled])
[self moveUp:menu];
}
- (void)moveLeft:(CPMenu)menu
{
if ([menu supermenu])
{
if ([menu supermenu] == [CPApp mainMenu])
{
[self showMenu:nil fromMenu:[menu supermenu] atPoint:CGPointMakeZero()];
[self moveUp:[CPApp mainMenu]];
var activeItem = [[CPApp mainMenu] highlightedItem],
menuLocation = CGPointMake([[activeItem _menuItemView] frameOrigin].x , [[activeItem _menuItemView] frameSize].height);
[self showMenu:[activeItem submenu] fromMenu:[activeItem menu] atPoint:menuLocation];
}
else
[self showMenu:nil fromMenu:[menu supermenu] atPoint:CGPointMakeZero()];
}
}
- (void)moveRight:(CPMenu)menu
{
var activeItem = [menu highlightedItem];
if ([activeItem hasSubmenu])
{
if ([[activeItem submenu] numberOfItems])
{
var activeItemIndex = [menu indexOfItem:activeItem],
activeMenuContainer = menu._menuWindow,
activeItemRect = [activeMenuContainer rectForItemAtIndex:activeItemIndex],
newMenuOrigin;
if ([activeMenuContainer isMenuBar])
newMenuOrigin = CGPointMake(CGRectGetMinX(activeItemRect), CGRectGetMaxY(activeItemRect));
else
newMenuOrigin = CGPointMake(CGRectGetMaxX(activeItemRect), CGRectGetMinY(activeItemRect));
newMenuOrigin = [activeMenuContainer convertBaseToGlobal:newMenuOrigin];
[self showMenu:[activeItem submenu] fromMenu:[activeItem menu] atPoint:newMenuOrigin];
[self moveDown:[activeItem submenu]];
}
}
else if ([self trackingMenu] == [CPApp mainMenu])
{
[self showMenu:nil fromMenu:menu atPoint:CGPointMakeZero()];
[self moveDown:[CPApp mainMenu]];
var activeItem = [[CPApp mainMenu] highlightedItem],
menuLocation = CGPointMake([[activeItem _menuItemView] frameOrigin].x , [[activeItem _menuItemView] frameSize].height);
[self showMenu:[activeItem submenu] fromMenu:[activeItem menu] atPoint:menuLocation];
}
}
- (void)moveDown:(CPMenu)menu
{
var index = menu._highlightedIndex + 1;
if (index < [menu numberOfItems])
{
[menu _highlightItemAtIndex:index];
var item = [menu highlightedItem];
if ([item isSeparatorItem] || [item isHidden] || ![item isEnabled])
[self moveDown:menu];
}
}
- (void)moveUp:(CPMenu)menu
{
var index = menu._highlightedIndex - 1;
if (index < 0)
return;
[menu _highlightItemAtIndex:index];
var item = [menu highlightedItem];
if ([item isSeparatorItem] || [item isHidden] || ![item isEnabled])
[self moveUp:menu];
}
- (void)insertNewline:(CPMenu)menu
{
if ([[menu highlightedItem] hasSubmenu])
[self moveRight:menu];
else
[menu cancelTracking]
}
- (void)cancelOperation:(CPMenu)menu
{
[menu _highlightItemAtIndex:CPNotFound];
[CPEvent stopPeriodicEvents];
[[self trackingMenu] cancelTracking];
}
@end
+59 -73
View File
@@ -1,11 +1,12 @@
@import "CPWindow.j"
#include "../CoreGraphics/CGGeometry.h"
var _CPMenuWindowPool = [],
_CPMenuWindowPoolCapacity = 5,
_CPMenuWindowBackgroundColors = [];
_CPMenuWindowMenuBarBackgroundStyle = 0;
_CPMenuWindowPopUpBackgroundStyle = 1;
_CPMenuWindowAttachedMenuBackgroundStyle = 2;
@@ -16,7 +17,7 @@ var STICKY_TIME_INTERVAL = 500,
LEFT_MARGIN = 1.0,
RIGHT_MARGIN = 1.0,
BOTTOM_MARGIN = 5.0,
SCROLL_INDICATOR_HEIGHT = 16.0;
/*
@@ -26,10 +27,10 @@ var STICKY_TIME_INTERVAL = 500,
{
_CPMenuView _menuView;
CPClipView _menuClipView;
CPImageView _moreAboveView;
CPImageView _moreBelowView;
CGRect _unconstrainedFrame;
CGRect _constraintRect;
}
@@ -67,9 +68,9 @@ var STICKY_TIME_INTERVAL = 500,
{
if (self != [_CPMenuWindow class])
return;
var bundle = [CPBundle bundleForClass:self];
_CPMenuWindowMoreAboveImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowMoreAbove.png"] size:CGSizeMake(38.0, 18.0)];
_CPMenuWindowMoreBelowImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowMoreBelow.png"] size:CGSizeMake(38.0, 18.0)];
}
@@ -89,31 +90,31 @@ var STICKY_TIME_INTERVAL = 500,
[self setAcceptsMouseMovedEvents:YES];
var contentView = [self contentView];
_menuView = [[_CPMenuView alloc] initWithFrame:CGRectMakeZero()];
_menuClipView = [[CPClipView alloc] initWithFrame:CGRectMake(LEFT_MARGIN, TOP_MARGIN, 0.0, 0.0)];
[_menuClipView setDocumentView:_menuView];
[contentView addSubview:_menuClipView];
_moreAboveView = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
[_moreAboveView setImage:_CPMenuWindowMoreAboveImage];
[_moreAboveView setFrameSize:[_CPMenuWindowMoreAboveImage size]];
[contentView addSubview:_moreAboveView];
_moreBelowView = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
[_moreBelowView setImage:_CPMenuWindowMoreBelowImage];
[_moreBelowView setFrameSize:[_CPMenuWindowMoreBelowImage size]];
[contentView addSubview:_moreBelowView];
[self setShadowStyle:CPWindowShadowStyleMenu];
}
return self;
}
@@ -135,7 +136,7 @@ var STICKY_TIME_INTERVAL = 500,
+ (CPColor)backgroundColorForBackgroundStyle:(_CPMenuWindowBackgroundStyle)aBackgroundStyle
{
var color = _CPMenuWindowBackgroundColors[aBackgroundStyle];
if (!color)
{
var bundle = [CPBundle bundleForClass:[self class]];
@@ -146,32 +147,32 @@ var STICKY_TIME_INTERVAL = 500,
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded0.png"] size:CGSizeMake(4.0, 4.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow1.png"] size:CGSizeMake(1.0, 4.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded2.png"] size:CGSizeMake(4.0, 4.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow3.png"] size:CGSizeMake(4.0, 1.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow4.png"] size:CGSizeMake(1.0, 1.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow5.png"] size:CGSizeMake(4.0, 1.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded6.png"] size:CGSizeMake(4.0, 4.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow7.png"] size:CGSizeMake(1.0, 4.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded8.png"] size:CGSizeMake(4.0, 4.0)]
]]];
else if (aBackgroundStyle == _CPMenuWindowMenuBarBackgroundStyle)
color = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow3.png"] size:CGSizeMake(4.0, 0.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow4.png"] size:CGSizeMake(1.0, 0.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow5.png"] size:CGSizeMake(4.0, 0.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow3.png"] size:CGSizeMake(4.0, 1.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow4.png"] size:CGSizeMake(1.0, 1.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow5.png"] size:CGSizeMake(4.0, 1.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded6.png"] size:CGSizeMake(4.0, 4.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow7.png"] size:CGSizeMake(1.0, 4.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded8.png"] size:CGSizeMake(4.0, 4.0)]
]]];
_CPMenuWindowBackgroundColors[aBackgroundStyle] = color;
}
@@ -187,11 +188,11 @@ var STICKY_TIME_INTERVAL = 500,
{
[aMenu _setMenuWindow:self];
[_menuView setMenu:aMenu];
var menuViewSize = [_menuView frame].size;
[self setFrameSize:CGSizeMake(LEFT_MARGIN + menuViewSize.width + RIGHT_MARGIN, TOP_MARGIN + menuViewSize.height + BOTTOM_MARGIN)];
[_menuView scrollPoint:CGPointMake(0.0, 0.0)];
[_menuClipView setFrame:CGRectMake(LEFT_MARGIN, TOP_MARGIN, menuViewSize.width, menuViewSize.height)];
}
@@ -208,16 +209,10 @@ var STICKY_TIME_INTERVAL = 500,
return [_menuView menu];
}
- (_CPMenuView)_menuView
{
return _menuView;
}
- (void)orderFront:(id)aSender
{
[[self menu] update];
[self setFrame:_unconstrainedFrame];
[super orderFront:aSender];
}
@@ -276,16 +271,16 @@ var STICKY_TIME_INTERVAL = 500,
topMargin = TOP_MARGIN,
bottomMargin = BOTTOM_MARGIN,
contentView = [self contentView],
bounds = [contentView bounds];
if (moreAbove)
{
topMargin += SCROLL_INDICATOR_HEIGHT;
var frame = [_moreAboveView frame];
[_moreAboveView setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth(frame)) / 2.0, (TOP_MARGIN + SCROLL_INDICATOR_HEIGHT - CGRectGetHeight(frame)) / 2.0)];
}
@@ -294,18 +289,13 @@ var STICKY_TIME_INTERVAL = 500,
if (moreBelow)
{
bottomMargin += SCROLL_INDICATOR_HEIGHT;
[_moreBelowView setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth([_moreBelowView frame])) / 2.0, CGRectGetHeight(bounds) - SCROLL_INDICATOR_HEIGHT - BOTTOM_MARGIN)];
}
[_moreBelowView setHidden:!moreBelow];
var clipFrame = CGRectMakeZero();
clipFrame.origin.x = LEFT_MARGIN;
clipFrame.origin.y = topMargin;
clipFrame.size.width = CGRectGetWidth(constrainedFrame) - LEFT_MARGIN - RIGHT_MARGIN;
clipFrame.size.height = CGRectGetHeight(constrainedFrame) - topMargin - bottomMargin;
var clipFrame = CGRectMake(LEFT_MARGIN, topMargin, CGRectGetWidth(constrainedFrame) - LEFT_MARGIN - RIGHT_MARGIN, CGRectGetHeight(constrainedFrame) - topMargin - bottomMargin)
[_menuClipView setFrame:clipFrame];
[_menuView setFrameSize:CGSizeMake(CGRectGetWidth(clipFrame), CGRectGetHeight([_menuView frame]))];
@@ -358,29 +348,24 @@ var STICKY_TIME_INTERVAL = 500,
return [self canScrollUp] || [self canScrollDown];
}
- (void)scrollByDelta:(float)theDelta
{
if (theDelta === 0.0)
return;
if (theDelta > 0.0 && ![self canScrollDown])
return;
if (theDelta < 0.0 && ![self canScrollUp])
return;
_unconstrainedFrame.origin.y -= theDelta;
[self setFrame:_unconstrainedFrame];
}
- (void)scrollUp
{
[self scrollByDelta:-10.0];
if (CGRectGetMinY(_unconstrainedFrame) >= CGRectGetMinY(_constraintRect))
return;
_unconstrainedFrame.origin.y += 10;
[self setFrame:_unconstrainedFrame];
}
- (void)scrollDown
{
[self scrollByDelta:10.0];
if (CGRectGetMaxY(_unconstrainedFrame) <= CGRectGetHeight(_constraintRect))
return;
_unconstrainedFrame.origin.y -= 10;
[self setFrame:_unconstrainedFrame];
}
@end
@@ -400,15 +385,16 @@ var STICKY_TIME_INTERVAL = 500,
- (_CPManagerScrollingState)scrollingStateForPoint:(CGPoint)aGlobalLocation
{
var frame = [self frame];
if (!CPRectContainsPoint(frame,aGlobalLocation) || ![self canScroll])
if (![self canScroll])
return _CPMenuManagerScrollingStateNone;
// If we're at or above of the top scroll indicator...
if (aGlobalLocation.y < CGRectGetMinY(frame) + TOP_MARGIN + SCROLL_INDICATOR_HEIGHT && ![_moreAboveView isHidden])
if (aGlobalLocation.y < CGRectGetMinY(frame) + TOP_MARGIN + SCROLL_INDICATOR_HEIGHT)
return _CPMenuManagerScrollingStateUp;
// If we're at or below the bottom scroll indicator...
if (aGlobalLocation.y > CGRectGetMaxY(frame) - BOTTOM_MARGIN - SCROLL_INDICATOR_HEIGHT && ![_moreBelowView isHidden])
if (aGlobalLocation.y > CGRectGetMaxY(frame) - BOTTOM_MARGIN - SCROLL_INDICATOR_HEIGHT)
return _CPMenuManagerScrollingStateDown;
return _CPMenuManagerScrollingStateNone;
@@ -443,7 +429,7 @@ var STICKY_TIME_INTERVAL = 500,
{
CPArray _menuItemViews;
CPArray _visibleMenuItemInfos;
CPFont _font @accessors(property=font);
}
@@ -477,7 +463,7 @@ var STICKY_TIME_INTERVAL = 500,
while (low <= high)
{
var middle = FLOOR(low + (high - low) / 2),
info = _visibleMenuItemInfos[middle],
info = _visibleMenuItemInfos[middle]
frame = [info.view frame];
if (y < CGRectGetMinY(frame))
@@ -495,7 +481,7 @@ var STICKY_TIME_INTERVAL = 500,
- (void)tile
{
[_menuItemViews makeObjectsPerformSelector:@selector(removeFromSuperview)];
[_menuItemViews makeObjectsPerformSelector:@selector(removeFromSuperview)];
_menuItemViews = [];
_visibleMenuItemInfos = [];
@@ -515,15 +501,15 @@ var STICKY_TIME_INTERVAL = 500,
for (; index < count; ++index)
{
var item = items[index],
view = [item _menuItemView];
view = [item _menuItemView];
_menuItemViews.push(view);
if ([item isHidden])
continue;
_visibleMenuItemInfos.push({ view:view, index:index });
[view setFont:_font];
[view setShowsStateColumn:showsStateColumn];
[view synchronizeWithMenuItem];
+58 -139
View File
@@ -29,27 +29,7 @@
@import "CPView.j"
@import "_CPMenuItemView.j"
var CPMenuItemStringRepresentationDictionary = [CPDictionary dictionary];
[CPMenuItemStringRepresentationDictionary setObject:"\u238B" forKey:CPEscapeFunctionKey];
[CPMenuItemStringRepresentationDictionary setObject:"\u21E5" forKey:CPTabCharacter];
[CPMenuItemStringRepresentationDictionary setObject:"\u21E4" forKey:CPBackTabCharacter];
[CPMenuItemStringRepresentationDictionary setObject:"\u2423" forKey:CPSpaceFunctionKey];
[CPMenuItemStringRepresentationDictionary setObject:"\u23CE" forKey:CPCarriageReturnCharacter];
[CPMenuItemStringRepresentationDictionary setObject:"\u232B" forKey:CPBackspaceCharacter];
[CPMenuItemStringRepresentationDictionary setObject:"\u232B" forKey:CPDeleteFunctionKey];
[CPMenuItemStringRepresentationDictionary setObject:"\u2326" forKey:CPDeleteCharacter];
[CPMenuItemStringRepresentationDictionary setObject:"\u21F1" forKey:CPHomeFunctionKey];
[CPMenuItemStringRepresentationDictionary setObject:"\u21F2" forKey:CPEndFunctionKey];
[CPMenuItemStringRepresentationDictionary setObject:"\u21DE" forKey:CPPageUpFunctionKey];
[CPMenuItemStringRepresentationDictionary setObject:"\u21DF" forKey:CPPageDownFunctionKey];
[CPMenuItemStringRepresentationDictionary setObject:"\u2191" forKey:CPUpArrowFunctionKey];
[CPMenuItemStringRepresentationDictionary setObject:"\u2193" forKey:CPDownArrowFunctionKey];
[CPMenuItemStringRepresentationDictionary setObject:"\u2190" forKey:CPLeftArrowFunctionKey];
[CPMenuItemStringRepresentationDictionary setObject:"\u2192" forKey:CPRightArrowFunctionKey];
[CPMenuItemStringRepresentationDictionary setObject:"\u2327" forKey:CPClearDisplayFunctionKey];
/*!
/*!
@ingroup appkit
@class CPMenuItem
@@ -63,41 +43,39 @@ var CPMenuItemStringRepresentationDictionary = [CPDictionary dictionary];
CPString _title;
//CPAttributedString _attributedTitle;
CPFont _font;
id _target;
SEL _action;
BOOL _isEnabled;
BOOL _isHidden;
int _tag;
int _state;
CPImage _image;
CPImage _alternateImage;
CPImage _onStateImage;
CPImage _offStateImage;
CPImage _mixedStateImage;
CPMenu _submenu;
CPMenu _menu;
CPString _keyEquivalent;
unsigned _keyEquivalentModifierMask;
int _mnemonicLocation;
BOOL _isAlternate;
int _indentationLevel;
CPString _toolTip;
id _representedObject;
CPView _view;
int _changeCount;
_CPMenuItemView _menuItemView;
}
@@ -116,21 +94,19 @@ var CPMenuItemStringRepresentationDictionary = [CPDictionary dictionary];
- (id)initWithTitle:(CPString)aTitle action:(SEL)anAction keyEquivalent:(CPString)aKeyEquivalent
{
self = [super init];
if (self)
{
_changeCount = 0;
_isSeparator = NO;
_title = aTitle;
_action = anAction;
_isEnabled = YES;
_isHidden = NO;
_tag = 0;
_state = CPOffState;
_keyEquivalent = aKeyEquivalent || @"";
_keyEquivalentModifierMask = CPPlatformActionKeyMask;
@@ -138,7 +114,7 @@ var CPMenuItemStringRepresentationDictionary = [CPDictionary dictionary];
_mnemonicLocation = CPNotFound;
}
return self;
}
@@ -152,17 +128,10 @@ var CPMenuItemStringRepresentationDictionary = [CPDictionary dictionary];
if ([_menu autoenablesItems])
return;
[self _setEnabled:isEnabled];
}
- (void)_setEnabled:(BOOL)isEnabled
{
if (_isEnabled === isEnabled)
return;
_isEnabled = !!isEnabled;
_isEnabled = isEnabled;
[_menuItemView setDirty];
[_menu itemChanged:self];
}
@@ -183,7 +152,7 @@ var CPMenuItemStringRepresentationDictionary = [CPDictionary dictionary];
{
if (_isHidden == isHidden)
return;
_isHidden = isHidden;
[_menu itemChanged:self];
@@ -204,9 +173,9 @@ var CPMenuItemStringRepresentationDictionary = [CPDictionary dictionary];
{
if (_isHidden)
return YES;
var supermenu = [_menu supermenu];
if ([[supermenu itemAtIndex:[supermenu indexOfItemWithSubmenu:_menu]] isHiddenOrHasHiddenAncestor])
return YES;
@@ -259,11 +228,11 @@ var CPMenuItemStringRepresentationDictionary = [CPDictionary dictionary];
if (_title == aTitle)
return;
_title = aTitle;
[_menuItemView setDirty];
[_menu itemChanged:self];
}
@@ -291,11 +260,11 @@ var CPMenuItemStringRepresentationDictionary = [CPDictionary dictionary];
{
if (_font == aFont)
return;
_font = aFont;
[_menu itemChanged:self];
[_menuItemView setDirty];
}
@@ -347,9 +316,9 @@ CPOffState
{
if (_state == aState)
return;
_state = aState;
[_menu itemChanged:self];
[_menuItemView setDirty];
@@ -377,11 +346,11 @@ CPOffState
{
if (_image == anImage)
return;
_image = anImage;
[_menuItemView setDirty];
[_menu itemChanged:self];
}
@@ -419,7 +388,7 @@ CPOffState
{
if (_onStateImage == anImage)
return;
_onStateImage = anImage;
[_menu itemChanged:self];
}
@@ -440,7 +409,7 @@ CPOffState
{
if (_offStateImage == anImage)
return;
_offStateImage = anImage;
[_menu itemChanged:self];
}
@@ -461,7 +430,7 @@ CPOffState
{
if (_mixedStateImage == anImage)
return;
_mixedStateImage = anImage;
[_menu itemChanged:self];
}
@@ -475,7 +444,7 @@ CPOffState
return _mixedStateImage;
}
// Managing Submenus
// Managing Subemenus
/*!
Sets the submenu for this item
@param aMenu the submenu
@@ -489,7 +458,7 @@ CPOffState
if (supermenu)
[CPException raise:CPInvalidArgumentException
reason: @"Can't add submenu \"" + [aMenu title] + "\" to item \"" + [self title] + "\", because it is already submenu of \"" + [[aMenu supermenu] title] + "\""];
reason: @"Can't add submenu \"" + [aMenu title] + "\" to item \"" + [self title] + "\", because it is already submenu of \"" + [[aMenu supermenu] title] + "\""];
_submenu = aMenu;
@@ -622,25 +591,21 @@ CPControlKeyMask
return @"";
var string = _keyEquivalent.toUpperCase(),
needsShift = _keyEquivalentModifierMask & CPShiftKeyMask ||
(string === _keyEquivalent && _keyEquivalent.toLowerCase() !== _keyEquivalent.toUpperCase());
if ([CPMenuItemStringRepresentationDictionary objectForKey:string])
string = [CPMenuItemStringRepresentationDictionary objectForKey:string];
needsShift = _keyEquivalentModifierMask & CPShiftKeyMask || string === _keyEquivalent;
if (CPBrowserIsOperatingSystem(CPMacOperatingSystem))
{
if (_keyEquivalentModifierMask & CPCommandKeyMask)
string = "\u2318" + string;
string = "" + string;
if (needsShift)
string = "\u21E7" + string;
string = "" + string;
if (_keyEquivalentModifierMask & CPAlternateKeyMask)
string = "\u2325" + string;
string = "" + string;
if (_keyEquivalentModifierMask & CPControlKeyMask)
string = "\u2303" + string;
string = "^" + string;
}
else
{
@@ -677,20 +642,20 @@ CPControlKeyMask
}
/*!
Sets the title of the menu item and the mnemonic character. The mnemonic character should be preceded by an '&'.
Sets the title of the menu item and the mnemonic character. The mnemonic chracter should be preceded by an '&'.
@param aTitle the title string with a denoted mnemonic
*/
- (void)setTitleWithMnemonicLocation:(CPString)aTitle
{
var location = [aTitle rangeOfString:@"&"].location;
if (location == CPNotFound)
[self setTitle:aTitle];
else
{
[self setTitle:[aTitle substringToIndex:location] + [aTitle substringFromIndex:location + 1]];
[self setMnemonicLocation:location];
}
}
}
/*!
@@ -731,7 +696,7 @@ CPControlKeyMask
{
if (aLevel < 0)
[CPException raise:CPInvalidArgumentException reason:"setIndentationLevel: argument must be greater than or equal to 0."];
_indentationLevel = MIN(15, aLevel);
}
@@ -790,11 +755,11 @@ CPControlKeyMask
{
if (_view === aView)
return;
_view = aView;
[_menuItemView setDirty];
[_menu itemChanged:self];
}
@@ -816,48 +781,7 @@ 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
@@ -866,7 +790,7 @@ CPControlKeyMask
{
if (!_menuItemView)
_menuItemView = [[_CPMenuItemView alloc] initWithFrame:CGRectMakeZero() forMenuItem:self];
return _menuItemView;
}
@@ -880,11 +804,6 @@ CPControlKeyMask
return ![self submenu] && [self menu] === [CPApp mainMenu];
}
- (CPString)description
{
return [super description] + @" target: " + [self target] + @" action: " + CPStringFromSelector([self action]);
}
@end
var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
@@ -925,16 +844,15 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
if (self)
{
_changeCount = 0;
_isSeparator = [aCoder containsValueForKey:CPMenuItemIsSeparatorKey] && [aCoder decodeBoolForKey:CPMenuItemIsSeparatorKey];
_title = [aCoder decodeObjectForKey:CPMenuItemTitleKey];
// _font;
_target = [aCoder decodeObjectForKey:CPMenuItemTargetKey];
_action = [aCoder decodeObjectForKey:CPMenuItemActionKey];
@@ -942,6 +860,7 @@ 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);
@@ -968,7 +887,7 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
_representedObject = DEFAULT_VALUE(CPMenuItemRepresentedObjectKey, nil);
_view = DEFAULT_VALUE(CPMenuItemViewKey, nil);
}
return self;
}
@@ -982,11 +901,11 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
[aCoder encodeBool:_isSeparator forKey:CPMenuItemIsSeparatorKey];
[aCoder encodeObject:_title forKey:CPMenuItemTitleKey];
[aCoder encodeObject:_target forKey:CPMenuItemTargetKey];
[aCoder encodeObject:_action forKey:CPMenuItemActionKey];
ENCODE_IFNOT(CPMenuItemIsEnabledKey, _isEnabled, YES);
ENCODE_IFNOT(CPMenuItemIsEnabledKey, _isEnabled, YES);
ENCODE_IFNOT(CPMenuItemIsHiddenKey, _isHidden, NO);
ENCODE_IFNOT(CPMenuItemTagKey, _tag, 0);
@@ -994,7 +913,7 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
ENCODE_IFNOT(CPMenuItemImageKey, _image, nil);
ENCODE_IFNOT(CPMenuItemAlternateImageKey, _alternateImage, nil);
ENCODE_IFNOT(CPMenuItemSubmenuKey, _submenu, nil);
ENCODE_IFNOT(CPMenuItemMenuKey, _menu, nil);
+8 -12
View File
@@ -1,6 +1,3 @@
@import "CPView.j"
var HORIZONTAL_MARGIN = 8.0,
SUBMENU_INDICATOR_MARGIN = 3.0,
VERTICAL_MARGIN = 4.0;
@@ -9,7 +6,7 @@ var SelectionColor = nil,
SUBMENU_INDICATOR_COLOR = nil,
_CPMenuItemSelectionColor = nil,
_CPMenuItemTextShadowColor = nil,
_CPMenuItemDefaultStateImages = [],
_CPMenuItemDefaultStateHighlightedImages = [];
@@ -40,7 +37,7 @@ var SelectionColor = nil,
_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];
_CPMenuItemDefaultStateImages[CPOffState] = nil;
_CPMenuItemDefaultStateHighlightedImages[CPOffState] = nil;
@@ -65,7 +62,6 @@ 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];
@@ -141,7 +137,7 @@ var SelectionColor = nil,
imageAndTextViewFrame.origin.y = FLOOR((height - CGRectGetHeight(imageAndTextViewFrame)) / 2.0);
[_imageAndTextView setFrame:imageAndTextViewFrame];
if (hasSubmenuIndicator)
{
submenuViewFrame.origin.y = FLOOR((height - CGRectGetHeight(submenuViewFrame)) / 2.0) + 1.0;
@@ -149,7 +145,7 @@ var SelectionColor = nil,
}
_minSize = CGSizeMake(x + HORIZONTAL_MARGIN, height);
[self setAutoresizesSubviews:NO];
[self setFrameSize:_minSize];
[self setAutoresizesSubviews:YES];
@@ -218,19 +214,19 @@ var SelectionColor = nil,
{
var context = [[CPGraphicsContext currentContext] graphicsPort],
bounds = [self bounds];
bounds.size.height -= 1.0;
bounds.size.width -= 2.0;
bounds.origin.x += 1.0;
CGContextBeginPath(context);
CGContextMoveToPoint(context, CGRectGetMinX(bounds), CGRectGetMinY(bounds));
CGContextAddLineToPoint(context, CGRectGetMaxX(bounds), CGRectGetMinY(bounds));
CGContextAddLineToPoint(context, CGRectGetMidX(bounds), CGRectGetMaxY(bounds));
CGContextClosePath(context);
CGContextSetShadowWithColor(context, CGSizeMake(0.0, 1.0), 1.1, _shadowColor || [CPColor whiteColor]);
CGContextSetFillColor(context, _color || [CPColor blackColor]);
CGContextFillPath(context);
+3 -3
View File
@@ -1,5 +1,5 @@
@import "CPView.j"
@import <AppKit/CPView.j>
@implementation _CPMenuItemSeparatorView : CPView
@@ -27,10 +27,10 @@
bounds = [self bounds];
CGContextBeginPath(context);
CGContextMoveToPoint(context, CGRectGetMinX(bounds), FLOOR(CGRectGetMidY(bounds)) - 0.5);
CGContextAddLineToPoint(context, CGRectGetMaxX(bounds), FLOOR(CGRectGetMidY(bounds)) - 0.5);
CGContextSetStrokeColor(context, [CPColor lightGrayColor]);
CGContextStrokePath(context);
}
+5 -11
View File
@@ -1,6 +1,3 @@
@import "CPControl.j"
var LEFT_MARGIN = 3.0,
RIGHT_MARGIN = 14.0 + 3.0,
STATE_COLUMN_WIDTH = 14.0,
@@ -42,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];
@@ -260,13 +257,10 @@ var SUBMENU_INDICATOR_COLOR = nil,
[_keyEquivalentView setTextShadowColor:[self textShadowColor]];
}
if ([[_menuItem menu] showsStateColumn])
{
if (shouldHighlight)
[_stateView setImage:_CPMenuItemDefaultStateHighlightedImages[[_menuItem state]] || nil];
else
[_stateView setImage:_CPMenuItemDefaultStateImages[[_menuItem state]] || nil];
}
if (shouldHighlight)
[_stateView setImage:_CPMenuItemDefaultStateHighlightedImages[[_menuItem state]] || nil];
else
[_stateView setImage:_CPMenuItemDefaultStateImages[[_menuItem state]] || nil];
}
@end
+20 -21
View File
@@ -1,6 +1,4 @@
@import <AppKit/CPControl.j>
@import "_CPMenuItemSeparatorView.j"
@import "_CPMenuItemStandardView.j"
@import "_CPMenuItemMenuBarView.j"
@@ -11,10 +9,10 @@ var LEFT_MARGIN = 3.0,
STATE_COLUMN_WIDTH = 14.0,
INDENTATION_WIDTH = 17.0,
VERTICAL_MARGIN = 4.0;
var _CPMenuItemSelectionColor = nil,
_CPMenuItemTextShadowColor = nil,
_CPMenuItemDefaultStateImages = [],
_CPMenuItemDefaultStateHighlightedImages = [];
@@ -34,6 +32,7 @@ var _CPMenuItemSelectionColor = nil,
BOOL _isDirty;
BOOL _showsStateColumn;
CPImageView _stateView;
_CPImageAndTextView _imageAndTextView;
CPView _submenuView;
}
@@ -42,12 +41,12 @@ var _CPMenuItemSelectionColor = nil,
{
if (self != [_CPMenuItemView class])
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];
_CPMenuItemDefaultStateImages[CPOffState] = nil;
_CPMenuItemDefaultStateHighlightedImages[CPOffState] = nil;
@@ -72,12 +71,12 @@ var _CPMenuItemSelectionColor = nil,
_menuItem = aMenuItem;
_showsStateColumn = YES;
_isDirty = YES;
[self setAutoresizingMask:CPViewWidthSizable];
[self synchronizeWithMenuItem];
}
return self;
}
@@ -111,7 +110,7 @@ var _CPMenuItemSelectionColor = nil,
_view = menuItemView;
}
}
else if ([_menuItem menu] == [CPApp mainMenu])
{
if (![_view isKindOfClass:[_CPMenuItemMenuBarView class]])
@@ -129,7 +128,7 @@ var _CPMenuItemSelectionColor = nil,
[_view removeFromSuperview];
_view = [_CPMenuItemStandardView view];
}
[_view setMenuItem:_menuItem];
}
@@ -160,7 +159,7 @@ var _CPMenuItemSelectionColor = nil,
{
if (![_menuItem hasSubmenu])
return NO;
return CGRectContainsPoint([_submenuView frame], [self convertPoint:[anEvent locationInWindow] fromView:nil]);
}
@@ -191,7 +190,7 @@ var _CPMenuItemSelectionColor = nil,
{
if (_textColor == aColor)
return;
_textColor = aColor;
[_imageAndTextView setTextColor:[self textColor]];
@@ -207,7 +206,7 @@ var _CPMenuItemSelectionColor = nil,
{
if (_textShadowColor == aColor)
return;
_textShadowColor = aColor;
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
@@ -232,25 +231,25 @@ var _CPMenuItemSelectionColor = nil,
return;
_color = aColor;
[self setNeedsDisplay:YES];
}
- (void)drawRect:(CGRect)aRect
{
var context = [[CPGraphicsContext currentContext] graphicsPort];
CGContextBeginPath(context);
CGContextMoveToPoint(context, 1.0, 4.0);
CGContextAddLineToPoint(context, 9.0, 4.0);
CGContextAddLineToPoint(context, 5.0, 8.0);
CGContextAddLineToPoint(context, 1.0, 4.0);
CGContextClosePath(context);
CGContextSetFillColor(context, _color);
CGContextFillPath(context);
}
@end
@end
-788
View File
@@ -1,788 +0,0 @@
/*
* CPObjectController.j
* AppKit
*
* Created by Ross Boucher.
* Copyright 2009, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPDictionary.j>
@import <Foundation/CPCountedSet.j>
@import "CPController.j"
/*!
@class
CPObjectController is a bindings-compatible controller class.
Properties of the content object of an object of this class can be bound to user interface elements to change and access their values.
The content of an CPObjectController instance is an CPMutableDictionary object by default.
This allows a single CPObjectController instance to be used to manage several properties accessed by key value paths.
The default content object class can be changed by calling setObjectClass:, which a subclass must override.
*/
@implementation CPObjectController : CPController
{
id _contentObject;
id _selection;
Class _objectClass;
CPString _objectClassName;
BOOL _isEditable;
BOOL _automaticallyPreparesContent;
CPCountedSet _observedKeys;
}
+ (id)initialize
{
[self exposeBinding:@"editable"];
[self exposeBinding:@"contentObject"];
}
+ (CPSet)keyPathsForValuesAffectingContentObject
{
return [CPSet setWithObjects:"content"];
}
+ (BOOL)automaticallyNotifiesObserversForKey:(CPString)aKey
{
if (aKey === @"contentObject")
return NO;
return YES;
}
+ (CPSet)keyPathsForValuesAffectingCanAdd
{
return [CPSet setWithObject:"editable"];
}
+ (CPSet)keyPathsForValuesAffectingCanInsert
{
return [CPSet setWithObject:"editable"];
}
+ (CPSet)keyPathsForValuesAffectingCanRemove
{
return [CPSet setWithObjects:"editable", "selection"];
}
/*!
@ignore
*/
- (id)init
{
return [self initWithContent:nil];
}
/*!
Inits and returns a CPObjectController object with the given content.
@param id aContent - The object the controller will use.
@return id the CPObjectConroller instance.
*/
- (id)initWithContent:(id)aContent
{
if (self = [super init])
{
[self setContent:aContent];
[self setEditable:YES];
[self setObjectClass:[CPMutableDictionary class]];
_observedKeys = [[CPCountedSet alloc] init];
}
return self;
}
/*!
Returns the controller's content object.
@return id - The content object of the controller.
*/
- (id)content
{
return _contentObject;
}
/*!
Sets the content object for the controller.
@param id aContent - The new content object for the controller.
*/
- (void)setContent:(id)aContent
{
[self willChangeValueForKey:@"contentObject"];
[self _selectionWillChange];
_contentObject = aContent;
[self didChangeValueForKey:@"contentObject"];
[self _selectionDidChange];
}
/*!
@ignore
*/
- (void)_setContentObject:(id)aContent
{
[self setContent:aContent];
}
/*!
@ignore
*/
- (id)_contentObject
{
return [self content];
}
/*!
Sets whether the controller automatically creates and inserts new content objects automatically when loading from a cib file.
If you pass YES and the controller uses prepareContent to create the content object.
The default is NO.
@param BOOL shouldAutomaticallyPrepareContent - YES if the content should be prepared, otherwise NO.
*/
- (void)setAutomaticallyPreparesContent:(BOOL)shouldAutomaticallyPrepareContent
{
_automaticallyPreparesContent = shouldAutomaticallyPrepareContent;
}
/*!
Returns if the controller prepares the content automatically.
@return BOOL - YES if the content is prepared, otherwise NO.
*/
- (BOOL)automaticallyPreparesContent
{
return _automaticallyPreparesContent;
}
/*!
Overridden by a subclass that require control over the creation of new objects.
*/
- (void)prepareContent
{
[self setContent:[self newObject]];
}
/*!
Sets the object class when creating new objects.
@param Class - the class of new objects that will be created.
*/
- (void)setObjectClass:(Class)aClass
{
_objectClass = aClass;
}
/*!
Returns the class of what new objects will be when they are created.
@return Class - The class of new objects.
*/
- (Class)objectClass
{
return _objectClass;
}
/*!
@ignore
*/
- (id)_defaultNewObject
{
return [[[self objectClass] alloc] init];
}
/*!
Creates and returns a new object of the appropriate class.
@return id - The object created.
*/
- (id)newObject
{
return [self _defaultNewObject];
}
/*!
Sets the controller's content object.
@param id anObject - The object to set for the controller.
*/
- (void)addObject:(id)anObject
{
[self setContent:anObject];
var binderClass = [[self class] _binderClassForBinding:@"contentObject"];
[[binderClass getBinding:@"contentObject" forObject:self] reverseSetValueFor:@"contentObject"];
}
/*!
Removes a given object from the controller.
@param id anObject - The object to remove from the receiver.
*/
- (void)removeObject:(id)anObject
{
if ([self content] === anObject)
[self setContent:nil];
var binderClass = [[self class] _binderClassForBinding:@"contentObject"];
[[binderClass getBinding:@"contentObject" forObject:self] reverseSetValueFor:@"contentObject"];
}
/*!
Creates and adds a sets the object as the controller's content.
@param id aSender - The sender of the message.
*/
- (void)add:(id)aSender
{
// FIXME: This should happen on the next run loop?
[self addObject:[self newObject]];
}
/*!
@return BOOL - YES if you can added to the controller using add:
*/
- (BOOL)canAdd
{
return [self isEditable];
}
/*!
Removes the content object from the controller.
@param id aSender - The sender of the message.
*/
- (void)remove:(id)aSender
{
// FIXME: This should happen on the next run loop?
[self removeObject:[self content]];
}
/*!
@return BOOL - Returns YES if you can remove the controller's content using remove:
*/
- (BOOL)canRemove
{
return [self isEditable] && [[self selectedObjects] count];
}
/*!
Sets whether the controller allows for the editing of the content.
@param BOOL shouldBeEditable - YES if the content should be editable, otherwise NO.
*/
- (void)setEditable:(BOOL)shouldBeEditable
{
_isEditable = shouldBeEditable;
}
/*!
@return BOOL - Returns YES if the content of the controller is editable, otherwise NO.
*/
- (BOOL)isEditable
{
return _isEditable;
}
/*!
@return CPArray - Returns an array of all objects to be affected by editing.
*/
- (CPArray)selectedObjects
{
return [[_CPObservableArray alloc] initWithArray:[_contentObject]];
}
/*!
Returns a proxy object representing the controller's selection.
*/
- (id)selection
{
return _selection;
}
/*!
@ignore
*/
- (void)_selectionWillChange
{
[_selection controllerWillChange];
[self willChangeValueForKey:@"selection"];
}
/*!
@ignore
*/
- (void)_selectionDidChange
{
if (_selection === undefined || _selection === nil)
_selection = [[CPControllerSelectionProxy alloc] initWithController:self];
[_selection controllerDidChange];
[self didChangeValueForKey:@"selection"];
}
/*!
@return id - Returns the keys which are being observed.
*/
- (id)observedKeys
{
return _observedKeys;
}
- (void)addObserver:(id)anObserver forKeyPath:(CPString)aKeyPath options:(CPKeyValueObservingOptions)options context:(id)context
{
[_observedKeys addObject:aKeyPath];
[super addObserver:anObserver forKeyPath:aKeyPath options:options context:context];
}
- (void)removeObserver:(id)anObserver forKeyPath:(CPString)aKeyPath
{
[_observedKeys removeObject:aKeyPath];
[super removeObserver:anObserver forKeyPath:aKeyPath];
}
@end
var CPObjectControllerContentKey = @"CPObjectControllerContentKey",
CPObjectControllerObjectClassNameKey = @"CPObjectControllerObjectClassNameKey",
CPObjectControllerIsEditableKey = @"CPObjectControllerIsEditableKey",
CPObjectControllerAutomaticallyPreparesContentKey = @"CPObjectControllerAutomaticallyPreparesContentKey";
@implementation CPObjectController (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
if (self)
{
var objectClassName = [aCoder decodeObjectForKey:CPObjectControllerObjectClassNameKey],
objectClass = CPClassFromString(objectClassName);
[self setObjectClass:objectClass || [CPMutableDictionary class]];
[self setEditable:[aCoder decodeBoolForKey:CPObjectControllerIsEditableKey]];
[self setAutomaticallyPreparesContent:[aCoder decodeBoolForKey:CPObjectControllerAutomaticallyPreparesContentKey] || NO];
[self setContent:[aCoder decodeObjectForKey:CPObjectControllerContentKey]];
_observedKeys = [[CPCountedSet alloc] init];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[aCoder encodeObject:[self content] forKey:CPObjectControllerContentKey];
if (_objectClass)
[aCoder encodeObject:CPStringFromClass(_objectClass) forKey:CPObjectControllerObjectClassNameKey];
else if (_objectClassName)
[aCoder encodeObject:_objectClassName forKey:CPObjectControllerObjectClassNameKey];
[aCoder encodeBool:[self isEditable] forKey:CPObjectControllerIsEditableKey];
[aCoder encodeBool:[self automaticallyPreparesContent] forKey:CPObjectControllerAutomaticallyPreparesContentKey];
}
- (void)awakeFromCib
{
if (![self content] && [self automaticallyPreparesContent])
[self prepareContent];
}
@end
@implementation _CPObservationProxy : CPObject
{
id _keyPath;
id _observer;
id _object;
BOOL _notifyObject;
id _context;
int _options;
}
- (id)initWithKeyPath:(id)aKeyPath observer:(id)anObserver object:(id)anObject
{
if (self = [super init])
{
_keyPath = aKeyPath;
_observer = anObserver;
_object = anObject;
}
return self;
}
- (id)observer
{
return _observer;
}
- (id)keyPath
{
return _keyPath;
}
- (id)context
{
return _context;
}
- (int)options
{
return _options;
}
- (void)setNotifyObject:(BOOL)notify
{
_notifyObject = notify;
}
- (BOOL)isEqual:(id)anObject
{
if ([anObject class] === [self class])
{
if (anObject._observer === _observer && [anObject._keyPath isEqual:_keyPath] && [anObject._object isEqual:_object])
return YES;
}
return NO;
}
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)change context:(id)context
{
if (_notifyObject)
[_object observeValueForKeyPath:aKeyPath ofObject:_object change:change context:context];
[_observer observeValueForKeyPath:aKeyPath ofObject:_object change:change context:context];
}
- (CPString)description
{
return [super description] + [CPString stringWithFormat:@"observation proxy for %@ on key path %@", _observer, _keyPath];
}
@end
// FIXME: This should subclass CPMutableArray not _CPJavaScriptArray
@implementation _CPObservableArray : _CPJavaScriptArray
{
CPArray _observationProxies;
}
+ (id)alloc
{
var a = [];
a.isa = self;
var ivars = class_copyIvarList(self),
count = ivars.length;
while (count--)
a[ivar_getName(ivars[count])] = nil;
return a;
}
- (CPString)description
{
return "<_CPObservableArray: "+[super description]+" >";
}
- (id)initWithArray:(CPArray)anArray
{
self = [super initWithArray:anArray];
self.isa = [_CPObservableArray class];
self._observationProxies = [];
return self;
}
- (void)addObserver:(id)anObserver forKeyPath:(CPString)aKeyPath options:(CPKeyValueObservingOptions)options context:(id)context
{
if (aKeyPath.indexOf("@") === 0)
{
var proxy = [[_CPObservationProxy alloc] initWithKeyPath:aKeyPath observer:anObserver object:self];
proxy._options = options;
proxy._context = context;
[_observationProxies addObject:proxy];
var dotIndex = aKeyPath.indexOf("."),
remaining = aKeyPath.substring(dotIndex + 1),
indexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [self count])];
[self addObserver:proxy toObjectsAtIndexes:indexes forKeyPath:remaining options:options context:context];
}
else
{
var indexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [self count])];
[self addObserver:anObserver toObjectsAtIndexes:indexes forKeyPath:aKeyPath options:options context:context];
}
}
- (void)removeObserver:(id)anObserver forKeyPath:(CPString)aKeyPath
{
if (aKeyPath.indexOf("@") === 0)
{
var proxy = [[_CPObservationProxy alloc] initWithKeyPath:aKeyPath observer:anObserver object:self],
index = [_observationProxies indexOfObject:proxy];
proxy = [_observationProxies objectAtIndex:index];
var dotIndex = aKeyPath.indexOf("."),
remaining = aKeyPath.substring(dotIndex + 1),
indexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [self count])];
[self removeObserver:proxy fromObjectsAtIndexes:indexes forKeyPath:remaining];
}
else
{
var indexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [self count])];
[self removeObserver:anObserver fromObjectsAtIndexes:indexes forKeyPath:aKeyPath];
}
}
- (void)insertObject:(id)anObject atIndex:(unsigned)anIndex
{
for (var i = 0, count = [_observationProxies count]; i < count; i++)
{
var proxy = [_observationProxies objectAtIndex:i],
keyPath = [proxy keyPath],
operator = keyPath.indexOf(".") === 0;
if (operator)
[self willChangeValueForKey:keyPath];
[anObject addObserver:proxy forKeyPath:keyPath options:[proxy options] context:[proxy context]];
if (operator)
[self didChangeValueForKey:keyPath];
}
[super insertObject:anObject atIndex:anIndex];
}
- (void)removeObjectAtIndex:(unsigned)anIndex
{
for (var i = 0, count = [_observationProxies count]; i < count; i++)
{
var proxy = [_observationProxies objectAtIndex:i],
keyPath = [proxy keyPath],
operator = keyPath.indexOf(".") === 0;
if (operator)
[self willChangeValueForKey:keyPath];
[anObject removeObserver:proxy forKeyPath:keyPath];
if (operator)
[self didChangeValueForKey:keyPath];
}
[super removeObjectAtIndex:anIndex];
}
- (_CPObservableArray)objectsAtIndexes:(CPIndexSet)theIndexes
{
return [_CPObservableArray arrayWithArray:[super objectsAtIndexes:theIndexes]];
}
- (void)addObject:(id)anObject
{
[self insertObject:anObject atIndex:[self count]];
}
- (void)removeLastObject
{
[self removeObjectAtIndex:[self count]];
}
- (void)replaceObjectAtIndex:(unsigned)anIndex withObject:(id)anObject
{
var currentObject = [self objectAtIndex:anIndex];
for (var i = 0, count = [_observationProxies count]; i < count; i++)
{
var proxy = [_observationProxies objectAtIndex:i],
keyPath = [proxy keyPath],
operator = keyPath.indexOf(".") === 0;
if (operator)
[self willChangeValueForKey:keyPath];
[currentObject removeObserver:proxy forKeyPath:keyPath];
[anObject addObserver:proxy forKeyPath:keyPath options:[proxy options] context:[proxy context]];
if (operator)
[self didChangeValueForKey:keyPath];
}
[super replaceObjectAtIndex:anIndex withObject:anObject];
}
@end
@implementation CPControllerSelectionProxy : CPObject
{
id _controller;
id _keys;
CPDictionary _cachedValues;
CPArray _observationProxies;
Object _observedObjectsByKeyPath;
}
- (id)initWithController:(id)aController
{
if (self = [super init])
{
_cachedValues = [CPDictionary dictionary];
_observationProxies = [CPArray array];
_controller = aController;
_observedObjectsByKeyPath = {};
}
return self;
}
- (id)_controllerMarkerForValues:(CPArray)theValues
{
var count = [theValues count];
if (!count)
value = CPNoSelectionMarker;
else if (count === 1)
value = [theValues objectAtIndex:0];
else
{
if ([_controller alwaysUsesMultipleValuesMarker])
value = CPMultipleValuesMarker;
else
{
value = [theValues objectAtIndex:0];
for (var i = 0, count= [theValues count]; i < count && value != CPMultipleValuesMarker; i++)
{
if (![value isEqual:[theValues objectAtIndex:i]])
value = CPMultipleValuesMarker;
}
}
}
if (value === nil || value.isa && [value isEqual:[CPNull null]])
value = CPNullMarker;
return value;
}
- (id)valueForKeyPath:(CPString)theKeyPath
{
var values = [[_controller selectedObjects] valueForKeyPath:theKeyPath];
value = [self _controllerMarkerForValues:values];
[_cachedValues setObject:value forKey:theKeyPath];
return value;
}
- (id)valueForKey:(CPString)theKeyPath
{
return [self valueForKeyPath:theKeyPath];
}
- (void)setValue:(id)theValue forKeyPath:(CPString)theKeyPath
{
[[_controller selectedObjects] setValue:theValue forKeyPath:theKeyPath];
[_cachedValues removeObjectForKey:theKeyPath];
}
- (void)setValue:(id)theValue forKey:(CPString)theKeyPath
{
[self setValue:theKeyPath forKeyPath:theKeyPath];
}
- (unsigned)count
{
return [_cachedValues count];
}
- (id)keyEnumerator
{
return [_cachedValues keyEnumerator];
}
- (void)controllerWillChange
{
_keys = [_cachedValues allKeys];
if (!_keys)
return;
for (var i = 0, count = _keys.length; i < count; i++)
[self willChangeValueForKey:_keys[i]];
[_cachedValues removeAllObjects];
}
- (void)controllerDidChange
{
[_cachedValues removeAllObjects];
if (!_keys)
return;
for (var i = 0, count = _keys.length; i < count; i++)
[self didChangeValueForKey:_keys[i]];
_keys = nil;
}
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)change context:(id)context
{
[_cachedValues removeObjectForKey:aKeyPath];
}
- (void)addObserver:(id)anObject forKeyPath:(CPString)aKeyPath options:(CPKeyValueObservingOptions)options context:(id)context
{
var proxy = [[_CPObservationProxy alloc] initWithKeyPath:aKeyPath observer:anObject object:self];
[proxy setNotifyObject:YES];
[_observationProxies addObject:proxy];
// We keep are reference to the observed objects
// because the removeObserver: will be called after the selection changes
var observedObjects = [_controller selectedObjects];
_observedObjectsByKeyPath[aKeyPath] = observedObjects;
[observedObjects addObserver:proxy forKeyPath:aKeyPath options:options context:context];
}
- (void)removeObserver:(id)anObject forKeyPath:(CPString)aKeyPath
{
var proxy = [[_CPObservationProxy alloc] initWithKeyPath:aKeyPath observer:anObject object:self],
index = [_observationProxies indexOfObject:proxy];
var observedObjects = _observedObjectsByKeyPath[aKeyPath];
[observedObjects removeObserver:[_observationProxies objectAtIndex:index] forKeyPath:aKeyPath];
[_observationProxies removeObjectAtIndex:index];
_observedObjects = nil;
}
@end
+1 -22
View File
@@ -1,26 +1,5 @@
/*
* CPOpenPanel.j
* AppKit
*
* Created by Ross Boucher.
* Copyright 2009, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPPanel.j"
@import <AppKit/CPPanel.j>
@implementation CPOpenPanel : CPPanel
+129 -989
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -26,7 +26,7 @@
CPOKButton = 1;
CPCancelButton = 0;
/*!
/*!
@ingroup appkit
@class CPPanel
@@ -51,7 +51,7 @@ CPCancelButton = 0;
@global
@class CPWindow
*/
CPDocModalWindowMask = 1 << 6;
CPDocModalWindowMask = 1 << 6;
@implementation CPPanel : CPWindow
{
+26 -24
View File
@@ -25,6 +25,8 @@
@import <Foundation/CPDictionary.j>
@import <Foundation/CPPropertyListSerialization.j>
#include "Platform/Platform.h"
CPGeneralPboard = @"CPGeneralPboard";
CPFontPboard = @"CPFontPboard";
@@ -50,18 +52,18 @@ CPImagePboardType = @"CPImagePboardType";
var CPPasteboards = nil,
supportsNativePasteboard = NO;
/*!
/*!
@ingroup appkit
@class CPPasteboard
CPPasteBoard is the object responsible for cut/copy/paste and drag&drop operations.
CPPasteBoard is the object responsible for cut/copy/paste and drag&drop operations.
*/
@implementation CPPasteboard : CPObject
{
CPArray _types;
CPDictionary _owners;
CPDictionary _provided;
unsigned _changeCount;
CPString _stateUID;
@@ -77,7 +79,7 @@ var CPPasteboards = nil,
return;
[self setVersion:1.0];
CPPasteboards = [CPDictionary dictionary];
if (typeof window.cpPasteboardWithName !== "undefined")
@@ -103,10 +105,10 @@ var CPPasteboards = nil,
if (pasteboard)
return pasteboard;
pasteboard = [[CPPasteboard alloc] _initWithName:aName];
[CPPasteboards setObject:pasteboard forKey:aName];
return pasteboard;
}
@@ -114,15 +116,15 @@ var CPPasteboards = nil,
- (id)_initWithName:(CPString)aName
{
self = [super init];
if (self)
{
_name = aName;
_types = [];
_owners = [CPDictionary dictionary];
_provided = [CPDictionary dictionary];
_changeCount = 0;
if (supportsNativePasteboard)
@@ -131,7 +133,7 @@ var CPPasteboards = nil,
[self _synchronizePasteboard];
}
}
return self;
}
@@ -145,17 +147,17 @@ var CPPasteboards = nil,
{
var i = 0,
count = types.length;
for (; i < count; ++i)
{
var type = types[i];
if (![_owners objectForKey:type])
if(![_owners objectForKey:type])
{
[_types addObject:type];
[_provided removeObjectForKey:type];
}
[_owners setObject:anOwner forKey:type];
}
@@ -191,7 +193,7 @@ var CPPasteboards = nil,
_provided = [CPDictionary dictionary];
var count = _types.length;
while (count--)
[_owners setObject:anOwner forKey:_types[count]];
@@ -283,18 +285,18 @@ var CPPasteboards = nil,
- (CPData)dataForType:(CPString)aType
{
var data = [_provided objectForKey:aType];
if (data)
return data;
var owner = [_owners objectForKey:aType];
if (owner)
{
[owner pasteboard:self provideDataForType:aType];
[owner pasteboard:self provideDataForType:aType];
return [_provided objectForKey:aType];
}
if (aType === CPStringPboardType)
return [self dataForType:UTF8PboardType];
@@ -339,10 +341,10 @@ var CPPasteboards = nil,
- (id)propertyListForType:(CPString)aType
{
var data = [self dataForType:aType];
if (data)
return [CPPropertyListSerialization propertyListFromData:data format:CPPropertyList280NorthFormat_v1_0];
return nil;
}
@@ -360,9 +362,9 @@ var CPPasteboards = nil,
- (CPString)_generateStateUID
{
var bits = 32;
_stateUID = @"";
while (bits--)
_stateUID += FLOOR(RAND() * 16.0).toString(16).toUpperCase();
+219 -273
View File
@@ -25,12 +25,14 @@
@import "CPMenu.j"
@import "CPMenuItem.j"
#include "CoreGraphics/CGGeometry.h"
var VISIBLE_MARGIN = 7.0;
var VISIBLE_MARGIN = 7.0;
CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
/*!
/*!
@ingroup appkit
@class CPPopUpButton
@@ -38,30 +40,17 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
@implementation CPPopUpButton : CPButton
{
CPUInteger _selectedIndex;
int _selectedIndex;
CPRectEdge _preferredEdge;
CPMenu _menu;
}
+ (CPString)defaultThemeClass
+ (CPString)themeClass
{
return "popup-button";
}
+ (CPSet)keyPathsForValuesAffectingSelectedIndex
{
return [CPSet setWithObject:@"objectValue"];
}
+ (CPSet)keyPathsForValuesAffectingSelectedTag
{
return [CPSet setWithObject:@"objectValue"];
}
+ (CPSet)keyPathsForValuesAffectingSelectedItem
{
return [CPSet setWithObject:@"objectValue"];
}
/*!
Initializes the pop-up button to the specified size.
@param aFrame the size for the button
@@ -71,27 +60,21 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
- (id)initWithFrame:(CGRect)aFrame pullsDown:(BOOL)shouldPullDown
{
self = [super initWithFrame:aFrame];
if (self)
{
[self selectItemAtIndex:CPNotFound];
_selectedIndex = CPNotFound;
_preferredEdge = CPMaxYEdge;
[self setValue:CPImageLeft forThemeAttribute:@"image-position"];
[self setValue:CPLeftTextAlignment forThemeAttribute:@"alignment"];
[self setValue:CPLineBreakByTruncatingTail forThemeAttribute:@"line-break-mode"];
[self setMenu:[[CPMenu alloc] initWithTitle:@""]];
[self setPullsDown:shouldPullDown];
var options = CPKeyValueObservingOptionNew |CPKeyValueObservingOptionOld;/* |CPKeyValueObservingOptionInitial;*/
[self addObserver:self forKeyPath:@"menu.items" options:options context:nil];
[self addObserver:self forKeyPath:@"_firstItem.changeCount" options:options context:nil];
[self addObserver:self forKeyPath:@"selectedItem.changeCount" options:options context:nil];
}
return self;
}
@@ -104,9 +87,6 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
/*!
Specifies whether the object is a pull-down or a pop-up menu.
If the button pulls down the menu items represent actions, not states.
So the text in the button will NOT change when the user selects something different.
@param shouldPullDown \c YES makes the pop-up button
a pull-down menu. \c NO makes it a pop-up menu.
*/
@@ -120,7 +100,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
if (!changed)
return;
var items = [[self menu] itemArray];
var items = [_menu itemArray];
if ([items count] <= 0)
return;
@@ -145,46 +125,46 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (void)addItem:(CPMenuItem)anItem
{
[[self menu] addItem:anItem];
[_menu addItem:anItem];
}
/*!
Adds a new menu item with the specified title.
@param the new menu item's title
@param the new menu item's tite
*/
- (void)addItemWithTitle:(CPString)aTitle
{
[[self menu] addItemWithTitle:aTitle action:NULL keyEquivalent:nil];
[_menu addItemWithTitle:aTitle action:NULL keyEquivalent:nil];
}
/*!
Adds multiple new menu items with the titles specified in the provided array.
@param titles an array of names for the new items
@param titles an arry of names for the new items
*/
- (void)addItemsWithTitles:(CPArray)titles
{
var index = 0,
count = [titles count];
for (; index < count; ++index)
[self addItemWithTitle:titles[index]];
}
/*!
Inserts a new item with the specified title and index location.
@param aTitle the new item's title
@param aTitle the new itme's title
@param anIndex the item's index in the menu
*/
- (void)insertItemWithTitle:(CPString)aTitle atIndex:(int)anIndex
{
var items = [self itemArray],
count = [items count];
while (count--)
if ([items[count] title] == aTitle)
[self removeItemAtIndex:count];
[[self menu] insertItemWithTitle:aTitle action:NULL keyEquivalent:nil atIndex:anIndex];
[_menu insertItemWithTitle:aTitle action:NULL keyEquivalent:nil atIndex:anIndex];
}
/*!
@@ -192,7 +172,10 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (void)removeAllItems
{
[[self menu] removeAllItems];
var count = [_menu numberOfItems];
while (count--)
[_menu removeItemAtIndex:0];
}
/*!
@@ -211,7 +194,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (void)removeItemAtIndex:(int)anIndex
{
[[self menu] removeItemAtIndex:anIndex];
[_menu removeItemAtIndex:anIndex];
[self synchronizeTitleAndSelectedItem];
}
@@ -221,12 +204,10 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (CPMenuItem)selectedItem
{
var indexOfSelectedItem = [self indexOfSelectedItem];
if (indexOfSelectedItem < 0 || indexOfSelectedItem > [self numberOfItems] - 1)
if (_selectedIndex < 0 || _selectedIndex > [self numberOfItems] - 1)
return nil;
return [[self menu] itemAtIndex:indexOfSelectedItem];
return [_menu itemAtIndex:_selectedIndex];
}
/*!
@@ -245,20 +226,13 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
return _selectedIndex;
}
// For us, CPNumber is toll-free bridged to Number, so just return the selected index.
/*!
@ignore
Returns the selected item's index. If no item is selected, it returns CPNotFound.
*/
- (int)selectedTag
- (id)objectValue
{
return [[self selectedItem] tag];
}
/*!
@ignore
*/
- (void)_setSelectedTag:(int)aTag
{
[self selectItemWithTag:aTag];
return _selectedIndex;
}
// Setting the Current Selection
@@ -275,50 +249,22 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
Selects the item at the specified index
@param anIndex the index of the item to select
*/
- (void)selectItemAtIndex:(CPUInteger)anIndex
- (void)selectItemAtIndex:(int)anIndex
{
[self setObjectValue:anIndex];
}
- (void)setSelectedIndex:(CPUInteger)anIndex
{
[self setObjectValue:anIndex];
}
- (CPUInteger)selectedIndex
{
return [self objectValue];
}
/*!
Selects the item at the specified index
@param anIndex the index of the item to select
*/
- (void)setObjectValue:(int)anIndex
{
var indexOfSelectedItem = [self objectValue];
anIndex = parseInt(+anIndex, 10);
if (indexOfSelectedItem === anIndex)
if (_selectedIndex == anIndex)
return;
if (indexOfSelectedItem >= 0 && ![self pullsDown])
if (_selectedIndex >= 0 && ![self pullsDown])
[[self selectedItem] setState:CPOffState];
_selectedIndex = anIndex;
if (indexOfSelectedItem >= 0 && ![self pullsDown])
if (_selectedIndex >= 0 && ![self pullsDown])
[[self selectedItem] setState:CPOnState];
[self synchronizeTitleAndSelectedItem];
}
- (id)objectValue
{
return _selectedIndex;
}
/*!
Selects the menu item with the specified tag
@param the tag of the item to select
@@ -337,14 +283,84 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
[self selectItemAtIndex:[self indexOfItemWithTitle:aTitle]];
}
/*!
Sets the object for the selected item. If no item is selected, then this method has no effect.
@param the object set for the selected item
*/
- (void)setObjectValue:(id)aValue
{
[self selectItemAtIndex:[aValue intValue]];
}
// Getting Menu Items
/*!
Returns the button's menu of items.
*/
- (CPMenu)menu
{
return _menu;
}
/*!
Sets the menu for the button
*/
- (void)setMenu:(CPMenu)aMenu
{
if (_menu === aMenu)
return;
var defaultCenter = [CPNotificationCenter defaultCenter];
if (_menu)
{
[defaultCenter
removeObserver:self
name:CPMenuDidAddItemNotification
object:_menu];
[defaultCenter
removeObserver:self
name:CPMenuDidChangeItemNotification
object:_menu];
[defaultCenter
removeObserver:self
name:CPMenuDidRemoveItemNotification
object:_menu];
}
_menu = aMenu;
if (_menu)
{
[defaultCenter
addObserver:self
selector:@selector(menuDidAddItem:)
name:CPMenuDidAddItemNotification
object:_menu];
[defaultCenter
addObserver:self
selector:@selector(menuDidChangeItem:)
name:CPMenuDidChangeItemNotification
object:_menu];
[defaultCenter
addObserver:self
selector:@selector(menuDidRemoveItem:)
name:CPMenuDidRemoveItemNotification
object:_menu];
}
[self synchronizeTitleAndSelectedItem];
}
/*!
Returns a count of the number of items in the button's menu.
*/
- (int)numberOfItems
{
return [[self menu] numberOfItems];
return [_menu numberOfItems];
}
/*!
@@ -352,7 +368,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (CPArray)itemArray
{
return [[self menu] itemArray];
return [_menu itemArray];
}
/*!
@@ -361,7 +377,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (CPMenuItem)itemAtIndex:(unsigned)anIndex
{
return [[self menu] itemAtIndex:anIndex];
return [_menu itemAtIndex:anIndex];
}
/*!
@@ -370,7 +386,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (CPString)itemTitleAtIndex:(unsigned)anIndex
{
return [[[self menu] itemAtIndex:anIndex] title];
return [[_menu itemAtIndex:anIndex] title];
}
/*!
@@ -380,13 +396,12 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
{
var titles = [],
items = [self itemArray],
index = 0,
count = [items count];
for (; index < count; ++index)
titles.push([items[index] title]);
return titles;
items.push([items[index] title]);
}
/*!
@@ -395,13 +410,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (CPMenuItem)itemWithTitle:(CPString)aTitle
{
var menu = [self menu],
itemIndex = [menu indexOfItemWithTitle:aTitle];
if (itemIndex === CPNotFound)
return nil;
return [menu itemAtIndex:itemIndex];
return [_menu itemAtIndex:[_menu indexOfItemWithTitle:aTitle]];
}
/*!
@@ -409,7 +418,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (CPMenuItem)lastItem
{
return [[[self menu] itemArray] lastObject];
return [[_menu itemArray] lastObject];
}
// Getting the Indices of Menu Items
@@ -419,7 +428,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (int)indexOfItem:(CPMenuItem)aMenuItem
{
return [[self menu] indexOfItem:aMenuItem];
return [_menu indexOfItem:aMenuItem];
}
/*!
@@ -428,16 +437,16 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (int)indexOfItemWithTag:(int)aTag
{
return [[self menu] indexOfItemWithTag:aTag];
return [_menu indexOfItemWithTag:aTag];
}
/*!
Returns the index of the item with the specified title or CPNotFound.
@param aTitle the item's title
@param aTitle the item's titel
*/
- (int)indexOfItemWithTitle:(CPString)aTitle
{
return [[self menu] indexOfItemWithTitle:aTitle];
return [_menu indexOfItemWithTitle:aTitle];
}
/*!
@@ -448,7 +457,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (int)indexOfItemWithRepresentedObject:(id)anObject
{
return [[self menu] indexOfItemWithRepresentedObject:anObject];
return [_menu indexOfItemWithRepresentedObject:anObject];
}
/*!
@@ -460,7 +469,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (int)indexOfItemWithTarget:(id)aTarget action:(SEL)anAction
{
return [[self menu] indexOfItemWithTarget:aTarget action:anAction];
return [_menu indexOfItemWithTarget:aTarget action:anAction];
}
// Setting the Cell Edge to Pop out in Restricted Situations
@@ -475,7 +484,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
}
/*!
Sets the preferred edge of the button to display the
Sets the preffered edge of the button to display the
pop-up when there is a limited amount of screen space.
By default, the pop-up should draw on top of the button.
*/
@@ -496,7 +505,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
if ([self pullsDown])
{
var items = [[self menu] itemArray];
var items = [_menu itemArray];
if ([items count] <= 0)
[self addItemWithTitle:aTitle];
@@ -510,14 +519,14 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
else
{
var index = [self indexOfItemWithTitle:aTitle];
if (index < 0)
{
[self addItemWithTitle:aTitle];
index = [self numberOfItems] - 1;
}
[self selectItemAtIndex:index];
}
}
@@ -544,8 +553,8 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
if ([self pullsDown])
{
var items = [[self menu] itemArray];
var items = [_menu itemArray];
if ([items count] > 0)
item = items[0];
}
@@ -556,117 +565,73 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
[super setTitle:[item title]];
}
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)changes context:(id)aContext
//
/*!
Called when the menu has a new item added to it.
@param aNotification information about the event
*/
- (void)menuDidAddItem:(CPNotification)aNotification
{
var pullsDown = [self pullsDown];
if (!pullsDown && aKeyPath === @"selectedItem.changeCount" ||
pullsDown && (aKeyPath === @"_firstItem" || aKeyPath === @"_firstItem.changeCount"))
var index = [[aNotification userInfo] objectForKey:@"CPMenuItemIndex"];
if (_selectedIndex < 0)
[self selectItemAtIndex:0];
else if (index == _selectedIndex)
[self synchronizeTitleAndSelectedItem];
// FIXME: This is due to a bug in KVO, we should never get it for "menu".
if (aKeyPath === @"menu")
else if (index < _selectedIndex)
++_selectedIndex;
if (index == 0 && [self pullsDown])
{
aKeyPath = @"menu.items";
[changes setObject:CPKeyValueChangeSetting forKey:CPKeyValueChangeKindKey];
[changes setObject:[[self menu] itemArray] forKey:CPKeyValueChangeNewKey];
var items = [_menu itemArray];
[items[0] setHidden:YES];
if (items.length > 0)
[items[1] setHidden:NO];
}
if (aKeyPath === @"menu.items")
var item = [_menu itemArray][index],
action = [item action];
if (!action || (action === @selector(_popUpItemAction:)))
{
var changeKind = [changes objectForKey:CPKeyValueChangeKindKey],
indexOfSelectedItem = [self indexOfSelectedItem];
if (changeKind === CPKeyValueChangeRemoval)
{
var index = CPNotFound,
indexes = [changes objectForKey:CPKeyValueChangeIndexesKey];
if ([indexes containsIndex:0] && [self pullsDown])
[self _firstItemDidChange];
// See whether the index has changed, despite the actual item not changing.
while ((index = [indexes indexGreaterThanIndex:index]) !== CPNotFound &&
index <= indexOfSelectedItem)
--indexOfSelectedItem;
[self selectItemAtIndex:indexOfSelectedItem];
}
else if (changeKind === CPKeyValueChangeReplacement)
{
var indexes = [changes objectForKey:CPKeyValueChangeIndexesKey];
if (pullsDown && [indexes containsIndex:0] ||
!pullsDown && [indexes containsIndex:indexOfSelectedItem])
[self synchronizeTitleAndSelectedItem];
}
else
{
// No matter what, we want to prepare the new items.
var newItems = [changes objectForKey:CPKeyValueChangeNewKey];
[newItems enumerateObjectsUsingBlock:function(aMenuItem)
{
var action = [aMenuItem action];
if (!action)
[aMenuItem setAction:action = @selector(_popUpItemAction:)];
if (action === @selector(_popUpItemAction:))
[aMenuItem setTarget:self];
}];
if (changeKind === CPKeyValueChangeSetting)
{
[self _firstItemDidChange];
[self selectItemAtIndex:CPNotFound];
[self selectItemAtIndex:MIN([newItems count] - 1, indexOfSelectedItem)];
}
else //if (changeKind === CPKeyValueChangeInsertion)
{
var indexes = [changes objectForKey:CPKeyValueChangeIndexesKey];
if ([self pullsDown] && [indexes containsIndex:0])
{
[self _firstItemDidChange];
if ([self numberOfItems] > 1)
{
var index = CPNotFound,
originalIndex = 0;
while ((index = [indexes indexGreaterThanIndex:index]) !== CPNotFound &&
index <= originalIndex)
++originalIndex;
[[self itemAtIndex:originalIndex] setHidden:NO];
}
}
if (indexOfSelectedItem < 0)
[self selectItemAtIndex:0];
else
{
var index = CPNotFound;
// See whether the index has changed, despite the actual item not changing.
while ((index = [indexes indexGreaterThanIndex:index]) !== CPNotFound &&
index <= indexOfSelectedItem)
++indexOfSelectedItem;
[self selectItemAtIndex:indexOfSelectedItem];
}
}
}
[item setTarget:self];
[item setAction:@selector(_popUpItemAction:)];
}
}
// [super observeValueForKeyPath:aKeyPath ofObject:anObject change:changes context:aContext];
/*!
Called when a menu item has changed.
@param aNotification information about the event
*/
- (void)menuDidChangeItem:(CPNotification)aNotification
{
var index = [[aNotification userInfo] objectForKey:@"CPMenuItemIndex"];
if ([self pullsDown] && index != 0)
return;
if (![self pullsDown] && index != _selectedIndex)
return;
[self synchronizeTitleAndSelectedItem];
}
/*!
Called when an item was removed from the menu.
@param aNotification information about the event
*/
- (void)menuDidRemoveItem:(CPNotification)aNotification
{
var numberOfItems = [self numberOfItems];
if (numberOfItems <= _selectedIndex && numberOfItems > 0)
[self selectItemAtIndex:numberOfItems - 1];
else
[self synchronizeTitleAndSelectedItem];
}
- (void)mouseDown:(CPEvent)anEvent
@@ -696,9 +661,6 @@ 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];
@@ -736,32 +698,11 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
}
- (void)rightMouseDown:(CPEvent)anEvent
{
// Disable standard CPView behavior which incorrectly displays the menu as a 'context menu'.
}
- (void)_popUpItemAction:(id)aSender
{
[self sendAction:[self action] to:[self target]];
}
- (void)_firstItemDidChange
{
[self willChangeValueForKey:@"_firstItem"];
[self didChangeValueForKey:@"_firstItem"];
[[self _firstItem] setHidden:YES];
}
- (CPMenuItem)_firstItem
{
if ([self numberOfItems] <= 0)
return nil;
return [[self menu] itemAtIndex:0];
}
- (void)takeValueFromKeyPath:(CPString)aKeyPath ofObjects:(CPArray)objects
{
var count = objects.length,
@@ -771,14 +712,19 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
[self setEnabled:YES];
while (count-- > 1)
{
if (value !== [objects[count] valueForKeyPath:aKeyPath])
{
[[self selectedItem] setState:CPOffState];
}
}
}
@end
var DEPRECATED_CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey",
DEPRECATED_CPPopUpButtonSelectedIndexKey = @"CPPopUpButtonSelectedIndexKey";
var CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey",
CPPopUpButtonSelectedIndexKey = @"CPPopUpButtonSelectedIndexKey",
CPPopUpButtonPullsDownKey = @"CPPopUpButtonPullsDownKey";
@implementation CPPopUpButton (CPCoding)
/*!
@@ -791,30 +737,30 @@ var DEPRECATED_CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey",
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
// FIXME: (or not?) _title is nulled in - [CPButton initWithCoder:],
// so we need to do this again.
[self synchronizeTitleAndSelectedItem];
// Nothing is currently selected
_selectedIndex = -1;
// FIXME: Remove deprecation leniency for 1.0
if ([aCoder containsValueForKey:DEPRECATED_CPPopUpButtonMenuKey])
{
CPLog.warn(self + " was encoded with an older version of Cappuccino. Please nib2cib the original nib again or open and re-save in Atlas.");
[self setMenu:[aCoder decodeObjectForKey:DEPRECATED_CPPopUpButtonMenuKey]];
[self setObjectValue:[aCoder decodeObjectForKey:DEPRECATED_CPPopUpButtonSelectedIndexKey]];
}
var options = CPKeyValueObservingOptionNew | CPKeyValueObservingOptionOld;/* | CPKeyValueObservingOptionInitial */
[self addObserver:self forKeyPath:@"menu.items" options:options context:nil];
[self addObserver:self forKeyPath:@"_firstItem.changeCount" options:options context:nil];
[self addObserver:self forKeyPath:@"selectedItem.changeCount" options:options context:nil];
[self setMenu:[aCoder decodeObjectForKey:CPPopUpButtonMenuKey]];
[self selectItemAtIndex:[aCoder decodeObjectForKey:CPPopUpButtonSelectedIndexKey]];
}
return self;
}
/*!
Encodes the data of the pop-up button into a coder
@param aCoder the coder to which the data
will be written
*/
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:_menu forKey:CPPopUpButtonMenuKey];
[aCoder encodeInt:_selectedIndex forKey:CPPopUpButtonSelectedIndexKey];
}
@end
+48 -83
View File
@@ -20,9 +20,11 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CGGeometry.j"
@import "CPImageView.j"
@import "CPView.j"
@import <AppKit/CGGeometry.j>
@import <AppKit/CPImageView.j>
@import <AppKit/CPView.j>
#include "CoreGraphics/CGGeometry.h"
/*
@@ -47,7 +49,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
CPProgressIndicatorStyleIdentifiers = nil,
CPProgressIndicatorStyleSizes = nil;
/*!
/*!
@ingroup appkit
@class CPProgressIndicator
@@ -59,19 +61,19 @@ var CPProgressIndicatorSpinningStyleColors = nil,
{
double _minValue;
double _maxValue;
double _doubleValue;
CPControlSize _controlSize;
BOOL _isIndeterminate;
CPProgressIndicatorStyle _style;
BOOL _isAnimating;
BOOL _isDisplayedWhenStoppedSet;
BOOL _isDisplayedWhenStopped;
CPView _barView;
}
@@ -82,11 +84,11 @@ var CPProgressIndicatorSpinningStyleColors = nil,
{
if (self != [CPProgressIndicator class])
return;
var bundle = [CPBundle bundleForClass:self];
CPProgressIndicatorSpinningStyleColors = [];
CPProgressIndicatorSpinningStyleColors[CPMiniControlSize] = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:
[bundle pathForResource:@"CPProgressIndicator/CPProgressIndicatorSpinningStyleRegular.gif"] size:CGSizeMake(64.0, 64.0)]];
CPProgressIndicatorSpinningStyleColors[CPSmallControlSize] = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:
@@ -95,10 +97,10 @@ var CPProgressIndicatorSpinningStyleColors = nil,
[bundle pathForResource:@"CPProgressIndicator/CPProgressIndicatorSpinningStyleRegular.gif"] size:CGSizeMake(64.0, 64.0)]];
CPProgressIndicatorBezelBorderViewPool = [];
var start = CPProgressIndicatorBarStyle,
end = CPProgressIndicatorHUDBarStyle;
for (; start <= end; ++start)
{
CPProgressIndicatorBezelBorderViewPool[start] = [];
@@ -106,21 +108,21 @@ var CPProgressIndicatorSpinningStyleColors = nil,
CPProgressIndicatorBezelBorderViewPool[start][CPSmallControlSize] = [];
CPProgressIndicatorBezelBorderViewPool[start][CPRegularControlSize] = [];
}
CPProgressIndicatorClassName = [self className];
CPProgressIndicatorStyleIdentifiers = [];
CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle] = @"Bar";
CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorSpinningStyle] = @"Spinny";
CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorHUDBarStyle] = @"HUDBar";
var regularIdentifier = _CPControlIdentifierForControlSize(CPRegularControlSize),
smallIdentifier = _CPControlIdentifierForControlSize(CPSmallControlSize),
miniIdentifier = _CPControlIdentifierForControlSize(CPMiniControlSize);
CPProgressIndicatorStyleSizes = [];
// Bar Style
// Bar Sttyle
var prefixes = [
CPProgressIndicatorClassName + @"BezelBorder" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle],
CPProgressIndicatorClassName + @"Bar" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle],
@@ -128,7 +130,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
CPProgressIndicatorClassName + @"Bar" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorHUDBarStyle]
];
for (var i = 0, count = prefixes.length; i < count; i++)
for (var i = 0, count = prefixes.length; i<count; i++)
{
var prefix = prefixes[i];
CPProgressIndicatorStyleSizes[prefix + regularIdentifier] = [_CGSizeMake(3.0, 16.0), _CGSizeMake(1.0, 16.0), _CGSizeMake(3.0, 16.0)];
@@ -140,23 +142,23 @@ var CPProgressIndicatorSpinningStyleColors = nil,
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
_minValue = 0.0;
_maxValue = 100.0;
_doubleValue = 0.0;
_style = CPProgressIndicatorBarStyle;
_isDisplayedWhenStoppedSet = NO;
_controlSize = CPRegularControlSize;
[self updateBackgroundColor];
[self drawBar];
}
return self;
}
@@ -174,7 +176,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
- (void)startAnimation:(id)aSender
{
_isAnimating = YES;
[self _hideOrDisplay];
}
@@ -213,7 +215,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
- (void)setDoubleValue:(double)aValue
{
_doubleValue = MIN(MAX(aValue, _minValue), _maxValue);
[self drawBar];
}
@@ -268,7 +270,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
{
if (_controlSize == aControlSize)
return;
_controlSize = aControlSize;
[self updateBackgroundColor];
@@ -290,7 +292,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
}
/*
Not yet implemented.
Not yet impemented.
*/
- (CPControlTint)controlTint
{
@@ -320,7 +322,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
{
if (_isIndeterminate == isIndeterminate)
return;
_isIndeterminate = isIndeterminate;
[self updateBackgroundColor];
@@ -342,9 +344,9 @@ var CPProgressIndicatorSpinningStyleColors = nil,
{
if (_style == aStyle)
return;
_style = aStyle;
[self updateBackgroundColor];
}
@@ -357,7 +359,8 @@ var CPProgressIndicatorSpinningStyleColors = nil,
[self setFrameSize:[[CPProgressIndicatorSpinningStyleColors[_controlSize] patternImage] size]];
else
[self setFrameSize:CGSizeMake(CGRectGetWidth([self frame]), CPProgressIndicatorStyleSizes[
CPProgressIndicatorClassName + @"BezelBorder" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle] + _CPControlIdentifierForControlSize(_controlSize)][0].height)];
CPProgressIndicatorClassName + @"BezelBorder" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle] +
_CPControlIdentifierForControlSize(_controlSize)][0].height)];
}
/*!
@@ -369,11 +372,11 @@ var CPProgressIndicatorSpinningStyleColors = nil,
{
if (_isDisplayedWhenStoppedSet && _isDisplayedWhenStopped == isDisplayedWhenStopped)
return;
_isDisplayedWhenStoppedSet = YES;
_isDisplayedWhenStopped = isDisplayedWhenStopped;
[self _hideOrDisplay];
}
@@ -384,10 +387,10 @@ var CPProgressIndicatorSpinningStyleColors = nil,
{
if (_isDisplayedWhenStoppedSet)
return _isDisplayedWhenStopped;
if (_style == CPProgressIndicatorBarStyle || _style == CPProgressIndicatorHUDBarStyle)
return YES;
return NO;
}
@@ -400,7 +403,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
- (void)setFrameSize:(CGSize)aSize
{
[super setFrameSize:aSize];
[self drawBar];
}
@@ -409,13 +412,13 @@ var CPProgressIndicatorSpinningStyleColors = nil,
{
if (_style == CPProgressIndicatorSpinningStyle)
return;
if (!_barView)
{
_barView = [[CPView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 16.0)];
_barView = [[CPView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 16.0)];
[self addSubview:_barView];
}
[_barView setBackgroundColor:_CPControlThreePartImagePattern(
NO,
CPProgressIndicatorStyleSizes,
@@ -441,9 +444,9 @@ var CPProgressIndicatorSpinningStyleColors = nil,
if (_style == CPProgressIndicatorSpinningStyle)
{
[_barView removeFromSuperview];
_barView = nil;
[self setBackgroundColor:CPProgressIndicatorSpinningStyleColors[_controlSize]];
}
else
@@ -455,7 +458,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
@"BezelBorder",
CPProgressIndicatorStyleIdentifiers[_style],
_CPControlIdentifierForControlSize(_controlSize))];
[self drawBar];
}
}
@@ -464,41 +467,3 @@ var CPProgressIndicatorSpinningStyleColors = nil,
}
@end
@implementation CPProgressIndicator (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
if (self = [super initWithCoder:aCoder])
{
_minValue = [aCoder decodeObjectForKey:@"_minValue"];
_maxValue = [aCoder decodeObjectForKey:@"_maxValue"];
_doubleValue = [aCoder decodeObjectForKey:@"_doubleValue"];
_controlSize = [aCoder decodeObjectForKey:@"_controlSize"];
_isIndeterminate = [aCoder decodeObjectForKey:@"_isIndeterminate"];
_style = [aCoder decodeObjectForKey:@"_style"];
_isAnimating = [aCoder decodeObjectForKey:@"_isAnimating"];
_isDisplayedWhenStoppedSet = [aCoder decodeObjectForKey:@"_isDisplayedWhenStoppedSet"];
_isDisplayedWhenStopped = [aCoder decodeObjectForKey:@"_isDisplayedWhenStopped"];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:_minValue forKey:@"_minValue"];
[aCoder encodeObject:_maxValue forKey:@"_maxValue"];
[aCoder encodeObject:_doubleValue forKey:@"_doubleValue"];
[aCoder encodeObject:_controlSize forKey:@"_controlSize"];
[aCoder encodeObject:_isIndeterminate forKey:@"_isIndeterminate"];
[aCoder encodeObject:_style forKey:@"_style"];
[aCoder encodeObject:_isAnimating forKey:@"_isAnimating"];
[aCoder encodeObject:_isDisplayedWhenStoppedSet forKey:@"_isDisplayedWhenStoppedSet"];
[aCoder encodeObject:_isDisplayedWhenStopped forKey:@"_isDisplayedWhenStopped"];
}
@end
+15 -19
View File
@@ -25,29 +25,28 @@
@import "CPButton.j"
/*!
@ingroup appkit
from this mailing list thread:
http://groups.google.com/group/objectivej/browse_thread/thread/7c41cbd9cbee9ea3
http://groups.google.com/group/objectivej/browse_thread/thread/7c41cbd9cbee9ea3
-----------------------------------
Creating a checkbox is easy enough:
checkbox = [[CPCheckBox alloc] initWithFrame:aFrame];
That's basically all there is to it. Radio buttons are very similar,
the key difference is the introduction of a new class CPRadioGroup,
which defines which radio buttons are part of the same group:
[myRadioButton setRadioGroup:aRadioGroup];
Every radio button receives a unique radio group by default (so if you
do nothing further, they will all behave independently), but you can
use an existing radio button's group with other buttons as so:
button1 = [[CPRadio alloc] initWithFrame:aFrame];
...
button2 = [[CPRadio alloc] initWithFrame:aFrame radioGroup:[button1
@@ -56,16 +55,13 @@
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;
@@ -90,7 +86,7 @@ CPRadioImageOffset = 4.0;
return button;
}
+ (CPString)defaultThemeClass
+ (CPString)themeClass
{
return @"radio";
}
@@ -99,7 +95,7 @@ CPRadioImageOffset = 4.0;
- (id)initWithFrame:(CGRect)aFrame radioGroup:(CPRadioGroup)aRadioGroup
{
self = [super initWithFrame:aFrame];
if (self)
{
[self setRadioGroup:aRadioGroup];
@@ -113,8 +109,8 @@ CPRadioImageOffset = 4.0;
[self setBordered:YES];
}
return self;
return self;
}
- (id)initWithFrame:(CGRect)aFrame
@@ -145,7 +141,7 @@ CPRadioImageOffset = 4.0;
- (void)setObjectValue:(id)aValue
{
[super setObjectValue:aValue];
if ([self state] === CPOnState)
[_radioGroup _setSelectedRadio:self];
}
+59 -60
View File
@@ -23,23 +23,22 @@
@import <Foundation/CPObject.j>
CPDeleteKeyCode = 8;
CPTabKeyCode = 9;
CPReturnKeyCode = 13;
CPEscapeKeyCode = 27;
CPSpaceKeyCode = 32;
CPPageUpKeyCode = 33;
CPPageDownKeyCode = 34;
CPLeftArrowKeyCode = 37;
CPUpArrowKeyCode = 38;
CPRightArrowKeyCode = 39;
CPDownArrowKeyCode = 40;
CPDeleteForwardKeyCode = 46;
CPDeleteKeyCode = 8;
CPTabKeyCode = 9;
CPReturnKeyCode = 13;
CPEscapeKeyCode = 27;
CPSpaceKeyCode = 32;
CPPageUpKeyCode = 33;
CPPageDownKeyCode = 34;
CPLeftArrowKeyCode = 37;
CPUpArrowKeyCode = 38;
CPRightArrowKeyCode = 39;
CPDownArrowKeyCode = 40;
/*!
@ingroup appkit
@class CPResponder
Subclasses of CPResonder can be part of the responder chain.
*/
@implementation CPResponder : CPObject
@@ -105,24 +104,42 @@ CPDeleteForwardKeyCode = 46;
for (; index < count; ++index)
{
var event = events[index],
modifierFlags = [event modifierFlags],
character = [event charactersIgnoringModifiers],
selectorNames = [CPKeyBinding selectorsForKey:character modifierFlags:modifierFlags];
var event = events[index];
if (selectorNames)
switch([event keyCode])
{
for (var s = 0, scount = selectorNames.length; s < scount; s++)
{
var selector = selectorNames[s];
if (!selector)
continue;
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;
[self doCommandBySelector:CPSelectorFromString(selector)];
}
case CPTabKeyCode: var shift = [event modifierFlags] & CPShiftKeyMask;
if (!shift)
[self doCommandBySelector:@selector(insertTab:)];
else
[self doCommandBySelector:@selector(insertBackTab:)];
break;
default: [self insertText:[event characters]];
}
else if (!(modifierFlags & (CPCommandKeyMask | CPControlKeyMask)) && [self respondsToSelector:@selector(insertText:)])
[self insertText:[event characters]];
}
}
@@ -222,27 +239,11 @@ 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];
}
/*!
Overridden by subclasses to handle a key equivalent.
If the character code or codes in \c anEvent match the receivers key equivalent,
the receiver should respond to the event and return \c YES. The default implementation
does nothing and returns \c NO.
You should extract the characters for a key equivalent using
\ref CPEvent::charactersIgnoringModifiers "[anEvent charactersIgnoringModifiers]".
@param anEvent An event object that represents the key equivalent pressed
@return \c YES if theEvent is a key equivalent that the receiver handled, \c NO if it is not a key equivalent that it should handle.
/*
FIXME This description is bad.
Based on \c anEvent, the receiver should simulate the event.
@param anEvent the event to simulate
@return \c YES if the event receiver simulated the event
*/
- (BOOL)performKeyEquivalent:(CPEvent)anEvent
{
@@ -268,6 +269,10 @@ CPDeleteForwardKeyCode = 46;
[[self nextResponder] insertNewline:aSender];
}
- (void)cancel:(id)sender
{
}
- (void)insertTab:(id)sender
{
}
@@ -307,10 +312,10 @@ CPDeleteForwardKeyCode = 46;
*/
- (BOOL)tryToPerform:(SEL)aSelector with:(id)anObject
{
if ([self respondsToSelector:aSelector])
if([self respondsToSelector:aSelector])
{
[self performSelector:aSelector withObject:anObject];
return YES;
}
@@ -349,8 +354,7 @@ CPDeleteForwardKeyCode = 46;
@end
var CPResponderNextResponderKey = @"CPResponderNextResponderKey",
CPResponderMenuKey = @"CPResponderMenuKey";
var CPResponderNextResponderKey = @"CPResponderNextResponderKey";
@implementation CPResponder (CPCoding)
@@ -362,13 +366,10 @@ var CPResponderNextResponderKey = @"CPResponderNextResponderKey",
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
if (self)
{
[self setNextResponder:[aCoder decodeObjectForKey:CPResponderNextResponderKey]];
[self setMenu:[aCoder decodeObjectForKey:CPResponderMenuKey]];
}
_nextResponder = [aCoder decodeObjectForKey:CPResponderNextResponderKey];
return self;
}
@@ -381,8 +382,6 @@ var CPResponderNextResponderKey = @"CPResponderNextResponderKey",
// This will come out nil on the other side with decodeObjectForKey:
if (_nextResponder !== nil)
[aCoder encodeConditionalObject:_nextResponder forKey:CPResponderNextResponderKey];
[aCoder encodeObject:_menu forKey:CPResponderMenuKey];
}
@end
-504
View File
@@ -1,504 +0,0 @@
/*
* CPPredicateEditor.j
* AppKit
*
* Created by cacaodev.
* Copyright 2011, cacaodev.
*
* 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 "CPRuleEditor.j"
@import "_CPPredicateEditorTree.j"
@import "_CPPredicateEditorRowNode.j"
@import "CPPredicateEditorRowTemplate.j"
@implementation CPPredicateEditor : CPRuleEditor
{
CPArray _allTemplates;
CPArray _rootTrees;
CPArray _rootHeaderTrees;
id _predicateTarget @accessors(property=target);
SEL _predicateAction @accessors(property=action);
}
#pragma mark public methods
/*!
@ingroup appkit
@class CPPredicateEditor
@brief CPPredicateEditor is a subclass of CPRuleEditor that is specialized for editing CPPredicate objects.
CPPredicateEditor provides a CPPredicate property—objectValue (inherited from CPControl)—that you can get and set directly, and that you can bind using bindings (you typically configure a predicate editor in Interface Builder). CPPredicateEditor depends on another class, CPPredicateEditorRowTemplate, that describes the available predicates and how to display them.
Unlike CPRuleEditor, CPPredicateEditor does not depend on its delegate to populate its rows (and does not call the populating delegate methods). Instead, its rows are populated from its objectValue property (an instance of CPPredicate). CPPredicateEditor relies on instances CPPredicateEditorRowTemplate, which are responsible for mapping back and forth between the displayed view values and various predicates.
CPPredicateEditor exposes one property, rowTemplates, which is an array of CPPredicateEditorRowTemplate objects.
*/
/*!
@brief Returns the row templates for the receiver.
@return The row templates for the receiver.
@discussion Until otherwise set, this contains a single compound CPPredicateEditorRowTemplate object.
@see setRowTemplates:
*/
- (CPArray)rowTemplates
{
return _allTemplates;
}
/*!
@brief Sets the row templates for the receiver.
@param rowTemplates An array of CPPredicateEditorRowTemplate objects.
@see rowTemplates
*/
- (void)setRowTemplates:(id)rowTemplates
{
if (_allTemplates == rowTemplates)
return;
_allTemplates = rowTemplates;
[self _updateItemsByCompoundTemplates];
[self _updateItemsBySimpleTemplates];
if ([self numberOfRows] > 0)
{
var predicate = [super predicate];
[self _reflectPredicate:predicate];
}
}
/*! @cond */
- (void)_initRuleEditorShared
{
[super _initRuleEditorShared];
_rootTrees = [CPArray array];
_rootHeaderTrees = [CPArray array];
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self != nil)
{
var initialTemplate = [[CPPredicateEditorRowTemplate alloc] initWithCompoundTypes:[CPAndPredicateType, CPOrPredicateType]];
_allTemplates = [CPArray arrayWithObject:initialTemplate];
}
return self;
}
- (id)objectValue
{
return [super predicate];
}
- (void)_updateItemsBySimpleTemplates
{
var templates = [CPMutableArray array],
count = [_allTemplates count],
t;
while (count--)
{
var t = _allTemplates[count];
if ([t _rowType] == CPRuleEditorRowTypeSimple)
[templates insertObject:t atIndex:0];
}
var trees = [self _constructTreesForTemplates:templates];
if ([trees count] > 0)
_rootTrees = [self _mergeTree:trees];
}
- (void)_updateItemsByCompoundTemplates
{
var templates = [CPMutableArray array],
count = [_allTemplates count],
t;
while (count--)
{
var t = _allTemplates[count];
if ([t _rowType] == CPRuleEditorRowTypeCompound)
[templates insertObject:t atIndex:0];
}
var trees = [self _constructTreesForTemplates:templates];
if ([trees count] > 0)
_rootHeaderTrees = [self _mergeTree:trees];
}
- (CPArray)_constructTreesForTemplates:(id)templates
{
var trees = [CPMutableArray array],
count = [templates count];
for (var i = 0; i < count; i++)
{
var tree = [self _constructTreeForTemplate:templates[i]];
[trees addObjectsFromArray:tree];
}
return trees;
}
- (id)_mergeTree:(id)tree
{
var merged = [CPMutableArray array],
titles = [CPMutableArray array],
count = [tree count];
for (var i = 0; i < count; i++)
{
var t = tree[i],
title = [CPString stringWithString:[t title]];
if ([titles containsObject:title])
{
CPLogConsole("CPPredicateEditor does not support templates merging yet. Ignoring duplicate template: " + [t description]);
continue;
}
[merged addObject:t];
[titles addObject:title];
}
return merged;
}
- (id)_constructTreeForTemplate:(CPPredicateEditorRowTemplate)aTemplate
{
var tree = [CPArray array],
templateViews = [aTemplate templateViews],
count = [templateViews count];
while (count--)
{
var children = [CPArray array],
itemsCount = 0,
menuIndex = -1,
itemsArray,
templateView = [templateViews objectAtIndex:count],
isPopup = [templateView isKindOfClass:[CPPopUpButton class]];
if (isPopup)
{
itemArray = [[templateView itemArray] valueForKey:@"title"];
itemsCount = [itemArray count],
menuIndex = 0;
}
for (; menuIndex < itemsCount; menuIndex++)
{
var item = [_CPPredicateEditorTree new];
[item setIndexIntoTemplate:count];
[item setTemplate:aTemplate];
[item setMenuItemIndex:menuIndex];
if (isPopup)
[item setTitle:[itemArray objectAtIndex:menuIndex]];
[children addObject:item];
}
[children makeObjectsPerformSelector:@selector(setChildren:) withObject:tree];
tree = children;
}
return tree;
}
#pragma mark Set the Predicate
- (void)setObjectValue:(id)objectValue
{
if (![[objectValue predicateFormat] isEqualToString:[[super predicate] predicateFormat]]) // ??
[self _reflectPredicate:objectValue];
}
- (void)_reflectPredicate:(id)predicate
{
var animation = _currentAnimation;
_currentAnimation = nil;
if (predicate != nil)
{
if ((_nestingMode == CPRuleEditorNestingModeSimple || _nestingMode == CPRuleEditorNestingModeCompound)
&& [predicate isKindOfClass:[CPComparisonPredicate class]])
predicate = [[CPCompoundPredicate alloc] initWithType:[self _compoundPredicateTypeForRootRows] subpredicates:[CPArray arrayWithObject:predicate]];
var row = [self _rowObjectFromPredicate:predicate];
if (row != nil)
[_boundArrayOwner setValue:[CPArray arrayWithObject:row] forKey:_boundArrayKeyPath];
}
[self setAnimation:animation];
}
- (id)_rowObjectFromPredicate:(CPPredicate)predicate
{
var quality, // TODO: We should use this ref somewhere !
type,
matchedTemplate = [CPPredicateEditorRowTemplate _bestMatchForPredicate:predicate inTemplates:[self rowTemplates] quality:quality];
if (matchedTemplate == nil)
return nil;
var copyTemplate = [matchedTemplate copy],
subpredicates = [matchedTemplate displayableSubpredicatesOfPredicate:predicate];
if (subpredicates == nil)
{
[copyTemplate _setComparisonPredicate:predicate];
type = CPRuleEditorRowTypeSimple;
}
else
{
[copyTemplate _setCompoundPredicate:predicate];
type = CPRuleEditorRowTypeCompound;
}
var row = [self _rowFromTemplate:copyTemplate originalTemplate:matchedTemplate withRowType:type];
if (subpredicates == nil)
return row;
var count = [subpredicates count],
subrows = [CPMutableArray array];
for (var i = 0; i < count; i++)
{
var subrow = [self _rowObjectFromPredicate:subpredicates[i]];
if (subrow != nil)
[subrows addObject:subrow];
}
[row setValue:subrows forKey:[super subrowsKeyPath]];
return row;
}
- (id)_rowFromTemplate:(CPPredicateEditorRowTemplate)aTemplate originalTemplate:(CPPredicateEditorRowTemplate)originalTemplate withRowType:(CPRuleEditorRowType)rowType
{
var criteria = [CPArray array],
values = [CPArray array],
templateViews = [aTemplate templateViews],
rootItems,
count;
rootItems = (rowType == CPRuleEditorRowTypeSimple) ? _rootTrees : _rootHeaderTrees;
while ((count = [rootItems count]) > 0)
{
var treeChild;
for (var i = 0; i < count; i++)
{
treeChild = [rootItems objectAtIndex:i];
var currentView = [templateViews objectAtIndex:[treeChild indexIntoTemplate]],
menuItemIndex = [treeChild menuItemIndex];
if (menuItemIndex == -1 || [[treeChild title] isEqual:[currentView titleOfSelectedItem]])
{
var node = [_CPPredicateEditorRowNode rowNodeFromTree:treeChild];
[node applyTemplate:aTemplate withViews:templateViews forOriginalTemplate:originalTemplate];
[criteria addObject:node];
[values addObject:[node displayValue]];
break;
}
}
rootItems = [treeChild children];
}
var row = [CPDictionary dictionaryWithObjectsAndKeys:criteria, @"criteria", values, @"displayValues", rowType, @"rowType"];
return row;
}
#pragma mark Get the predicate
- (void)_updatePredicate
{
[self willChangeValueForKey:@"objectValue"];
[self _updatePredicateFromRows];
[self didChangeValueForKey:@"objectValue"];
}
- (void)_updatePredicateFromRows
{
var rootRowsArray = [super _rootRowsArray],
subpredicates = [CPMutableArray array],
count = count2 = [rootRowsArray count],
predicate;
while (count--)
{
var item = [rootRowsArray objectAtIndex:count],
subpredicate = [self _predicateFromRowItem:item];
if (subpredicate != nil)
[subpredicates insertObject:subpredicate atIndex:0];
}
if (_nestingMode != CPRuleEditorNestingModeList && count2 == 1)
predicate = [subpredicates lastObject];
else
predicate = [[CPCompoundPredicate alloc] initWithType:[self _compoundPredicateTypeForRootRows] subpredicates:subpredicates];
[super _setPredicate:predicate];
}
- (id)_predicateFromRowItem:(id)rowItem
{
var subpredicates = [CPArray array],
rowType = [rowItem valueForKey:_typeKeyPath];
if (rowType == CPRuleEditorRowTypeCompound)
{
var subrows = [rowItem valueForKey:_subrowsArrayKeyPath],
count = [subrows count];
for (var i = 0; i < count; i++)
{
var subrow = [subrows objectAtIndex:i];
var predicate = [self _predicateFromRowItem:subrow];
[subpredicates addObject:predicate];
}
}
var criteria = [rowItem valueForKey:_itemsKeyPath],
displayValues = [rowItem valueForKey:_valuesKeyPath],
count = [criteria count],
lastItem = [criteria lastObject],
template = [lastItem templateForRow],
templateViews = [template templateViews];
for (var j = 0; j < count; j++)
{
var view = [templateViews objectAtIndex:j],
value = [displayValues objectAtIndex:j];
[[criteria objectAtIndex:j] setTemplateViews:templateViews];
if ([view isKindOfClass:[CPPopUpButton class]])
[view selectItemWithTitle:value];
else if ([view respondsToSelector:@selector(setObjectValue:)])
[view setObjectValue:[value objectValue]];
}
return [template predicateWithSubpredicates:subpredicates];
}
- (CPCompoundPredicateType)_compoundPredicateTypeForRootRows
{
return CPAndPredicateType;
}
#pragma mark Control delegate
- (void)_sendRuleAction
{
[self _updatePredicate];
[super _sendRuleAction];
}
- (BOOL)_sendsActionOnIncompleteTextChange
{
return NO;
}
/*
- (void)_setDefaultTargetAndActionOnView:(CPView)view
{
if ([view isKindOfClass:[CPControl class]])
{
[view setTarget:self];
[view setAction:@selector(_templateControlValueDidChange:)];
}
}
- (void)_templateControlValueDidChange:(id)sender
{
}
- (void)controlTextDidBeginEditing:(CPNotification)notification
{
}
- (void)controlTextDidEndEditing:(CPNotification)notification
{
}
- (void)controlTextDidChange:(CPNotification)notification
{
}
*/
#pragma mark RuleEditor delegate methods
- (int)_queryNumberOfChildrenOfItem:(id)rowItem withRowType:(int)type
{
if (rowItem == nil)
{
var trees = (type == CPRuleEditorRowTypeSimple) ? _rootTrees : _rootHeaderTrees;
return [trees count];
}
return [[rowItem children] count];
}
- (id)_queryChild:(int)childIndex ofItem:(id)rowItem withRowType:(int)type
{
if (rowItem == nil)
{
var trees = (type == CPRuleEditorRowTypeSimple) ? _rootTrees : _rootHeaderTrees;
return [_CPPredicateEditorRowNode rowNodeFromTree:trees[childIndex]];
}
return [[rowItem children] objectAtIndex:childIndex];
}
- (id)_queryValueForItem:(id)rowItem inRow:(int)rowIndex
{
return [rowItem displayValue];
}
@end
var CPPredicateTemplatesKey = @"CPPredicateTemplates";
@implementation CPPredicateEditor (CPCoding)
- (id)initWithCoder:(id)aCoder
{
self = [super initWithCoder:aCoder];
if (self != nil)
{
var nibTemplates = [aCoder decodeObjectForKey:CPPredicateTemplatesKey];
if (nibTemplates != nil)
[self setRowTemplates:nibTemplates];
}
return self;
}
- (void)encodeWithCoder:(id)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:_allTemplates forKey:CPPredicateTemplatesKey];
}
@end
/*! @endcond */
@@ -1,788 +0,0 @@
/*
* CPPredicateEditorRowTemplate.j
* AppKit
*
* Created by cacaodev.
* Copyright 2011, cacaodev.
*
* 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
*/
CPUndefinedAttributeType = 0,
CPInteger16AttributeType = 100,
CPInteger32AttributeType = 200,
CPInteger64AttributeType = 300,
CPDecimalAttributeType = 400,
CPDoubleAttributeType = 500,
CPFloatAttributeType = 600,
CPStringAttributeType = 700,
CPBooleanAttributeType = 800,
CPDateAttributeType = 900,
CPBinaryDataAttributeType = 1000,
CPTransformableAttributeType = 1800;
@implementation CPPredicateEditorRowTemplate : CPObject
{
int _templateType @accessors(readwrite, getter=_templateType, setter=_setTemplateType:);
unsigned _predicateOptions @accessors(readwrite, setter=_setOptions:);
unsigned _predicateModifier @accessors(readwrite, setter=_setModifier:);
unsigned _leftAttributeType @accessors(readwrite, getter=leftAttributeType, setter=_setLeftAttributeType:);
unsigned _rightAttributeType @accessors(readwrite, getter=rightAttributeType, setter=_setRightAttributeType:);
BOOL _leftIsWildcard @accessors(property=leftIsWildcard);
BOOL _rightIsWildcard @accessors(property=rightIsWildcard);
CPArray _views @accessors(setter=setTemplateViews:);
}
/*!
@ingroup appkit
@class CPPredicateEditorRowTemplate
@brief CPPredicateEditorRowTemplate describes available predicates and how to display them.
You can create instances of CPPredicateEditorRowTemplate programmatically or in Interface Builder. By default, a non-compound row template has three views: a popup (or static text field) on the left, a popup or static text field for operators, and either a popup or other view on the right. You can subclass CPPredicateEditorRowTemplate to create a row template with different numbers or types of views.
CPPredicateEditorRowTemplate is a concrete class, but it has five primitive methods which are called by CPPredicateEditor: -#templateViews, -#matchForPredicate:, -#setPredicate:, -#displayableSubpredicatesOfPredicate:, and -#predicateWithSubpredicates:. CPPredicateEditorRowTemplate implements all of them, but you can override them for custom templates. The primitive methods are used by an instance of CPPredicateEditor as follows.
First, an instance of CPPredicateEditor is created, and some row templates are set on it—either through a nib file or programmatically. The first thing predicate editor does is ask each of the templates for their views, using templateViews.
After setting up the predicate editor, you typically send it a CPPredicateEditor#setObjectValue: message to restore a saved predicate. CPPredicateEditor needs to determine which of its templates should display each predicate in the predicate tree. It does this by sending each of its row templates a matchForPredicate: message and choosing the one that returns the highest value.
After finding the best match for a predicate, CPPredicateEditor copies that template to get fresh views, inserts them into the proper row, and then sets the predicate on the template using setPredicate:. Within that method, the CPPredicateEditorRowTemplate object must set its views' values to represent that predicate.
CPPredicateEditorRowTemplate next asks the template for the “displayable sub-predicates” of the predicate by sending a -#displayableSubpredicatesOfPredicate: message. If a template represents a predicate in its entirety, or if the predicate has no subpredicates, it can return nil for this. Otherwise, it should return a list of predicates to be made into sub-rows of that template's row. The whole process repeats for each sub-predicate.
At this point, the user sees the predicate that was saved. If the user then makes some changes to the views of the templates, this causes CPPredicateEditor to recompute its predicate by asking each of the templates to return the predicate represented by the new view values, passing in the subpredicates represented by the sub-rows (an empty array if there are none, or nil if they aren't supported by that predicate type).
*/
/*!
@name Initializing a Template
*/
/*!
@brief Initializes and returns a “pop-up-pop-up-pop-up”-style row template.
@param leftExpressions An array of CPExpression objects that represent the left hand side of a predicate.
@param rightExpressions An array of CPExpression objects that represent the right hand side of a predicate.
@param modifier A modifier for the predicate (see @c CPComparisonPredicateModifier for possible values).
@param operators An array of CPNumber objects specifying the operator type (see @c CPPredicateOperatorType for possible values).
@param options Options for the predicate (see @c CPComparisonPredicateOptions for possible values).
@return A row template of the “pop-up-pop-up-pop-up”-form, with the left and right popups representing the left and right expression arrays -#leftExpressions and -#rightExpressions, and the center popup representing the operators.
*/
- (id)initWithLeftExpressions:(CPArray)leftExpressions rightExpressions:(CPArray)rightExpressions modifier:(int)modifier operators:(CPArray)operators options:(int)options
{
self = [super init];
if (self != nil)
{
_templateType = 1;
_leftIsWildcard = NO;
_rightIsWildcard = NO;
_leftAttributeType = 0;
_rightAttributeType = 0;
_predicateModifier = modifier;
_predicateOptions = options;
var leftView = [self _viewFromExpressions:leftExpressions],
rightView = [self _viewFromExpressions:rightExpressions],
middleView = [self _viewFromOperatorTypes:operators];
_views = [[CPArray alloc] initWithObjects:leftView, middleView, rightView];
}
return self;
}
/*!
@brief Initializes and returns a “pop-up-pop-up-view”-style row template.
@param leftExpressions An array of CPExpression objects that represent the left hand side of a predicate.
@param attributeType An attribute type for the right hand side of a predicate. This value dictates the type of view created, and how the controls object value is coerced before putting it into a predicate.
@param modifier A modifier for the predicate (see @c CPComparisonPredicateModifier for possible values).
@param operators An array of CPNumber objects specifying the operator type (see @c CPPredicateOperatorType for possible values).
@param options Options for the predicate (see CPComparisonPredicateOptions for possible values).
@return A row template initialized using the given arguments.
*/
- (id)initWithLeftExpressions:(CPArray )leftExpressions rightExpressionAttributeType:(CPAttributeType)attributeType modifier:(CPComparisonPredicateModifier)modifier operators:(CPArray )operators options:(int)options
{
self = [super init];
if (self != nil)
{
var leftView = [self _viewFromExpressions:leftExpressions],
middleView = [self _viewFromOperatorTypes:operators],
rightView = [self _viewFromAttributeType:attributeType];
_templateType = 1;
_leftIsWildcard = NO;
_rightIsWildcard = YES;
_leftAttributeType = 0;
_rightAttributeType = attributeType;
_predicateModifier = modifier;
_predicateOptions = options;
_views = [[CPArray alloc] initWithObjects:leftView, middleView, rightView];
}
return self;
}
/*!
@brief Initializes and returns a row template suitable for displaying compound predicates.
@param compoundTypes An array of CPNumber objects specifying compound predicate types. See @c CPCompoundPredicateTypes for possible values.
@return A row template initialized for displaying compound predicates of the types specified by @a compoundTypes.
@discussion CPPredicateEditor contains such a template by default.
*/
- (id)initWithCompoundTypes:(CPArray )compoundTypes
{
self = [super init];
if (self != nil)
{
var leftView = [self _viewFromCompoundTypes:compoundTypes],
rightView = [[CPPopUpButton alloc] init];
[rightView addItemWithTitle:@"of the following are true"];
_templateType = 2;
_leftIsWildcard = NO;
_rightIsWildcard = NO;
_rightAttributeType = 0;
_views = [[CPArray alloc] initWithObjects:leftView, rightView];
}
return self;
}
/*!
@name Primitive Methods
*/
/*!
@brief Returns a positive number if the receiver can represent a given predicate, and 0 if it cannot.
@return A positive number if the template can represent predicate, and @c 0 if it cannot.
@discussion By default, returns values in the range @c 0 to @c 1.
The highest match among all the templates determines which template is responsible for displaying the predicate. You can override this to determine which predicates your custom template handles.
*/
- (double)matchForPredicate:(CPPredicate)predicate
{
// How exactly this value (float 0-1) is computed ?
if ([self _templateType] == 2 && [predicate isKindOfClass:[CPCompoundPredicate class]])
{
if ([[self compoundTypes] containsObject:[predicate compoundPredicateType]])
return 1;
}
else if ([self _templateType] == 1 && [predicate isKindOfClass:[CPComparisonPredicate class]])
{
if (!_leftIsWildcard && ![[self leftExpressions] containsObject:[predicate leftExpression]])
return 0;
if (![[self operators] containsObject:[predicate predicateOperatorType]])
return 0;
if (!_rightIsWildcard && ![[self rightExpressions] containsObject:[predicate rightExpression]]) return 0;
return 1;
}
return 0;
}
/*!
@brief Returns the views for the receiver.
@return The views for the receiver.
@discussion Instances of CPPopUpButton are treated specially by CPPredicateEditor; their menu items are merged into a single popup button, and matching menu item titles are combined. In this way, a single tree is built from the separate templates.
*/
- (CPArray)templateViews
{
return _views;
}
/*!
@brief Sets the value of the views according to the given predicate.
@param predicate The predicate value for the receiver.
@discussion This method is only called if -#matchForPredicate: returned a positive value for the receiver.
You can override this to set the values of custom views.
*/
- (void)setPredicate:(CPPredicate)predicate
{
if (_templateType == 2)
[self _setCompoundPredicate:predicate];
else
[self _setComparisonPredicate:predicate];
}
/*!
@brief Returns the subpredicates that should be made sub-rows of a given predicate.
@param predicate A predicate object.
@return The subpredicates that should be made sub-rows of @a predicate. For compound predicates (instances of CPCompoundPredicate), the array of subpredicates; for other types of predicate, returns @c nil. If a template represents a predicate in its entirety, or if the predicate has no subpredicates, returns @c nil.
@discussion You can override this method to create custom templates that handle complicated compound predicates.
*/
- (CPArray)displayableSubpredicatesOfPredicate:(CPPredicate)predicate
{
if ([predicate isKindOfClass:[CPCompoundPredicate class]])
{
var subpredicates = [predicate subpredicates];
if ([subpredicates count] == 0)
return nil;
return subpredicates;
}
return nil;
}
/*!
@brief Returns the predicate represented by the receivers views' values and the given sub-predicates.
@param subpredicates An array of predicates.
@return The predicate represented by the values of the template's views and the given @a subpredicates. You can override this method to return the predicate represented by your custom views.
@discussion This method is only called if -#matchForPredicate: returned a positive value for the receiver.
You can override this method to return the predicate represented by a custom view.
*/
- (CPPredicate)predicateWithSubpredicates:(CPArray)subpredicates
{
if (_templateType == 2)
{
var type = [[_views[0] selectedItem] representedObject];
return [[CPCompoundPredicate alloc] initWithType:type subpredicates:subpredicates];
}
if (_templateType == 1)
{
var lhs = [self _leftExpression],
rhs = [self _rightExpression],
operator = [[_views[1] selectedItem] representedObject];
return [CPComparisonPredicate predicateWithLeftExpression:lhs
rightExpression:rhs
modifier:[self modifier]
type:operator
options:[self options]];
}
return nil;
}
/*!
@name Information About a Row Template
*/
/*!
@brief Returns the left hand expressions for the receiver.
@return The left hand expressions for the receiver.
*/
- (CPArray)leftExpressions
{
if (_templateType ==1 && !_leftIsWildcard)
{
var view = [_views objectAtIndex:0];
return [[view itemArray] valueForKey:@"representedObject"];
}
return nil;
}
/*!
@brief Returns the right hand expressions for the receiver.
@return The right hand expressions for the receiver.
*/
- (CPArray)rightExpressions
{
if (_templateType == 1 && !_rightIsWildcard)
{
var view = [_views objectAtIndex:2];
return [[view itemArray] valueForKey:@"representedObject"];
}
return nil;
}
/*!
@brief Returns the compound predicate types for the receiver.
@return An array of CPNumber objects specifying compound predicate types. See @c CompoundPredicateTypes for possible values.
*/
- (CPArray)compoundTypes
{
if (_templateType == 2)
{
var view = [_views objectAtIndex:0];
return [[view itemArray] valueForKey:@"representedObject"];
}
return nil;
}
/*!
@brief Returns the comparison predicate modifier for the receiver.
@return The comparison predicate modifier for the receiver.
*/
- (CPComparisonPredicateModifier)modifier
{
if (_templateType == 1)
return _predicateModifier;
return nil;
}
/*!
@brief Returns Returns the array of operators for the receiver.
@return The array of operators for the receiver.
*/
- (CPArray)operators
{
if (_templateType == 1)
{
var view = [_views objectAtIndex:1];
return [[view itemArray] valueForKey:@"representedObject"];
}
return nil;
}
/*!
@brief Returns the comparison predicate options for the receiver.
@return The comparison predicate options for the receiver. See @c CPComparisonPredicateOptions for possible values. Returns @c 0 if this does not apply (for example, for a compound template initialized with -#initWithCompoundTypes:).
*/
- (int)options
{
if (_templateType == 1)
return _predicateOptions;
return nil;
}
/*!
@brief Returns the attribute type of the receivers right expression.
@return The attribute type of the receivers right expression.
*/
- (CPAttributeType)rightExpressionAttributeType
{
return _rightAttributeType;
}
/*!
@brief Returns the attribute type of the receivers left expression.
@return The attribute type of the receivers left expression.
*/
- (CPAttributeType)leftExpressionAttributeType
{
return _leftAttributeType;
}
/*! @cond */
+ (id)_bestMatchForPredicate:(CPPredicate)predicate inTemplates:(CPArray)templates quality:(double)quality
{
var count = [templates count],
match_value = 0,
templateIndex = CPNotFound,
i;
for (i = 0; i < count; i++)
{
var template = [templates objectAtIndex:i],
amatch = [template matchForPredicate:predicate];
if (amatch > match_value)
{
templateIndex = i;
match_value = amatch;
}
}
if (templateIndex == CPNotFound)
{
[CPException raise:CPRangeException reason:@"Unable to find template matching predicate: " + [predicate predicateFormat]];
return nil;
}
return [templates objectAtIndex:templateIndex];
}
- (void)_setCompoundPredicate:(CPCompoundPredicate)predicate
{
var left = [_views objectAtIndex:0],
type = [predicate compoundPredicateType],
index = [left indexOfItemWithRepresentedObject:type];
[left selectItemAtIndex:index];
}
- (void)_setComparisonPredicate:(CPComparisonPredicate)predicate
{
var left = [_views objectAtIndex:0],
middle = [_views objectAtIndex:1],
right = [_views objectAtIndex:2],
leftExpression = [predicate leftExpression],
rightExpression = [predicate rightExpression],
operator = [predicate predicateOperatorType];
if (_leftIsWildcard)
[left setObjectValue:[leftExpression constantValue]];
else
{
var index = [left indexOfItemWithRepresentedObject:leftExpression];
[left selectItemAtIndex:index];
}
var op_index = [middle indexOfItemWithRepresentedObject:operator];
[middle selectItemAtIndex:op_index];
if (_rightIsWildcard)
[right setObjectValue:[rightExpression constantValue]];
else
{
var index = [right indexOfItemWithRepresentedObject:rightExpression];
[right selectItemAtIndex:index];
}
}
- (CPExpression)_leftExpression
{
return [self _expressionFromView:_views[0] forAttributeType:_leftAttributeType];
}
- (CPExpression)_rightExpression
{
return [self _expressionFromView:_views[2] forAttributeType:_rightAttributeType];
}
- (CPExpression)_expressionFromView:(CPView)aView forAttributeType:(CPAttributeType)attributeType
{
if (attributeType == 0)
return [[aView selectedItem] representedObject];
var value;
if (attributeType >= CPInteger16AttributeType && attributeType <= CPFloatAttributeType)
value = [aView intValue];
else if (attributeType == CPBooleanAttributeType)
value = [aView state];
else
value = [aView stringValue];
return [CPExpression expressionForConstantValue:value];
}
- (int)_rowType
{
return (_templateType - 1);
}
- (id)copy
{
return [CPKeyedUnarchiver unarchiveObjectWithData:[CPKeyedArchiver archivedDataWithRootObject:self]];
}
+ (id)_operatorsForAttributeType:(CPAttributeType)attributeType
{
var operators_array = [CPMutableArray array];
switch (attributeType)
{
case CPInteger16AttributeType : [operators_array addObjects:4,5,0,2,1,3];
break;
case CPInteger32AttributeType : [operators_array addObjects:4,5,0,2,1,3];
break;
case CPInteger64AttributeType : [operators_array addObjects:4,5,0,2,1,3];
break;
case CPDecimalAttributeType : [operators_array addObjects:4,5,0,2,1,3];
break;
case CPDoubleAttributeType : [operators_array addObjects:4,5,0,2,1,3];
break;
case CPFloatAttributeType : [operators_array addObjects:4,5,0,2,1,3];
break;
case CPStringAttributeType : [operators_array addObjects:99,4,5,8,9];
break;
case CPBooleanAttributeType : [operators_array addObjects:4,5];
break;
case CPDateAttributeType : [operators_array addObjects:4,5,0,2,1,3];
break;
default : CPLogConsole("Cannot create operators for an CPAttributeType " + attributeType);
break;
}
return operators_array;
}
- (int)_templateType
{
return _templateType;
}
- (id)_displayValueForPredicateOperator:(int)operator
{
var value;
switch (operator)
{
case CPLessThanPredicateOperatorType : value = @"is less than";
break;
case CPLessThanOrEqualToPredicateOperatorType : value = @"is less than or equal to";
break;
case CPGreaterThanPredicateOperatorType : value = @"is greater than";
break;
case CPGreaterThanOrEqualToPredicateOperatorType : value = @"is greater than or equal to";
break;
case CPEqualToPredicateOperatorType : value = @"is";
break;
case CPNotEqualToPredicateOperatorType : value = @"is not";
break;
case CPMatchesPredicateOperatorType : value = @"matches";
break;
case CPLikePredicateOperatorType : value = @"is like";
break;
case CPBeginsWithPredicateOperatorType : value = @"begins with";
break;
case CPEndsWithPredicateOperatorType : value = @"ends with";
break;
case CPInPredicateOperatorType : value = @"in";
break;
case CPContainsPredicateOperatorType : value = @"contains";
break;
case CPBetweenPredicateOperatorType : value = @"between";
break;
default : CPLogConsole(@"unknown predicate operator %d" + operator);
}
return value;
}
- (id)_displayValueForCompoundPredicateType:(unsigned int)predicateType
{
var value;
switch (predicateType)
{
case CPNotPredicateType: value = @"None";
break;
case CPAndPredicateType: value = @"All";
break;
case CPOrPredicateType: value = @"Any";
break;
default : value = [CPString stringWithFormat:@"unknown compound predicate type %d",predicateType];
}
return value;
}
- (id)_displayValueForConstantValue:(id)value
{
return [value description]; // number, date, string, ... localize
}
- (id)_displayValueForKeyPath:(CPString)keyPath
{
return keyPath; // localize
}
- (CPPopUpButton)_viewFromExpressions:(CPArray)expressions
{
var popup = [[CPPopUpButton alloc] initWithFrame:CPMakeRect(0, 0, 100, 18)],
count = [expressions count];
for (var i = 0; i < count; i++)
{
var exp = expressions[i],
type = [exp expressionType],
title;
switch (type)
{
case CPKeyPathExpressionType: title = [self _displayValueForKeyPath:[exp keyPath]];
break;
case CPConstantValueExpressionType: title = [self _displayValueForConstantValue:[exp constantValue]];
break;
default: [CPException raise:CPInvalidArgumentException reason:@"Invalid Expression type " + type];
break;
}
var item = [[CPMenuItem alloc] initWithTitle:title action:nil keyEquivalent:@""];
[item setRepresentedObject:exp];
[popup addItem:item];
}
[popup sizeToFit];
return popup;
}
- (CPPopUpButton)_viewFromOperatorTypes:(CPArray)operators
{
var popup = [[CPPopUpButton alloc] initWithFrame:CGRectMake(0, 0, 100, 18)],
count = [operators count];
for (var i = 0; i < count; i++)
{
var op = operators[i],
title = [self _displayValueForPredicateOperator:op],
item = [[CPMenuItem alloc] initWithTitle:title action:nil keyEquivalent:@""];
[item setRepresentedObject:op];
[popup addItem:item];
}
[popup sizeToFit];
return popup;
}
- (CPView)_viewFromCompoundTypes:(CPArray)compoundTypes
{
var popup = [[CPPopUpButton alloc] initWithFrame:CGRectMake(0, 0, 100, 18)],
count = [compoundTypes count];
for (var i = 0; i < count; i++)
{
var type = compoundTypes[i],
title = [self _displayValueForCompoundPredicateType:type],
item = [[CPMenuItem alloc] initWithTitle:title action:nil keyEquivalent:@""];
[item setRepresentedObject:type];
[popup addItem:item];
}
[popup sizeToFit];
return popup;
}
- (CPView)_viewFromAttributeType:(CPAttributeType)attributeType
{
var view;
if (attributeType >= CPInteger16AttributeType && attributeType <= CPFloatAttributeType)
{
view = [self _textFieldWithFrame:CGRectMake(0, 0, 50, 26)];
}
else if (attributeType == CPStringAttributeType)
{
view = [self _textFieldWithFrame:CGRectMake(0, 0, 150, 26)];
}
else if (attributeType == CPBooleanAttributeType)
{
view = [[CPCheckBox alloc] initWithFrame:CGRectMake(0, 0, 50, 26)];
}
else if (attributeType == CPDateAttributeType)
view = [[CPDatePicker alloc] initWithFrame:CGRectMake(0, 0, 150, 26)];
else
return nil;
[view setTag:attributeType];
return view;
}
- (CPTextField)_textFieldWithFrame:(CGRect)frame
{
var textField = [[CPTextField alloc] initWithFrame:frame];
[textField setBezeled:YES];
[textField setBezelStyle:CPTextFieldSquareBezel];
[textField setBordered:YES];
[textField setEditable:YES];
[textField setFont:[CPFont systemFontOfSize:10]];
return textField;
}
- (void)_setOptions:(unsigned int)options
{
_predicateOptions = options;
}
- (void)_setModifier:(unsigned int)modifier
{
_predicateModifier = modifier;
}
- (CPString)description
{
if (_templateType == 2)
return [CPString stringWithFormat:@"<%@ %p %@>",[self className],self,[[self compoundTypes] componentsJoinedByString:@", "]];
else if (_templateType == 1 && _rightIsWildcard)
return [CPString stringWithFormat:@"<%@ %p [%@] [%@] %d>",[self className],self,[[self leftExpressions] componentsJoinedByString:@", "],[[self operators] componentsJoinedByString:@", "],[self rightExpressionAttributeType]];
else
return [CPString stringWithFormat:@"<%@ %p [%@] [%@] [%@]>",[self className],self,[[self leftExpressions] componentsJoinedByString:@", "],[[self operators] componentsJoinedByString:@", "],[[self rightExpressions] componentsJoinedByString:@", "]];
}
/*
- (void)_setLeftExpressionObject:(id)object
{
}
- (void)_setRightExpressionObject:(id)object
{
}
- (BOOL)_predicateIsNoneAreTrue:(id)predicate
{
}
- (id)_viewFromExpressionObject:(id)object
{
}
*/
@end
var CPPredicateTemplateTypeKey = @"CPPredicateTemplateType",
CPPredicateTemplateOptionsKey = @"CPPredicateTemplateOptions",
CPPredicateTemplateModifierKey = @"CPPredicateTemplateModifier",
CPPredicateTemplateLeftAttributeTypeKey = @"CPPredicateTemplateLeftAttributeType",
CPPredicateTemplateRightAttributeTypeKey = @"CPPredicateTemplateRightAttributeType",
CPPredicateTemplateLeftIsWildcardKey = @"CPPredicateTemplateLeftIsWildcard",
CPPredicateTemplateRightIsWildcardKey = @"CPPredicateTemplateRightIsWildcard",
CPPredicateTemplateViewsKey = @"CPPredicateTemplateViews";
@implementation CPPredicateEditorRowTemplate (CPCoding)
- (id)initWithCoder:(CPCoder)coder
{
self = [super init];
if (self != nil)
{
_templateType = [coder decodeIntForKey:CPPredicateTemplateTypeKey];
_predicateOptions = [coder decodeIntForKey:CPPredicateTemplateOptionsKey];
_predicateModifier = [coder decodeIntForKey:CPPredicateTemplateModifierKey];
_leftAttributeType = [coder decodeIntForKey:CPPredicateTemplateLeftAttributeTypeKey];
_rightAttributeType = [coder decodeIntForKey:CPPredicateTemplateRightAttributeTypeKey];
_leftIsWildcard = [coder decodeBoolForKey:CPPredicateTemplateLeftIsWildcardKey];
_rightIsWildcard = [coder decodeBoolForKey:CPPredicateTemplateRightIsWildcardKey];
_views = [coder decodeObjectForKey:CPPredicateTemplateViewsKey];
// In Xcode 4, when the menu item title == template's expression keypath, representedObject is empty.
// So we need to regenerate expressions from titles.
if (_templateType == 1 && _leftIsWildcard == NO)
{
var itemArray = [_views[0] itemArray],
count = [itemArray count];
for (var i = 0; i < count; i++)
{
var item = itemArray[i];
if ([item representedObject] == nil)
{
var exp = [CPExpression expressionForKeyPath:[item title]];
[item setRepresentedObject:exp];
}
}
}
}
return self;
}
- (void)encodeWithCoder:(CPCoder)coder
{
[coder encodeInt:_templateType forKey:CPPredicateTemplateTypeKey];
[coder encodeInt:_predicateOptions forKey:CPPredicateTemplateOptionsKey];
[coder encodeInt:_predicateModifier forKey:CPPredicateTemplateModifierKey];
[coder encodeInt:_leftAttributeType forKey:CPPredicateTemplateLeftAttributeTypeKey];
[coder encodeInt:_rightAttributeType forKey:CPPredicateTemplateRightAttributeTypeKey];
[coder encodeBool:_leftIsWildcard forKey:CPPredicateTemplateLeftIsWildcardKey];
[coder encodeBool:_rightIsWildcard forKey:CPPredicateTemplateRightIsWildcardKey];
[coder encodeObject:_views forKey:CPPredicateTemplateViewsKey];
}
@end
/*! @endcond */
File diff suppressed because it is too large Load Diff
@@ -1,132 +0,0 @@
/*
* Created by cacaodev@gmail.com.
* Copyright (c) 2011 Pear, Inc. All rights reserved.
*/
@class _CPPredicateEditorTree;
@implementation _CPPredicateEditorRowNode : CPObject
{
_CPPredicateEditorTree tree @accessors;
CPMutableArray templateViews @accessors;
CPMutableArray copiedTemplateContainer @accessors;
CPArray children @accessors(copy);
}
+ (id)rowNodeFromTree:(id)aTree
{
var mapTable = {};
return [_CPPredicateEditorRowNode _rowNodeFromTree:aTree withTemplateTable:mapTable];
}
+ (id)_rowNodeFromTree:(id)aTree withTemplateTable:(id)templateTable
{
var node,
views,
copiedContainer;
node = [[_CPPredicateEditorRowNode alloc] init];
node.tree = aTree;
var template = [aTree template],
uuid = [template UID];
var cachedNode = templateTable[uuid];
if (cachedNode == nil)
{
views = [CPMutableArray array];
copiedContainer = [CPMutableArray array];
templateTable[uuid] = node;
}
else
{
views = [cachedNode templateViews];
copiedContainer = [cachedNode copiedTemplateContainer];
}
node.templateViews = views;
node.copiedTemplateContainer = copiedContainer;
var nodeChildren = [CPMutableArray array],
treeChildren = [aTree children],
count = [treeChildren count];
for (var i = 0; i < count; i++)
{
var treeChild = treeChildren[i],
child = [_CPPredicateEditorRowNode _rowNodeFromTree:treeChild withTemplateTable:templateTable];
[nodeChildren addObject:child];
}
[node setChildren:nodeChildren];
return node;
}
- (BOOL)applyTemplate:(id)template withViews:(id)views forOriginalTemplate:(id)originalTemplate
{
var t = [tree template];
if (t !== template)
{
[templateViews setArray:views];
[copiedTemplateContainer removeAllObjects];
[copiedTemplateContainer addObject:template];
}
var count = [children count];
for (var i; i < count; i++)
[children[i] applyTemplate:template withViews:views forOriginalTemplate:originalTemplate];
}
- (BOOL)isEqual:(id)node
{
if (![node isKindOfClass:[_CPPredicateEditorRowNode class]])
return NO;
return (tree === [node tree]);
}
- (void)copyTemplateIfNecessary
{
if ([copiedTemplateContainer count] == 0)
{
CPLogConsole("COPYING TEMPLATE");
var copy = [[tree template] copy];
[copiedTemplateContainer addObject:copy];
[templateViews addObjectsFromArray:[copy templateViews]];
}
}
- (CPView)templateView
{
[self copyTemplateIfNecessary];
return [templateViews objectAtIndex:[tree indexIntoTemplate]];
}
- (id)templateForRow
{
[self copyTemplateIfNecessary];
return [copiedTemplateContainer lastObject];
}
- (CPString)title
{
return [tree title];
}
- (id)displayValue
{
var title = [self title];
if (title != nil)
return title;
return [self templateView];
}
- (CPString)description
{
return [CPString stringWithFormat:@"<%@ %@ %@ tree:%@ tviews:%@", [self className],[self UID], [self title], [tree UID], [templateViews description]];
}
@end
@@ -1,33 +0,0 @@
/*
* Created by cacaodev@gmail.com.
* Copyright (c) 2011 Pear, Inc. All rights reserved.
*/
@implementation _CPPredicateEditorTree : CPObject
{
CPPredicateEditorRowTemplate template @accessors;
CPString title @accessors(copy);
CPArray children @accessors(copy);
CPInteger indexIntoTemplate @accessors;
CPInteger menuItemIndex @accessors;
}
- (id)copy
{
var tree = [[_CPPredicateEditorTree alloc] init];
[tree setTemplate:template];
[tree setTitle:title];
[tree setMenuItemIndex:menuItemIndex];
[tree setIndexIntoTemplate:indexIntoTemplate];
[tree setChildren:children];
return tree;
}
- (CPString)description
{
return [CPString stringWithFormat:@"<%@: %p (%@) [%d-%d] T:%p at:%d> [\r%@\r]", [self className], self, title, indexIntoTemplate, menuItemIndex, template, [template rightExpressionAttributeType], children];
}
@end
@@ -1,75 +0,0 @@
/*
* Created by cacaodev@gmail.com.
* Copyright (c) 2011 Pear, Inc. All rights reserved.
*/
@import <Foundation/CPObject.j>
@import <Foundation/CPDictionary.j>
@import <Foundation/CPString.j>
var regex = new RegExp("\"(.+)\"\\s*=\\s*\"(.+)\"\\s*;\\s*(//.+)?");
@implementation _CPRuleEditorLocalizer : CPObject
{
CPDictionary _dictionary @accessors(property=dictionary);
CPURLConnection connection;
CPURLRequest resquest;
}
- (void)loadContentOfURL:(CPURL)aURL
{
request = [CPURLRequest requestWithURL:aURL];
connection = [CPURLConnection connectionWithRequest:request delegate:self];
}
- (void)reloadIfNeeded
{
if (connection != nil) // Connection waiting
{
connection = nil;
var data = [CPURLConnection sendSynchronousRequest:request returningResponse:NULL];
[self loadContent:[data rawString]];
}
}
- (void)connection:(CPURLConnection)aConnection didReceiveData:(CPString)rawString
{
if (connection != nil && rawString != nil)
[self loadContent:rawString];
connection = nil;
}
- (void)loadContent:(CPString)aContent
{
var dict = [CPDictionary dictionary],
lines = [aContent componentsSeparatedByString:"\n"],
count = [lines count];
for (var i = 0 ; i < count ; i++)
{
var line = [lines objectAtIndex:i];
if (line.length > 1)
{
var match = regex.exec(line);
if (match.length >= 3)
[dict setObject:match[2] forKey:match[1]];
}
}
_dictionary = [CPDictionary dictionaryWithDictionary:dict];
}
- (CPString)localizedStringForString:(CPString)aString
{
[self reloadIfNeeded];
if (_dictionary != nil && aString != nil)
{
var localized = [_dictionary objectForKey:aString];
if (localized != nil)
return localized;
}
return aString;
}
@@ -1,157 +0,0 @@
/*
* Created by cacaodev@gmail.com.
* Copyright (c) 2011 Pear, Inc. All rights reserved.
*/
var GRADIENT_NORMAL,
GRADIENT_HIGHLIGHTED,
IE_FILTER = "progid:DXImageTransform.Microsoft.gradient(startColorstr='#fcfcfc', endColorstr='#dfdfdf')";
@implementation _CPRuleEditorPopUpButton : CPPopUpButton
{
CPInteger radius;
}
+ (void)initialize
{
if (CPBrowserIsEngine(CPWebKitBrowserEngine))
{
GRADIENT_NORMAL = "-webkit-gradient(linear, left top, left bottom, from(rgb(252, 252, 252)), to(rgb(223, 223, 223)))",
GRADIENT_HIGHLIGHTED = "-webkit-gradient(linear, left top, left bottom, from(rgb(223, 223, 223)), to(rgb(252, 252, 252)))";
}
else if (CPBrowserIsEngine(CPGeckoBrowserEngine))
{
GRADIENT_NORMAL = "-moz-linear-gradient(top, rgb(252, 252, 252), rgb(223, 223, 223))",
GRADIENT_HIGHLIGHTED = "-moz-linear-gradient(top, rgb(223, 223, 223), rgb(252, 252, 252))";
}
}
- (id)initWithFrame:(CGRect)aFrame
{
if (self = [super initWithFrame:aFrame])
{
var style = _DOMElement.style;
style.backgroundImage = GRADIENT_NORMAL;
style.border = "1px solid rgb(189, 189, 189)";
style.filter = IE_FILTER;
[self setTextColor:[CPColor colorWithWhite:101/255 alpha:1]];
[self setBordered:NO];
}
return self;
}
- (id)hitTest:(CPPoint)point
{
var slice = [self superview];
if (!CPRectContainsPoint([self frame], point) || ![self sliceIsEditable])
return nil;
return self;
}
- (void)setHighlighted:(BOOL)shouldHighlight
{
_DOMElement.style.backgroundImage = (shouldHighlight) ? GRADIENT_HIGHLIGHTED : GRADIENT_NORMAL;
}
- (BOOL)sliceIsEditable
{
return [[self superview] isEditable];
}
- (BOOL)trackMouse:(CPEvent)theEvent
{
if (![self sliceIsEditable])
return NO;
return [super trackMouse:theEvent];
}
- (CGRect)contentRectForBounds:(CGRect)bounds
{
var contentRect = [super contentRectForBounds:bounds];
contentRect.origin.x += radius;
contentRect.size.width -= 2 * radius;
return contentRect;
}
- (void)layoutSubviews
{
radius = FLOOR(CGRectGetHeight([self bounds])/2);
var style = _DOMElement.style,
radiusCSS = radius + "px";
//style.webkitBorderRadius = radiusCSS;
//style.mozBorderRadius = radiusCSS;
style.borderRadius = radiusCSS;
[super layoutSubviews];
}
- (void)drawRect:(CGRect)aRect
{
var bounds = [self bounds],
context = [[CPGraphicsContext currentContext] graphicsPort];
var arrow_width = FLOOR(CGRectGetHeight(bounds)/3.5);
CGContextTranslateCTM(context, CGRectGetWidth(bounds) - radius - arrow_width, CGRectGetHeight(bounds) / 2);
var arrowsPath = [CPBezierPath bezierPath];
[arrowsPath moveToPoint:CGPointMake(0, 1)];
[arrowsPath lineToPoint:CGPointMake(arrow_width, 1)];
[arrowsPath lineToPoint:CGPointMake(arrow_width/2, arrow_width + 1)];
[arrowsPath closePath];
CGContextSetFillColor(context, [CPColor colorWithWhite:101/255 alpha:1]);
[arrowsPath fill];
CGContextScaleCTM(context, 1 , -1);
[arrowsPath fill];
}
@end
@implementation _CPRuleEditorButton : CPButton
{
CPInteger radius;
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
[self setFont:[CPFont boldFontWithName:@"Apple Symbol" size:12.0]];
[self setTextColor:[CPColor colorWithWhite:150/255 alpha:1]];
[self setAlignment:CPCenterTextAlignment];
[self setAutoresizingMask:CPViewMinXMargin];
[self setImagePosition:CPImageOnly];
[self setBordered:NO];
var style = _DOMElement.style;
style.border = "1px solid rgb(189, 189, 189)";
style.filter = IE_FILTER;
}
return self;
}
- (void)layoutSubviews
{
radius = FLOOR(CGRectGetHeight([self bounds])/2);
var style = _DOMElement.style,
radiusCSS = radius + "px";
style.borderRadius = radiusCSS;
style.backgroundImage = ([self isHighlighted]) ? GRADIENT_HIGHLIGHTED : GRADIENT_NORMAL;
[super layoutSubviews];
}
@end
@@ -1,109 +0,0 @@
/*
* Created by cacaodev@gmail.com.
* Copyright (c) 2011 Pear, Inc. All rights reserved.
*/
@implementation _CPRuleEditorViewSlice : CPView
{
CPRuleEditor _ruleEditor;
int _indentation @accessors(property=indentation);
int _rowIndex @accessors(property=rowIndex);
CPRect _animationTargetRect @accessors(property=_animationTargetRect);
BOOL _selected @accessors(getter=_isSelected, setter=_setSelected:);
BOOL _lastSelected @accessors(getter=_isLastSelected, setter=_setLastSelected:);
CPColor _backgroundColor @accessors(property=backgroundColor);
}
- (void)removeFromSuperview
{
[super removeFromSuperview];
}
- (id)initWithFrame:(CGRect)frame ruleEditorView:(id)editor
{
if (self = [super initWithFrame:frame])
{
_ruleEditor = editor;
_selected = NO;
_lastSelected = NO;
}
return self;
}
- (void)_setSelected:(BOOL)select
{
if (select == _selected)
return;
var selector = select ? @"setThemeState:" : @"unsetThemeState:";
[[self subviews] makeObjectsPerformSelector:CPSelectorFromString(selector) withObject:CPThemeStateSelectedDataView];
_selected = select;
}
- (void)drawRect:(CPRect)rect
{
var context = [[CPGraphicsContext currentContext] graphicsPort],
bounds = [self bounds],
maxX = CGRectGetWidth(bounds) - 2,
maxY = CGRectGetHeight(bounds);
// Draw background
if ([self _isSelected])
_backgroundColor = [_ruleEditor _selectedRowColor];
else
{
var colors = [_ruleEditor _backgroundColors],
count = [colors count];
_backgroundColor = [colors objectAtIndex:(_rowIndex % count)];
}
CGContextSetFillColor(context, _backgroundColor);
CGContextFillRect(context, rect);
// Draw Top Border
CGContextBeginPath(context);
CGContextMoveToPoint(context, 1, 0);
CGContextAddLineToPoint(context, maxX, 0);
CGContextClosePath(context);
CGContextSetStrokeColor(context, [_ruleEditor _sliceTopBorderColor]);
CGContextStrokePath(context);
// Draw Bottom Border
CGContextBeginPath(context);
CGContextMoveToPoint(context, 1, maxY - 0.5);
CGContextAddLineToPoint(context, maxX, maxY - 0.5);
CGContextClosePath(context);
var bottomColor = (_rowIndex == [_ruleEditor _lastRow]) ? [_ruleEditor _sliceLastBottomBorderColor] : [_ruleEditor _sliceBottomBorderColor];
CGContextSetStrokeColor(context, bottomColor);
CGContextStrokePath(context);
}
- (void)mouseDown:(CPEvent)theEvent
{
if (editable)
[_ruleEditor _mouseDownOnSlice:self withEvent:theEvent];
}
- (void)mouseUp:(CPEvent)theEvent
{
if (editable)
[_ruleEditor _mouseUpOnSlice:self withEvent:theEvent];
}
/*
- (void)rightMouseDown:(CPEvent)theEvent
{
[_ruleEditor _rightMouseDownOnSlice:self withEvent:theEvent];
}
*/
// =========
// ! DEBUG
// =========
- (CPString)description
{
return [CPString stringWithFormat:@"<%@ %p index:%d indentation:%d>",[self className],self,[self rowIndex],[self indentation]];
}
@end
@@ -1,512 +0,0 @@
/*
* Created by cacaodev@gmail.com.
* Copyright (c) 2011 Pear, Inc. All rights reserved.
*/
@import "_CPRuleEditorViewSlice.j"
@import "_CPRuleEditorPopUpButton.j"
@import "CPRuleEditor.j"
var CONTROL_HEIGHT = 16.,
BUTTON_HEIGHT = 16.;
@implementation _CPRuleEditorViewSliceRow : _CPRuleEditorViewSlice
{
CPMutableArray _ruleOptionViews;
CPMutableArray _ruleOptionFrames;
CPMutableArray _correspondingRuleItems;
CPMutableArray _ruleOptionInitialViewFrames;
CPButton _addButton;
CPButton _subtractButton;
BOOL editable;
CPRuleEditorRowType _rowType @accessors;
CPRuleEditorRowType _plusButtonRowType;
}
- (id)initWithFrame:(CGRect)frame ruleEditorView:(id)editor
{
if (self = [super initWithFrame:frame ruleEditorView:editor])
[self _initShared];
return self;
}
- (void)_initShared
{
_correspondingRuleItems = [[CPMutableArray alloc] init];
_ruleOptionFrames = [[CPMutableArray alloc] init];
_ruleOptionInitialViewFrames = [[CPMutableArray alloc] init];
_ruleOptionViews = [[CPMutableArray alloc] init];
editable = [_ruleEditor isEditable];
_addButton = [self _createAddRowButton];
_subtractButton = [self _createDeleteRowButton];
//[_addButton setToolTip:[_ruleEditor _toolTipForAddSimpleRowButton]];
//[_subtractButton setToolTip:[_ruleEditor _toolTipForDeleteRowButton]];
[_addButton setHidden:!editable];
[_subtractButton setHidden:!editable];
[self addSubview:_addButton];
[self addSubview:_subtractButton];
[self setAutoresizingMask:CPViewWidthSizable];
var center = [CPNotificationCenter defaultCenter];
[center addObserver:self selector:@selector(_textDidChange:) name:CPControlTextDidChangeNotification object:nil];
}
- (CPButton)_createAddRowButton
{
var button = [[_CPRuleEditorButton alloc] initWithFrame:CGRectMakeZero()];
[button setImage:[_ruleEditor _addImage]];
[button setAction:@selector(_addOption:)];
[button setTarget:self];
[button setAutoresizingMask:CPViewMinXMargin];
return button;
}
- (CPButton)_createDeleteRowButton
{
var button = [[_CPRuleEditorButton alloc] initWithFrame:CGRectMakeZero()];
[button setImage:[_ruleEditor _removeImage]];
[button setAction:@selector(_deleteOption:)];
[button setTarget:self];
[button setAutoresizingMask:CPViewMinXMargin];
return button;
}
- (CPMenuItem)_createMenuItemWithTitle:(CPString )title
{
title = [[_ruleEditor standardLocalizer] localizedStringForString:title];
var mItem = [[CPMenuItem alloc] initWithTitle:title action:nil keyEquivalent:@""];
return mItem;
}
- (CPPopUpButton)_createPopUpButtonWithItems:(CPArray)itemsArray selectedItemIndex:(int)index
{
var title = [[itemsArray objectAtIndex:index] title];
var font = [_ruleEditor font],
width = [title sizeWithFont:font].width + 20,
rect = CGRectMake(0, 0, (width - width % 40) + 80, CONTROL_HEIGHT);
var popup = [[_CPRuleEditorPopUpButton alloc] initWithFrame:rect];
[popup setValue:font forThemeAttribute:@"font"];
var count = [itemsArray count];
for (var i = 0; i < count; i++)
[popup addItem:[itemsArray objectAtIndex:i]];
[popup selectItemAtIndex:index];
return popup;
}
- (CPMenuItem)_createMenuSeparatorItem
{
return [CPMenuItem separatorItem];
}
- (_CPRuleEditorTextField)_createStaticTextFieldWithStringValue:(CPString )text
{
text = [[_ruleEditor standardLocalizer] localizedStringForString:text];
var textField = [[_CPRuleEditorTextField alloc] initWithFrame:CPMakeRect(0, 0, 200, CONTROL_HEIGHT)];
var font = [_ruleEditor font];
font = [CPFont fontWithName:font._name size:font._size + 2];
[textField setValue:font forThemeAttribute:@"font"];
[textField setStringValue:text];
[textField sizeToFit];
return textField;
}
- (void)_addOption:(id)sender
{
if (_rowIndex == [_ruleEditor numberOfRows] - 1)
[self setNeedsDisplay:YES];
var type = _plusButtonRowType;
if ([_ruleEditor nestingMode] == CPRuleEditorNestingModeCompound && ([[CPApp currentEvent] modifierFlags] & CPAlternateKeyMask))
type = CPRuleEditorRowTypeCompound;
[_ruleEditor _addOptionFromSlice:self ofRowType:type];
}
- (void)_deleteOption:(id)sender
{
[_ruleEditor _deleteSlice:self];
}
- (void)_ruleOptionPopupChangedAction:(CPMenuItem )sender
{
var layoutdict = [sender representedObject],
newItem = [layoutdict objectForKey:@"item"],
indexInCriteria = [layoutdict objectForKey:@"indexInCriteria"],
oldItem = [_correspondingRuleItems objectAtIndex:indexInCriteria];
if (![newItem isEqual:oldItem])
{
[_correspondingRuleItems replaceObjectAtIndex:indexInCriteria withObject:newItem];
[_ruleEditor _changedItem:oldItem toItem:newItem inRow:_rowIndex atCriteriaIndex:indexInCriteria];
}
}
- (BOOL)validateMenuItem:(CPMenuItem )menuItem
{
return [_ruleEditor _validateItem:menuItem value:[[menuItem representedObject] valueForKey:@"item"] inRow:_rowIndex];
}
- (void)_emptyRulePartSubviews
{
var count = [_ruleOptionViews count];
while (count--)
[_ruleOptionViews[count] removeFromSuperview];
[_ruleOptionViews removeAllObjects];
[_ruleOptionFrames removeAllObjects];
[_ruleOptionInitialViewFrames removeAllObjects];
}
- (void)_reconfigureSubviews
{
var ruleItems,
criteria,
repObject,
menuItem,
ruleView,
criterion,
parent,
numberOfCriteria,
numberOfChildren,
firstResponderIndex;
var ruleItems = [CPMutableArray array];
[self _emptyRulePartSubviews];
criteria = [_ruleEditor criteriaForRow:_rowIndex];
numberOfCriteria = [criteria count];
firstResponderIndex = numberOfCriteria - 1;
var responder = [[self window] firstResponder];
if (responder)
firstResponderIndex = [_ruleOptionViews indexOfObjectIdenticalTo:responder];
for (var i = 0; i < numberOfCriteria; i++)
{
ruleView = nil;
parent = nil;
criterion = [criteria objectAtIndex:i];
if (i > 0)
parent = [criteria objectAtIndex:i - 1];
var childItems = [],
childValues = [];
[_ruleEditor _getAllAvailableItems:childItems values:childValues asChildrenOfItem:parent inRow:_rowIndex];
numberOfChildren = [childItems count];
if (numberOfChildren > 1)
{
var menuItems = [CPMutableArray arrayWithCapacity:numberOfChildren];
var selectedIndex = [childItems indexOfObject:criterion];
if (selectedIndex == CPNotFound)
break;
for (var j = 0; j < numberOfChildren; ++j)
{
var childItem = [childItems objectAtIndex:j];
var childValue = [childValues objectAtIndex:j];
if ([childValue isKindOfClass:[CPMenuItem class]])
{
[[childValue menu] removeItem:childValue];
menuItem = childValue;
}
else
{
if ([childValue isEqualToString:@""])
menuItem = [self _createMenuSeparatorItem];
else
{
menuItem = [self _createMenuItemWithTitle:childValue];
[menuItem setTarget:self];
[menuItem setAction:@selector(_ruleOptionPopupChangedAction:)];
}
}
repObject = [CPDictionary dictionaryWithObjectsAndKeys:childItem, @"item", childValue, @"value", i, @"indexInCriteria"];
[menuItem setRepresentedObject:repObject];
[menuItems addObject:menuItem];
}
ruleView = [self _createPopUpButtonWithItems:menuItems selectedItemIndex:selectedIndex];
}
else
{
var value = [childValues objectAtIndex:0];
var type = [value valueType];
if (type === 0)
ruleView = [self _createStaticTextFieldWithStringValue:value];
else
{
if (type !== 1)
{
[CPException raise:CPInternalInconsistencyException reason:@"Display value must be a string or a menu item"];
continue;
}
ruleView = value;
[ruleView setTarget:self];
[ruleView setAction:@selector(_sendRuleAction:)];
if ([ruleView respondsToSelector:@selector(setDelegate:)])
[ruleView setDelegate:self];
}
}
if (ruleView != nil)
{
[_ruleOptionViews addObject:ruleView];
var frame = [ruleView frame];
[_ruleOptionInitialViewFrames addObject:frame];
[_ruleOptionFrames addObject:frame];
if (!criterion)
criterion = [CPNull null];
[ruleItems addObject:criterion];
}
}
[_correspondingRuleItems setArray:ruleItems];
if (!editable)
[self _updateEnabledStateForSubviews];
[self _relayoutSubviewsWidthChanged:YES];
if (firstResponderIndex != CPNotFound)
{
var aView = [_ruleOptionViews objectAtIndex:firstResponderIndex];
[[self window] makeFirstResponder:aView]; // This is not working. bug in CPPopUpButton firstResponder ?
}
//[self setNeedsDisplay:YES];
}
- (void)_updateEnabledStateForSubviews
{
[_ruleOptionViews makeObjectsPerformSelector:@selector(setEnabled:) withObject:NO];
}
- (void)layoutSubviews
{
// CPLogConsole(_cmd);
[self _relayoutSubviewsWidthChanged:YES];
}
- (void)_relayoutSubviewsWidthChanged:(BOOL)widthChanged
{
var optionViewOriginX,
leftHorizontalPadding,
leftButtonMinX,
rowHeight = [_ruleEditor rowHeight],
count = [_ruleOptionViews count],
sliceFrame = [self frame];
var buttonFrame = CGRectMake(CGRectGetWidth(sliceFrame) - BUTTON_HEIGHT - [self _rowButtonsRightHorizontalPadding], ([_ruleEditor rowHeight] - BUTTON_HEIGHT)/2 - 2, BUTTON_HEIGHT, BUTTON_HEIGHT);
[_addButton setFrame:buttonFrame];
buttonFrame.origin.x -= BUTTON_HEIGHT + [self _rowButtonsInterviewHorizontalPadding];
[_subtractButton setFrame:buttonFrame];
if (widthChanged)
{
optionViewOriginX = [self _leftmostViewFixedHorizontalPadding] + [self _indentationHorizontalPadding] * _indentation;
leftHorizontalPadding = [self _rowButtonsLeftHorizontalPadding];
leftButtonMinX = CGRectGetMinX(buttonFrame);
}
for (var i = 0; i < count; i++)
{
var ruleOptionView = _ruleOptionViews[i],
optionFrame = _ruleOptionFrames[i];
optionFrame.origin.y = (rowHeight - CGRectGetHeight(optionFrame))/2 - 2;
if (widthChanged)
{
optionFrame.origin.x = optionViewOriginX;
if (i == count - 1 && ![self _isRulePopup:ruleOptionView])
{
var initialFrame = _ruleOptionInitialViewFrames[i];
optionFrame.size.width = MIN(CGRectGetWidth(initialFrame), leftButtonMinX - leftHorizontalPadding - optionViewOriginX);
}
}
[ruleOptionView setFrame:optionFrame];
[self addSubview:ruleOptionView];
if (widthChanged)
optionViewOriginX += CGRectGetWidth(optionFrame) + [self _interviewHorizontalPadding];
}
}
- (void)_updateButtonVisibilities
{
[_addButton setHidden:[_ruleEditor _shouldHideAddButtonForSlice:self]];
[_subtractButton setHidden:[_ruleEditor _shouldHideSubtractButtonForSlice:self]];
}
- (void)_configurePlusButtonByRowType:(CPRuleEditorRowType)type
{
[self _setRowTypeToAddFromPlusButton:type];
}
- (BOOL)isEditable
{
return editable;
}
- (void)setEditable:(BOOL)value
{
editable = value;
// [self _updateEnabledStateForSubviews];
[self _updateButtonVisibilities];
}
- (float)_alignmentGridWidth
{
return [_ruleEditor _alignmentGridWidth];
}
- (float)_indentationHorizontalPadding
{
return 30.;
}
- (float)_interviewHorizontalPadding
{
return 6.;
}
- (float)_leftmostViewFixedHorizontalPadding
{
return 7.;
}
- (float)_minimumVerticalPopupPadding
{
return 2.;
}
- (float)_rowButtonsInterviewHorizontalPadding
{
return 6.;
}
- (float)_rowButtonsLeftHorizontalPadding
{
return 10.;
}
- (float)_rowButtonsRightHorizontalPadding
{
return 10.;
}
- (void)_setRowTypeToAddFromPlusButton:(int)type
{
_plusButtonRowType = type;
}
- (void)setNeedsDisplay:(BOOL)flag
{
[super setNeedsDisplay:flag];
}
- (BOOL)_nestingModeShouldHideAddButton
{
return [_ruleEditor _applicableNestingMode] == CPRuleEditorNestingModeSingle;
}
- (BOOL)_nestingModeShouldHideSubtractButton
{
return [_ruleEditor _applicableNestingMode] == CPRuleEditorNestingModeSingle;
}
- (BOOL)containsDisplayValue:(id)value
{
return [[_ruleEditor displayValuesForRow:_rowIndex] containsObject:value];
// Ou alors avec _correspondingRuleItems
}
- (void)viewDidMoveToWindow
{
[self layoutSubviews];
}
- (void)drawRect:(CPRect)rect
{
[super drawRect:rect];
}
- (BOOL)_isRulePopup:(CPView)view
{
if ([view isKindOfClass:[_CPRuleEditorPopUpButton class]])
return YES;
return NO;
}
- (BOOL)_isRuleStaticTextField:(CPView)view
{
if ([view isKindOfClass:[_CPRuleEditorTextField class]])
return YES;
return NO;
}
- (void)_sendRuleAction:(id)sender
{
[_ruleEditor _sendRuleAction];
}
- (void)_textDidChange:(CPNotification)aNotif
{
if ([[aNotif object] superview] == self && [_ruleEditor _sendsActionOnIncompleteTextChange])
[_ruleEditor _sendRuleAction];
}
@end
@implementation _CPRuleEditorTextField : CPTextField
{
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self != nil)
{
[self setBordered:NO];
[self setEditable:NO];
[self setDrawsBackground:NO];
}
return self;
}
- (id)hitTest:(CPPoint)point
{
if (!CPRectContainsPoint([self frame], point))
return nil;
return [self superview];
}
@end
+1 -22
View File
@@ -1,26 +1,5 @@
/*
* CPSavePanel.j
* AppKit
*
* Created by Francisco Tolmasky.
* Copyright 2009, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPPanel.j"
@import <AppKit/CPPanel.j>
@implementation CPSavePanel : CPPanel
+4 -36
View File
@@ -1,45 +1,13 @@
/*
* CPScreen.j
* AppKit
*
* Created by Francisco Tolmasky.
* Copyright 2009, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPObject.j>
/*!
@ingroup appkit
@class CPScreen
#import "CoreGraphics/CGGeometry.h"
#import "Platform/Platform.h"
A CPScreen object describes the attributes of a display device available
to Cappuccino.
*/
@implementation CPScreen : CPObject
{
}
/*!
Returns the position and size of the visible area of the receiving screen.
This will normally be smaller than the full size of the screen to account
for system UI elements. For example, on a Mac the top of the visible frame
is placed below the bottom of the menu bar.
@return the visible screen rectangle
*/
- (CGRect)visibleFrame
{
#if PLATFORM(DOM)
@@ -49,4 +17,4 @@
#endif
}
@end
@end
+100 -392
View File
@@ -20,13 +20,14 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPBox.j"
@import "CPView.j"
@import "CPClipView.j"
@import "CPScroller.j"
@import "CPView.j"
#include "CoreGraphics/CGGeometry.h"
/*!
/*!
@ingroup appkit
@class CPScrollView
@@ -36,39 +37,23 @@
*/
@implementation CPScrollView : CPView
{
CPClipView _contentView;
CPClipView _headerClipView;
CPView _cornerView;
CPView _bottomCornerView;
CPClipView _contentView;
CPClipView _headerClipView;
CPView _cornerView;
BOOL _hasVerticalScroller;
BOOL _hasHorizontalScroller;
BOOL _autohidesScrollers;
CPScroller _verticalScroller;
CPScroller _horizontalScroller;
int _recursionCount;
float _verticalLineScroll;
float _verticalPageScroll;
float _horizontalLineScroll;
float _horizontalPageScroll;
CPBorderType _borderType;
}
+ (CPString)defaultThemeClass
{
return @"scrollview"
}
+ (CPDictionary)themeAttributes
{
return [CPDictionary dictionaryWithJSObject:{
@"bottom-corner-color": [CPColor whiteColor],
@"border-color": [CPColor blackColor]
}];
BOOL _hasVerticalScroller;
BOOL _hasHorizontalScroller;
BOOL _autohidesScrollers;
CPScroller _verticalScroller;
CPScroller _horizontalScroller;
int _recursionCount;
float _verticalLineScroll;
float _verticalPageScroll;
float _horizontalLineScroll;
float _horizontalPageScroll;
}
- (id)initWithFrame:(CGRect)aFrame
@@ -83,17 +68,13 @@
_horizontalLineScroll = 10.0;
_horizontalPageScroll = 10.0;
_borderType = CPNoBorder;
_contentView = [[CPClipView alloc] initWithFrame:[self _insetBounds]];
_contentView = [[CPClipView alloc] initWithFrame:[self bounds]];
[self addSubview:_contentView];
_headerClipView = [[CPClipView alloc] init];
[self addSubview:_headerClipView];
_bottomCornerView = [[CPView alloc] init];
[self addSubview:_bottomCornerView];
[self addSubview:_headerClipView];
[self setHasVerticalScroller:YES];
[self setHasHorizontalScroller:YES];
@@ -102,70 +83,11 @@
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.
*/
- (CGSize)contentSize
- (CGRect)contentSize
{
return [_contentView frame].size;
}
@@ -184,7 +106,7 @@
*/
- (void)setContentView:(CPClipView)aContentView
{
if (_contentView === aContentView || !aContentView)
if (_contentView !== aContentView || !aContentView)
return;
var documentView = [aContentView documentView];
@@ -231,16 +153,16 @@
*/
- (void)reflectScrolledClipView:(CPClipView)aClipView
{
if (_contentView !== aClipView)
if(_contentView !== aClipView)
return;
if (_recursionCount > 5)
return;
++_recursionCount;
var documentView = [self documentView];
if (!documentView)
{
if (_autohidesScrollers)
@@ -254,7 +176,7 @@
// [_horizontalScroller setEnabled:NO];
}
[_contentView setFrame:[self _insetBounds]];
[_contentView setFrame:[self bounds]];
[_headerClipView setFrame:_CGRectMakeZero()];
--_recursionCount;
@@ -263,7 +185,7 @@
}
var documentFrame = [documentView frame], // the size of the whole document
contentFrame = [self _insetBounds], // assume it takes up the entire size of the scrollview (no scrollers)
contentFrame = [self bounds], // assume it takes up the entire size of the scrollview (no scrollers)
headerClipViewFrame = [self _headerClipViewFrame],
headerClipViewHeight = _CGRectGetHeight(headerClipViewFrame);
@@ -313,10 +235,11 @@
if (shouldShowVerticalScroller)
{
var verticalScrollerY =
MAX(_CGRectGetMinY(contentFrame), MAX(_CGRectGetMaxY([self _cornerViewFrame]), _CGRectGetMaxY(headerClipViewFrame)));
var verticalScrollerY = MAX(_CGRectGetHeight([self _cornerViewFrame]), headerClipViewHeight),
verticalScrollerHeight = _CGRectGetHeight([self bounds]) - verticalScrollerY;
var verticalScrollerHeight = _CGRectGetMaxY(contentFrame) - verticalScrollerY;
if (shouldShowHorizontalScroller)
verticalScrollerHeight -= horizontalScrollerHeight;
[_verticalScroller setFloatValue:(difference.height <= 0.0) ? 0.0 : scrollPoint.y / difference.height];
[_verticalScroller setKnobProportion:_CGRectGetHeight(contentFrame) / _CGRectGetHeight(documentFrame)];
@@ -327,12 +250,12 @@
[_verticalScroller setFloatValue:0.0];
[_verticalScroller setKnobProportion:1.0];
}
if (shouldShowHorizontalScroller)
{
[_horizontalScroller setFloatValue:(difference.width <= 0.0) ? 0.0 : scrollPoint.x / difference.width];
[_horizontalScroller setKnobProportion:_CGRectGetWidth(contentFrame) / _CGRectGetWidth(documentFrame)];
[_horizontalScroller setFrame:_CGRectMake(_CGRectGetMinX(contentFrame), _CGRectGetMaxY(contentFrame), _CGRectGetWidth(contentFrame), horizontalScrollerHeight)];
[_horizontalScroller setFrame:_CGRectMake(0.0, _CGRectGetMaxY(contentFrame), _CGRectGetWidth(contentFrame), horizontalScrollerHeight)];
}
else if (wasShowingHorizontalScroller)
{
@@ -342,45 +265,11 @@
[_contentView setFrame:contentFrame];
[_headerClipView setFrame:headerClipViewFrame];
[[_headerClipView documentView] setNeedsDisplay:YES];
[_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.
Valid types are:
<pre>
CPNoBorder
CPLineBorder
CPBezelBorder
CPGrooveBorder</pre>
*/
- (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.
@@ -390,13 +279,13 @@
{
if (_horizontalScroller === aScroller)
return;
[_horizontalScroller removeFromSuperview];
[_horizontalScroller setTarget:nil];
[_horizontalScroller setAction:nil];
_horizontalScroller = aScroller;
[_horizontalScroller setTarget:self];
[_horizontalScroller setAction:@selector(_horizontalScrollerDidScroll:)];
@@ -427,10 +316,8 @@
if (_hasHorizontalScroller && !_horizontalScroller)
{
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 setHorizontalScroller:[[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, MAX(_CGRectGetWidth([self bounds]), [CPScroller scrollerWidth]+1), [CPScroller scrollerWidth])]];
[[self horizontalScroller] setFrameSize:CGSizeMake(_CGRectGetWidth([self bounds]), [CPScroller scrollerWidth])];
}
[self reflectScrolledClipView:_contentView];
@@ -452,13 +339,13 @@
{
if (_verticalScroller === aScroller)
return;
[_verticalScroller removeFromSuperview];
[_verticalScroller setTarget:nil];
[_verticalScroller setAction:nil];
_verticalScroller = aScroller;
[_verticalScroller setTarget:self];
[_verticalScroller setAction:@selector(_verticalScrollerDidScroll:)];
@@ -490,10 +377,8 @@
if (_hasVerticalScroller && !_verticalScroller)
{
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 setVerticalScroller:[[CPScroller alloc] initWithFrame:_CGRectMake(0.0, 0.0, [CPScroller scrollerWidth], MAX(_CGRectGetHeight([self bounds]), [CPScroller scrollerWidth]+1))]];
[[self verticalScroller] setFrameSize:CGSizeMake([CPScroller scrollerWidth], _CGRectGetHeight([self bounds]))];
}
[self reflectScrolledClipView:_contentView];
@@ -508,7 +393,7 @@
}
/*!
Sets whether the scroll view hides its scroll bars when not needed.
Sets whether the scroll view hides its scoll bars when not needed.
@param autohidesScrollers \c YES causes the scroll bars
to be hidden when not needed.
*/
@@ -518,7 +403,7 @@
return;
_autohidesScrollers = autohidesScrollers;
[self reflectScrolledClipView:_contentView];
}
@@ -568,11 +453,11 @@
if (!_cornerView)
return _CGRectMakeZero();
var bounds = [self _insetBounds],
var bounds = [self bounds],
frame = [_cornerView frame];
frame.origin.x = _CGRectGetMaxX(bounds) - _CGRectGetWidth(frame);
frame.origin.y = _CGRectGetMinY(bounds);
frame.origin.y = 0;
return frame;
}
@@ -584,7 +469,7 @@
if (!headerView)
return _CGRectMakeZero();
var frame = [self _insetBounds];
var frame = [self bounds];
frame.size.height = _CGRectGetHeight([headerView frame]);
frame.size.width -= _CGRectGetWidth([self _cornerViewFrame]);
@@ -592,69 +477,33 @@
return frame;
}
- (CGRect)_bottomCornerViewFrame
{
if ([[self horizontalScroller] isHidden] || [[self verticalScroller] isHidden])
return CGRectMakeZero();
var verticalFrame = [[self verticalScroller] frame],
bottomCornerFrame = CGRectMakeZero();
bottomCornerFrame.origin.x = CGRectGetMinX(verticalFrame);
bottomCornerFrame.origin.y = CGRectGetMaxY(verticalFrame);
bottomCornerFrame.size.width = [CPScroller scrollerWidth];
bottomCornerFrame.size.height = [CPScroller scrollerWidth];
return bottomCornerFrame;
}
- (void)setBottomCornerView:(CPView)aBottomCornerView
{
if (_bottomCornerView === aBottomCornerView)
return;
[_bottomCornerView removeFromSuperview];
[aBottomCornerView setFrame:[self _bottomCornerViewFrame]];
[self addSubview:aBottomCornerView];
_bottomCornerView = aBottomCornerView;
[self _updateCornerAndHeaderView];
}
- (CPView)bottomCornerView
{
return _bottomCornerView;
}
/* @ignore */
- (void)_verticalScrollerDidScroll:(CPScroller)aScroller
{
var value = [aScroller floatValue],
documentFrame = [[_contentView documentView] frame],
var value = [aScroller floatValue],
documentFrame = [[_contentView documentView] frame];
contentBounds = [_contentView bounds];
switch ([_verticalScroller hitPart])
{
case CPScrollerDecrementLine: contentBounds.origin.y -= _verticalLineScroll;
break;
case CPScrollerIncrementLine: contentBounds.origin.y += _verticalLineScroll;
break;
case CPScrollerDecrementPage: contentBounds.origin.y -= _CGRectGetHeight(contentBounds) - _verticalPageScroll;
break;
case CPScrollerIncrementPage: contentBounds.origin.y += _CGRectGetHeight(contentBounds) - _verticalPageScroll;
break;
case CPScrollerKnobSlot:
case CPScrollerKnob:
// We want integral bounds!
default: contentBounds.origin.y = ROUND(value * (_CGRectGetHeight(documentFrame) - _CGRectGetHeight(contentBounds)));
}
[_contentView scrollToPoint:contentBounds.origin];
}
@@ -664,21 +513,21 @@
var value = [aScroller floatValue],
documentFrame = [[self documentView] frame],
contentBounds = [_contentView bounds];
switch ([_horizontalScroller hitPart])
{
case CPScrollerDecrementLine: contentBounds.origin.x -= _horizontalLineScroll;
break;
case CPScrollerIncrementLine: contentBounds.origin.x += _horizontalLineScroll;
break;
case CPScrollerDecrementPage: contentBounds.origin.x -= _CGRectGetWidth(contentBounds) - _horizontalPageScroll;
break;
case CPScrollerIncrementPage: contentBounds.origin.x += _CGRectGetWidth(contentBounds) - _horizontalPageScroll;
break;
case CPScrollerKnobSlot:
case CPScrollerKnob:
// We want integral bounds!
@@ -703,7 +552,7 @@
/*
@ignore
*/
- (void)resizeSubviewsWithOldSize:(CGSize)aSize
-(void)resizeSubviewsWithOldSize:(CGSize)aSize
{
[self reflectScrolledClipView:_contentView];
}
@@ -715,7 +564,7 @@
*/
- (void)setLineScroll:(float)aLineScroll
{
[self setHorizontalLineScroll:aLineScroll];
[self setHorizonalLineScroll:aLineScroll];
[self setVerticalLineScroll:aLineScroll];
}
@@ -798,7 +647,7 @@
/*!
Sets the vertical page scroll amount.
@param aPageScroll the new vertical page scroll amount
@param aPageScroll the new vertcal page scroll amount
*/
- (void)setVerticalPageScroll:(float)aPageScroll
{
@@ -813,138 +662,14 @@
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] deltaY:[anEvent deltaY]];
[self _respondToScrollWheelEventWithDeltaX:[anEvent deltaX] * _horizontalLineScroll
deltaY:[anEvent deltaY] * _verticalLineScroll];
}
- (void)_respondToScrollWheelEventWithDeltaX:(float)deltaX deltaY:(float)deltaY
@@ -952,15 +677,17 @@
var documentFrame = [[self documentView] frame],
contentBounds = [_contentView bounds],
contentFrame = [_contentView frame],
enclosingScrollView = [self enclosingScrollView];
enclosingScrollView = [self enclosingScrollView],
extraX = 0,
extraY = 0;
// 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,
extraY = contentBounds.origin.y - constrainedOrigin.y;
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];
[_contentView scrollToPoint:constrainedOrigin];
[_headerClipView scrollToPoint:CGPointMake(constrainedOrigin.x, 0.0)];
@@ -969,34 +696,23 @@
[enclosingScrollView _respondToScrollWheelEventWithDeltaX:extraX deltaY:extraY];
}
- (void)scrollPageUp:(id)sender
- (void)keyDown:(CPEvent)anEvent
{
[self interpretKeyEvents:[anEvent]];
}
- (void)pageUp:(id)sender
{
var contentBounds = [_contentView bounds];
[self moveByOffset:CGSizeMake(0.0, -(_CGRectGetHeight(contentBounds) - _verticalPageScroll))];
}
- (void)scrollPageDown:(id)sender
- (void)pageDown:(id)sender
{
var contentBounds = [_contentView bounds];
[self moveByOffset:CGSizeMake(0.0, _CGRectGetHeight(contentBounds) - _verticalPageScroll)];
}
- (void)scrollToBeginningOfDocument:(id)sender
{
[_contentView scrollToPoint:_CGPointMakeZero()];
[_headerClipView scrollToPoint:_CGPointMakeZero()];
}
- (void)scrollToEndOfDocument:(id)sender
{
var contentBounds = [_contentView bounds],
documentFrame = [[self documentView] frame],
scrollPoint = _CGPointMake(0.0, _CGRectGetHeight(documentFrame) - _CGRectGetHeight(contentBounds));
[_contentView scrollToPoint:scrollPoint];
[_headerClipView scrollToPoint:_CGPointMakeZero()];
}
- (void)moveLeft:(id)sender
{
[self moveByOffset:CGSizeMake(-_horizontalLineScroll, 0.0)];
@@ -1026,25 +742,23 @@
contentBounds.origin.y += aSize.height;
[_contentView scrollToPoint:contentBounds.origin];
[_headerClipView scrollToPoint:CGPointMake(contentBounds.origin.x, 0)];
[_headerClipView scrollToPoint:CGPointMake(contentBounds.origin, 0)];
}
@end
var CPScrollViewContentViewKey = @"CPScrollViewContentView",
CPScrollViewHeaderClipViewKey = @"CPScrollViewHeaderClipViewKey",
CPScrollViewVLineScrollKey = @"CPScrollViewVLineScroll",
CPScrollViewHLineScrollKey = @"CPScrollViewHLineScroll",
CPScrollViewVPageScrollKey = @"CPScrollViewVPageScroll",
CPScrollViewHPageScrollKey = @"CPScrollViewHPageScroll",
CPScrollViewHasVScrollerKey = @"CPScrollViewHasVScroller",
CPScrollViewHasHScrollerKey = @"CPScrollViewHasHScroller",
CPScrollViewVScrollerKey = @"CPScrollViewVScroller",
CPScrollViewHScrollerKey = @"CPScrollViewHScroller",
CPScrollViewAutohidesScrollerKey = @"CPScrollViewAutohidesScroller",
CPScrollViewCornerViewKey = @"CPScrollViewCornerViewKey",
CPScrollViewBottomCornerViewKey = @"CPScrollViewBottomCornerViewKey",
CPScrollViewBorderTypeKey = @"CPScrollViewBorderTypeKey";
var CPScrollViewContentViewKey = "CPScrollViewContentView",
CPScrollViewHeaderClipViewKey = "CPScrollViewHeaderClipViewKey",
CPScrollViewVLineScrollKey = "CPScrollViewVLineScroll",
CPScrollViewHLineScrollKey = "CPScrollViewHLineScroll",
CPScrollViewVPageScrollKey = "CPScrollViewVPageScroll",
CPScrollViewHPageScrollKey = "CPScrollViewHPageScroll",
CPScrollViewHasVScrollerKey = "CPScrollViewHasVScroller",
CPScrollViewHasHScrollerKey = "CPScrollViewHasHScroller",
CPScrollViewVScrollerKey = "CPScrollViewVScroller",
CPScrollViewHScrollerKey = "CPScrollViewHScroller",
CPScrollViewAutohidesScrollerKey = "CPScrollViewAutohidesScroller",
CPScrollViewCornerViewKey = "CPScrollViewCornerViewKey";
@implementation CPScrollView (CPCoding)
@@ -1057,7 +771,7 @@ var CPScrollViewContentViewKey = @"CPScrollViewContentView",
_horizontalLineScroll = [aCoder decodeFloatForKey:CPScrollViewHLineScrollKey];
_horizontalPageScroll = [aCoder decodeFloatForKey:CPScrollViewHPageScrollKey];
_contentView = [aCoder decodeObjectForKey:CPScrollViewContentViewKey];
_headerClipView = [aCoder decodeObjectForKey:CPScrollViewHeaderClipViewKey];
@@ -1074,41 +788,35 @@ var CPScrollViewContentViewKey = @"CPScrollViewContentView",
_hasHorizontalScroller = [aCoder decodeBoolForKey:CPScrollViewHasHScrollerKey];
_autohidesScrollers = [aCoder decodeBoolForKey:CPScrollViewAutohidesScrollerKey];
_borderType = [aCoder decodeIntForKey:CPScrollViewBorderTypeKey];
_cornerView = [aCoder decodeObjectForKey:CPScrollViewCornerViewKey];
_bottomCornerView = [aCoder decodeObjectForKey:CPScrollViewBottomCornerViewKey];
// Due to the anything goes nature of decoding, our subviews may not exist yet, so layout at the end of the run loop when we're sure everything is in a correct state.
[[CPRunLoop currentRunLoop] performSelector:@selector(_updateCornerAndHeaderView) target:self argument:_contentView order:0 modes:[CPDefaultRunLoopMode]];
// Do to the anything goes nature of decoding, our subviews may not exist yet, so layout at the end of the run loop when we're sure everything is in a correct state.
[[CPRunLoop currentRunLoop] performSelector:@selector(reflectScrolledClipView:) target:self argument:_contentView order:0 modes:[CPDefaultRunLoopMode]];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:_contentView forKey:CPScrollViewContentViewKey];
[aCoder encodeObject:_headerClipView forKey:CPScrollViewHeaderClipViewKey];
[aCoder encodeObject:_verticalScroller forKey:CPScrollViewVScrollerKey];
[aCoder encodeObject:_horizontalScroller forKey:CPScrollViewHScrollerKey];
[aCoder encodeFloat:_verticalLineScroll forKey:CPScrollViewVLineScrollKey];
[aCoder encodeFloat:_verticalPageScroll forKey:CPScrollViewVPageScrollKey];
[aCoder encodeFloat:_horizontalLineScroll forKey:CPScrollViewHLineScrollKey];
[aCoder encodeFloat:_horizontalPageScroll forKey:CPScrollViewHPageScrollKey];
[aCoder encodeBool:_hasVerticalScroller forKey:CPScrollViewHasVScrollerKey];
[aCoder encodeBool:_hasHorizontalScroller forKey:CPScrollViewHasHScrollerKey];
[aCoder encodeBool:_autohidesScrollers forKey:CPScrollViewAutohidesScrollerKey];
[aCoder encodeObject:_cornerView forKey:CPScrollViewCornerViewKey];
[aCoder encodeObject:_bottomCornerView forKey:CPScrollViewBottomCornerViewKey];
[aCoder encodeInt:_borderType forKey:CPScrollViewBorderTypeKey];
}
@end
+90 -102
View File
@@ -22,6 +22,8 @@
@import "CPControl.j"
#include "CoreGraphics/CGGeometry.h"
// CPScroller Constants
CPScrollerNoPart = 0;
@@ -39,9 +41,9 @@ CPNoScrollerParts = 0;
CPOnlyScrollerArrows = 1;
CPAllScrollerParts = 2;
/*!
/*!
@ingroup appkit
@class CPScroller
@class CPScroller
*/
var PARTS_ARRANGEMENT = [CPScrollerKnobSlot, CPScrollerDecrementLine, CPScrollerIncrementLine, CPScrollerKnob],
@@ -70,25 +72,24 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
CGPoint _trackingStartPoint;
}
+ (CPString)defaultThemeClass
+ (CPString)themeClass
{
return "scroller";
}
+ (id)themeAttributes
{
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
}]
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"]];
}
@@ -97,7 +98,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
_controlSize = CPRegularControlSize;
@@ -105,7 +106,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
[self setFloatValue:0.0];
[self setKnobProportion:1.0];
_hitPart = CPScrollerNoPart;
[self _calculateIsVertical];
@@ -120,7 +121,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
*/
+ (float)scrollerWidth
{
return [[[CPScroller alloc] init] currentValueForThemeAttribute:@"scroller-width"];
return 15.0;//[self scrollerWidthForControlSize:CPRegularControlSize];
}
/*!
@@ -129,7 +130,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
*/
+ (float)scrollerWidthForControlSize:(CPControlSize)aControlSize
{
return [self scrollerWidth];
return 15.0;//_CPScrollerWidths[aControlSize];
}
/*!
@@ -179,10 +180,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];
}
@@ -204,25 +205,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;
@@ -240,7 +241,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
if (_knobProportion === 1.0)
{
_usableParts = CPNoScrollerParts;
_partRects[CPScrollerDecrementPage] = CGRectMakeZero();
_partRects[CPScrollerKnob] = CGRectMakeZero();
_partRects[CPScrollerIncrementPage] = CGRectMakeZero();
@@ -249,7 +250,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
// In this case, the slot is the entirety of the scroller.
_partRects[CPScrollerKnobSlot] = CGRectMakeCopy(bounds);
return;
}
@@ -259,31 +260,31 @@ 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"],
incrementLineSize = [self currentValueForThemeAttribute:"increment-line-size"],
effectiveDecrementLineHeight = decrementLineSize.height + trackInset.top,
effectiveIncrementLineHeight = incrementLineSize.height + trackInset.bottom,
slotSize = height - effectiveDecrementLineHeight - effectiveIncrementLineHeight,
slotHeight = height - effectiveDecrementLineHeight - effectiveIncrementLineHeight,
minimumKnobLength = [self currentValueForThemeAttribute:"minimum-knob-length"],
knobWidth = width - knobInset.left - knobInset.right,
knobHeight = MAX(minimumKnobLength, (slotSize * _knobProportion)),
knobLocation = effectiveDecrementLineHeight + (slotSize - knobHeight) * [self floatValue];
knobHeight = MAX(minimumKnobLength, (slotHeight * _knobProportion)),
knobLocation = effectiveDecrementLineHeight + (slotHeight - knobHeight) * [self floatValue];
_partRects[CPScrollerDecrementPage] = _CGRectMake(0.0, effectiveDecrementLineHeight, width, knobLocation - effectiveDecrementLineHeight);
_partRects[CPScrollerKnob] = _CGRectMake(knobInset.left, knobLocation, knobWidth, knobHeight);
_partRects[CPScrollerIncrementPage] = _CGRectMake(0.0, knobLocation + knobHeight, width, height - (knobLocation + knobHeight) - effectiveIncrementLineHeight);
_partRects[CPScrollerKnobSlot] = _CGRectMake(trackInset.left, effectiveDecrementLineHeight, width - trackInset.left - trackInset.right, slotSize);
_partRects[CPScrollerKnobSlot] = _CGRectMake(trackInset.left, effectiveDecrementLineHeight, width - trackInset.left - trackInset.right, slotHeight);
_partRects[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
_partRects[CPScrollerIncrementLine] = _CGRectMake(0.0, height - incrementLineSize.height, incrementLineSize.width, incrementLineSize.height);
if (height < knobHeight + decrementLineSize.height + incrementLineSize.height + trackInset.top + trackInset.bottom)
if(height < knobHeight + decrementLineSize.height + incrementLineSize.height + trackInset.top + trackInset.bottom)
_partRects[CPScrollerKnob] = _CGRectMakeZero();
if (height < decrementLineSize.height + incrementLineSize.height - 2)
if(height < decrementLineSize.height + incrementLineSize.height - 2)
{
_partRects[CPScrollerIncrementLine] = _CGRectMakeZero();
_partRects[CPScrollerDecrementLine] = _CGRectMakeZero();
@@ -295,28 +296,28 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
var decrementLineSize = [self currentValueForThemeAttribute:"decrement-line-size"],
incrementLineSize = [self currentValueForThemeAttribute:"increment-line-size"],
effectiveDecrementLineWidth = decrementLineSize.width + trackInset.left,
effectiveIncrementLineWidth = incrementLineSize.width + trackInset.right,
slotSize = width - effectiveDecrementLineWidth - effectiveIncrementLineWidth,
effectiveIncrementLineWidth = incrementLineSize.width + trackInset.right;
slotWidth = width - effectiveDecrementLineWidth - effectiveIncrementLineWidth,
minimumKnobLength = [self currentValueForThemeAttribute:"minimum-knob-length"],
knobWidth = MAX(minimumKnobLength, (slotSize * _knobProportion)),
knobWidth = MAX(minimumKnobLength, (slotWidth * _knobProportion)),
knobHeight = height - knobInset.top - knobInset.bottom,
knobLocation = effectiveDecrementLineWidth + (slotSize - knobWidth) * [self floatValue];
knobLocation = effectiveDecrementLineWidth + (slotWidth - knobWidth) * [self floatValue];
_partRects[CPScrollerDecrementPage] = _CGRectMake(effectiveDecrementLineWidth, 0.0, knobLocation - effectiveDecrementLineWidth, height);
_partRects[CPScrollerKnob] = _CGRectMake(knobLocation, knobInset.top, knobWidth, knobHeight);
_partRects[CPScrollerIncrementPage] = _CGRectMake(knobLocation + knobWidth, 0.0, width - (knobLocation + knobWidth) - effectiveIncrementLineWidth, height);
_partRects[CPScrollerKnobSlot] = _CGRectMake(effectiveDecrementLineWidth, trackInset.top, slotSize, height - trackInset.top - trackInset.bottom);
_partRects[CPScrollerKnobSlot] = _CGRectMake(effectiveDecrementLineWidth, trackInset.top, slotWidth, height - trackInset.top - trackInset.bottom);
_partRects[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
_partRects[CPScrollerIncrementLine] = _CGRectMake(width - incrementLineSize.width, 0.0, incrementLineSize.width, incrementLineSize.height);
if (width < knobWidth + decrementLineSize.width + incrementLineSize.width + trackInset.left + trackInset.right)
if(width < knobWidth + decrementLineSize.width + incrementLineSize.width + trackInset.left + trackInset.right)
_partRects[CPScrollerKnob] = _CGRectMakeZero();
if (width < decrementLineSize.width + incrementLineSize.width - 2)
if(width < decrementLineSize.width + incrementLineSize.width - 2)
{
_partRects[CPScrollerIncrementLine] = _CGRectMakeZero();
_partRects[CPScrollerDecrementLine] = _CGRectMakeZero();
_partRects[CPScrollerKnobSlot] = _CGRectMake(0.0, 0.0, width, slotSize);
_partRects[CPScrollerKnobSlot] = _CGRectMake(0.0, 0.0, width, slotHeight);
}
}
}
@@ -357,9 +358,9 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
- (CPView)createViewForPart:(CPScrollerPart)aPart
{
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
[view setHitTests:NO];
return view;
}
@@ -373,7 +374,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
var view = [[CPView alloc] initWithFrame:_CGRectMakeZero()];
[view setHitTests:NO];
return view;
}
@@ -387,12 +388,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"]];
}
@@ -402,7 +403,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];
@@ -425,37 +426,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]];
@@ -473,26 +474,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],
@@ -501,42 +502,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];
}
@@ -568,15 +569,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];
}
@@ -602,32 +603,19 @@ 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];
}
+216 -306
View File
@@ -20,9 +20,10 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPButton.j"
@import "CPTextField.j"
#include "Platform/Platform.h"
CPSearchFieldRecentsTitleMenuItemTag = 1000;
CPSearchFieldRecentsMenuItemTag = 1001;
CPSearchFieldClearRecentsMenuItemTag = 1002;
@@ -33,20 +34,12 @@ var CPSearchFieldSearchImage = nil,
CPSearchFieldCancelImage = nil,
CPSearchFieldCancelPressedImage = nil;
var SEARCH_BUTTON_DEFAULT_WIDTH = 25.0,
CANCEL_BUTTON_DEFAULT_WIDTH = 22.0,
BUTTON_DEFAULT_HEIGHT = 22.0;
var CPAutosavedRecentsChangedNotification = @"CPAutosavedRecentsChangedNotification";
var RECENT_SEARCH_PREFIX = @" ";
/*!
/*!
@ingroup appkit
@class CPSearchField
The CPSearchField class defines the programmatic interface for text fields that are optimized for text-based searches. A CPSearchField object directly inherits from the CPTextField class. The search field implemented by these classes presents a standard user interface for searches, including a search button, a cancel button, and a pop-up icon menu for listing recent search strings and custom search categories.
When the user types and then pauses, the text field's action message is sent to its target. You can query the text field's string value for the current text to search for. Do not rely on the sender of the action to be an CPMenu object because the menu may change. If you need to change the menu, modify the search menu template and call the setSearchMenuTemplate: method to update.
When the user types and then pauses, the text field's action message is sent to its target. You can query the text field's string value for the current text to search for. Do not rely on the sender of the action to be an CPMenu object because the menu may change. If you need to change the menu, modify the search menu template and call the setSearchMenuTemplate: method to update.
*/
@implementation CPSearchField : CPTextField
{
@@ -57,83 +50,62 @@ var RECENT_SEARCH_PREFIX = @" ";
CPString _recentsAutosaveName;
CPArray _recentSearches;
int _maximumRecents;
BOOL _sendsWholeSearchString;
BOOL _sendsSearchStringImmediately;
BOOL _canResignFirstResponder;
CPTimer _partialStringTimer;
}
+ (CPString)defaultThemeClass
{
return @"searchfield"
}
+ (void)initialize
{
if (self != [CPSearchField class])
return;
var bundle = [CPBundle bundleForClass:self];
CPSearchFieldSearchImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPSearchField/CPSearchFieldSearch.png"] size:_CGSizeMake(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)];
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)];
}
- (id)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame])
{
_recentSearches = [CPArray array];
_maximumRecents = 10;
_sendsWholeSearchString = NO;
_sendsSearchStringImmediately = NO;
_recentsAutosaveName = nil;
[self _init];
[self _initWithFrame:frame];
#if PLATFORM(DOM)
_cancelButton._DOMElement.style.cursor = "default";
_searchButton._DOMElement.style.cursor = "default";
#endif
#endif
}
return self;
}
- (void)_init
- (void)_initWithFrame:(CGRect)frame
{
_recentSearches = [CPArray array];
[self setBezeled:YES];
[self setBezelStyle:CPTextFieldRoundedBezel];
[self setBordered:YES];
[self setEditable:YES];
[self setContinuous:YES];
var bounds = [self bounds],
cancelButton = [[CPButton alloc] initWithFrame:[self cancelButtonRectForBounds:bounds]],
searchButton = [[CPButton alloc] initWithFrame:[self searchButtonRectForBounds:bounds]];
[self setCancelButton:cancelButton];
[self setDelegate:self];
_cancelButton = [[CPButton alloc] initWithFrame:CGRectMake(frame.size.width - 27,(frame.size.height-22)/2,22,22)];
[self resetCancelButton];
[self setSearchButton:searchButton];
[_cancelButton setHidden:YES];
[_cancelButton setAutoresizingMask:CPViewMinXMargin];
[self addSubview:_cancelButton];
_searchButton = [[CPButton alloc] initWithFrame:CGRectMake(5,(frame.size.height-25)/2,25,25)];
[self resetSearchButton];
_canResignFirstResponder = YES;
}
- (void)viewWillMoveToSuperview:(CPView)aView
{
[super viewWillMoveToSuperview:aView];
// First we remove any observer that may have been in place to avoid memory leakage.
[[CPNotificationCenter defaultCenter] removeObserver:self name:CPControlTextDidChangeNotification object:self];
// Register the observe here if we need to.
if (aView)
[[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(_searchFieldTextDidChange:) name:CPControlTextDidChangeNotification object:self];
[self addSubview:_searchButton];
}
// Managing Buttons
@@ -142,16 +114,8 @@ var RECENT_SEARCH_PREFIX = @" ";
@param button The search button.
*/
- (void)setSearchButton:(CPButton)button
{
if (button != _searchButton)
{
[_searchButton removeFromSuperview];
_searchButton = button;
[_searchButton setFrame:[self searchButtonRectForBounds:[self bounds]]];
[_searchButton setAutoresizingMask:CPViewMaxXMargin];
[self addSubview:_searchButton];
}
{
_searchButton = button;
}
/*!
@@ -169,13 +133,30 @@ var RECENT_SEARCH_PREFIX = @" ";
*/
- (void)resetSearchButton
{
var button = [self searchButton],
searchButtonImage = (_searchMenuTemplate === nil) ? CPSearchFieldSearchImage : CPSearchFieldFindImage;
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;
}
[button setBordered:NO];
[button setImageScaling:CPScaleToFit];
[button setImage:searchButtonImage];
[button setAutoresizingMask:CPViewMaxXMargin];
[button setTarget:target];
[button setAction:action];
}
/*!
@@ -184,18 +165,7 @@ var RECENT_SEARCH_PREFIX = @" ";
*/
- (void)setCancelButton:(CPButton)button
{
if (button != _cancelButton)
{
[_cancelButton removeFromSuperview];
_cancelButton = button;
[_cancelButton setFrame:[self cancelButtonRectForBounds:[self bounds]]];
[_cancelButton setAutoresizingMask:CPViewMinXMargin];
[_cancelButton setTarget:self];
[_cancelButton setAction:@selector(cancelOperation:)];
[self _updateCancelButtonVisibility];
[self addSubview:_cancelButton];
}
_cancelButton = button;
}
/*!
@@ -209,7 +179,7 @@ var RECENT_SEARCH_PREFIX = @" ";
/*!
Resets the cancel button to its default attributes.
This method resets the target, action, regular image, and pressed image. This method gives you a way to customize the cancel button for specific situations and then reset the button defaults without having to undo changes individually.
This method resets the target, action, regular image, and pressed image. By default, when users click the cancel button, the delete: action message is sent up the responder chain. This method gives you a way to customize the cancel button for specific situations and then reset the button defaults without having to undo changes individually.
*/
- (void)resetCancelButton
{
@@ -220,7 +190,7 @@ var RECENT_SEARCH_PREFIX = @" ";
[button setAlternateImage:CPSearchFieldCancelPressedImage];
[button setAutoresizingMask:CPViewMinXMargin];
[button setTarget:self];
[button setAction:@selector(cancelOperation:)];
[button setAction:@selector(_searchFieldCancel:)];
}
// Custom Layout
@@ -230,25 +200,23 @@ var RECENT_SEARCH_PREFIX = @" ";
@return The updated bounding rectangle to use for the search text field. The default value is the value passed into the rect parameter.
Subclasses can override this method to return a new bounding rectangle for the text-field object. You might use this method to provide a custom layout for the search field control.
*/
- (CGRect)searchTextRectForBounds:(CGRect)rect
- (CPRect)searchTextRectForBounds:(CPRect)rect
{
var leftOffset = 0,
width = _CGRectGetWidth(rect),
bounds = [self bounds];
var leftOffset = 0, width = rect.size.width;
if (_searchButton)
{
var searchBounds = [self searchButtonRectForBounds:bounds];
leftOffset = _CGRectGetMaxX(searchBounds) + 2;
var searchRect = [_searchButton frame];
leftOffset = searchRect.origin.x + searchRect.size.width;
}
if (_cancelButton)
{
var cancelRect = [self cancelButtonRectForBounds:bounds];
width = _CGRectGetMinX(cancelRect) - leftOffset;
var cancelRect = [_cancelButton frame];
width = cancelRect.origin.x - leftOffset;
}
return _CGRectMake(leftOffset, _CGRectGetMinY(rect), width, _CGRectGetHeight(rect));
return CPMakeRect(leftOffset,rect.origin.y,width,rect.size.height);
}
/*!
@@ -256,9 +224,9 @@ var RECENT_SEARCH_PREFIX = @" ";
@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.
*/
- (CGRect)searchButtonRectForBounds:(CGRect)rect
- (CPRect)searchButtonRectForBounds:(CPRect)rect
{
return _CGRectMake(5, (_CGRectGetHeight(rect) - BUTTON_DEFAULT_HEIGHT) / 2, SEARCH_BUTTON_DEFAULT_WIDTH, BUTTON_DEFAULT_HEIGHT);
return [_searchButton frame];
}
/*!
@@ -266,9 +234,9 @@ var RECENT_SEARCH_PREFIX = @" ";
@param rect The updated bounding rectangle to use for the cancel button. The default value is the value passed into the rect parameter.
Subclasses can override this method to return a new bounding rectangle for the cancel button. You might use this method to provide a custom layout for the search field control.
*/
- (CGRect)cancelButtonRectForBounds:(CGRect)rect
- (CPRect)cancelButtonRectForBounds:(CPRect)rect
{
return _CGRectMake(_CGRectGetWidth(rect) - CANCEL_BUTTON_DEFAULT_WIDTH - 5, (_CGRectGetHeight(rect) - CANCEL_BUTTON_DEFAULT_WIDTH) / 2, BUTTON_DEFAULT_HEIGHT, BUTTON_DEFAULT_HEIGHT);
return [_cancelButton frame];
}
// Managing Menu Templates
@@ -286,10 +254,10 @@ var RECENT_SEARCH_PREFIX = @" ";
@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)aMenu
- (void)setSearchMenuTemplate:(CPMenu)menu
{
_searchMenuTemplate = aMenu;
_searchMenuTemplate = menu;
[self resetSearchButton];
[self _loadRecentSearchList];
[self _updateSearchMenu];
@@ -301,8 +269,8 @@ var RECENT_SEARCH_PREFIX = @" ";
@return \c YES if the action message is sent all at once when the user clicks the search button or presses return; otherwise, NO if the search string is sent after each keystroke. The default value is NO.
*/
- (BOOL)sendsWholeSearchString
{
return _sendsWholeSearchString;
{
return _sendsWholeSearchString;
}
/*!
@@ -319,8 +287,8 @@ var RECENT_SEARCH_PREFIX = @" ";
@return \c YES if the text field sends its action immediately upon notification of any changes to the search field; otherwise, NO.
*/
- (BOOL)sendsSearchStringImmediately
{
return _sendsSearchStringImmediately;
{
return _sendsSearchStringImmediately;
}
/*!
@@ -338,7 +306,7 @@ var RECENT_SEARCH_PREFIX = @" ";
@return The maximum number of search strings that can appear in the menu. This value is between 0 and 254.
*/
- (int)maximumRecents
{
{
return _maximumRecents;
}
@@ -352,13 +320,13 @@ var RECENT_SEARCH_PREFIX = @" ";
max = 254;
else if (max < 0)
max = 10;
_maximumRecents = max;
}
/*!
Returns the list of recent search strings for the control.
@return An array of \c CPString objects, each of which contains a search string either displayed in the search menu or from a recent autosave archive. If there have been no recent searches and no prior searches saved under an autosave name, this array may be empty.
@return An array of \c CPString objects, each of which contains a search string either displayed in the search menu or from a recent autosave archive. If there have been no recent searches and no prior searches saved under an autosave name, this array may be empty.
*/
- (CPArray)recentSearches
{
@@ -374,8 +342,8 @@ var RECENT_SEARCH_PREFIX = @" ";
{
var max = MIN([self maximumRecents], [searches count]),
searches = [searches subarrayWithRange:CPMakeRange(0, max)];
_recentSearches = searches;
_recentSearches = searches;
[self _autosaveRecentSearchList];
}
@@ -385,7 +353,7 @@ var RECENT_SEARCH_PREFIX = @" ";
*/
- (CPString)recentsAutosaveName
{
return _recentsAutosaveName;
return _recentsAutosaveName;
}
/*!
@@ -396,24 +364,24 @@ var RECENT_SEARCH_PREFIX = @" ";
{
if (_recentsAutosaveName != nil)
[self _deregisterForAutosaveNotification];
_recentsAutosaveName = name;
if (_recentsAutosaveName != nil)
[self _registerForAutosaveNotification];
}
// Private methods and subclassing
- (CGRect)contentRectForBounds:(CGRect)bounds
- (CPRect)contentRectForBounds:(CPRect)bounds
{
var superbounds = [super contentRectForBounds:bounds];
var superbounds = [super contentRectForBounds:bounds];
return [self searchTextRectForBounds:superbounds];
}
+ (double)_keyboardDelayForPartialSearchString:(CPString)string
{
return (6 - MIN([string length], 4)) / 10;
return (6 - MIN([string length],4))/10;
}
- (CPMenu)menu
@@ -431,7 +399,7 @@ var RECENT_SEARCH_PREFIX = @" ";
[_cancelButton setHidden:([[self stringValue] length] === 0)];
}
- (void)_searchFieldTextDidChange:(CPNotification)aNotification
- (void)controlTextDidChange:(CPNotification)aNotification
{
if (![self sendsWholeSearchString])
{
@@ -441,15 +409,15 @@ var RECENT_SEARCH_PREFIX = @" ";
{
[_partialStringTimer invalidate];
var timeInterval = [CPSearchField _keyboardDelayForPartialSearchString:[self stringValue]];
_partialStringTimer = [CPTimer scheduledTimerWithTimeInterval:timeInterval
target:self
selector:@selector(_sendPartialString)
userInfo:nil
repeats:NO];
_partialStringTimer = [CPTimer scheduledTimerWithTimeInterval:timeInterval
target:self
selector:@selector(_sendPartialString)
userInfo:nil
repeats:NO];
}
}
[self _updateCancelButtonVisibility];
}
@@ -472,111 +440,70 @@ var RECENT_SEARCH_PREFIX = @" ";
{
if (string === nil || string === @"" || [_recentSearches containsObject:string])
return;
var searches = [CPMutableArray arrayWithArray:_recentSearches];
[searches addObject:string];
[self setRecentSearches:searches];
[self _updateSearchMenu];
}
- (CPView)hitTest:(CGPoint)aPoint
- (BOOL)trackMouse:(CPEvent)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;
}
- (BOOL)resignFirstResponder
{
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))
var rect,
point,
location = [event locationInWindow];
point = [self convertPoint:location fromView:nil];
rect = [self searchButtonRectForBounds:[self frame]];
if (CPRectContainsPoint(rect,point))
{
if (_searchMenuTemplate == nil)
[self _sendAction:self];
else
[self _showMenu];
return [[self searchButton] trackMouse:event];
}
else if (_CGRectContainsPoint([self cancelButtonRectForBounds:[self bounds]], point))
[_cancelButton mouseDown:anEvent];
else
[super mouseDown:anEvent];
rect = [self cancelButtonRectForBounds:[self frame]];
if (CPRectContainsPoint(rect,point))
{
return [[self cancelButton] trackMouse:event];
}
return [super trackMouse:event];
}
/*!
Provides the common case items for a recent searches menu. If there are not recent searches,
displays a single disabled item:
No Recent Searches
If there are 1 more recent searches, it displays:
Recent Searches
recent search 1
recent search 2
etc.
---------------------
Clear Recent Searches
If you wish to add items before or after the template, you can. If you put items
before, a separator will automatically be placed before the default template item.
If you add items after the default template, it is your responsibility to add a separator.
To add a custom item:
item = [[CPMenuItem alloc] initWithTitle:@"google"
action:@selector(google:)
keyEquivalent:@""];
[item setTag:700];
[item setTarget:self];
[template addItem:item];
Be sure that your custom items do not use tags in the range 1000-1003 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
- (CPMenu)_defaultSearchMenuTemplate
{
var template = [[CPMenu alloc] init],
item;
item = [[CPMenuItem alloc] initWithTitle:@"Recent Searches"
action:nil
var template, item;
template = [[CPMenu alloc] init];
item = [[CPMenuItem alloc] initWithTitle:@"Recent searches"
action:NULL
keyEquivalent:@""];
[item setTag:CPSearchFieldRecentsTitleMenuItemTag];
[item setEnabled:NO];
[template addItem:item];
item = [[CPMenuItem alloc] initWithTitle:@"Recent search item"
action:@selector(_searchFieldSearch:)
item = [[CPMenuItem alloc] initWithTitle:@"Recent search item"
action:@selector(_searchFieldSearch:)
keyEquivalent:@""];
[item setTag:CPSearchFieldRecentsMenuItemTag];
[item setTarget:self];
[template addItem:item];
item = [[CPMenuItem alloc] initWithTitle:@"Clear Recent Searches"
action:@selector(_searchFieldClearRecents:)
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:nil
item = [[CPMenuItem alloc] initWithTitle:@"No recent searches"
action:NULL
keyEquivalent:@""];
[item setTag:CPSearchFieldNoRecentsMenuItemTag];
[item setEnabled:NO];
[template addItem:item];
return template;
}
@@ -584,128 +511,95 @@ var RECENT_SEARCH_PREFIX = @" ";
{
if (_searchMenuTemplate === nil)
return;
var menu = [[CPMenu alloc] init],
var i, menu = [[CPMenu alloc] init],
countOfRecents = [_recentSearches count],
numberOfItems = [_searchMenuTemplate numberOfItems];
for (var i = 0; i < numberOfItems; i++)
for (i = 0; i < numberOfItems; i++)
{
var item = [[_searchMenuTemplate itemAtIndex:i] copy];
switch ([item tag])
var item = [_searchMenuTemplate itemAtIndex:i],
tag = [item tag];
if (!(tag === CPSearchFieldRecentsTitleMenuItemTag && countOfRecents === 0) &&
!(tag === CPSearchFieldClearRecentsMenuItemTag && countOfRecents === 0) &&
!(tag === CPSearchFieldNoRecentsMenuItemTag && countOfRecents != 0) &&
!(tag === CPSearchFieldRecentsMenuItemTag))
{
case CPSearchFieldRecentsTitleMenuItemTag:
if (countOfRecents === 0)
continue;
if ([menu numberOfItems] > 0)
[self _addSeparatorToMenu:menu];
break;
case CPSearchFieldRecentsMenuItemTag:
var itemAction, itemTarget;
switch (tag)
{
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 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;
}
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;
if (tag === CPSearchFieldClearRecentsMenuItemTag || tag === CPSearchFieldRecentsTitleMenuItemTag)
{
var separator = [CPMenuItem separatorItem];
[separator setEnabled:NO];
[menu addItem:separator];
}
[item setEnabled:([item isEnabled] && [item action] != nil && [item target] != nil)];
[menu addItem:item];
}
[menu setDelegate:self];
var templateItem = [[CPMenuItem alloc] initWithTitle:[item title]
action:itemAction
keyEquivalent:[item keyEquivalent]];
[templateItem setTarget:itemTarget];
[templateItem setEnabled:([item isEnabled] && itemAction != NULL)];
[templateItem setTag:tag];
[menu addItem:templateItem];
}
else if (tag === CPSearchFieldRecentsMenuItemTag)
{
var j;
for (j = 0; j < countOfRecents; j++)
{
var rencentItem = [[CPMenuItem alloc] initWithTitle:[_recentSearches objectAtIndex:j]
action:@selector(_searchFieldSearch:)
keyEquivalent:[item keyEquivalent]];
[rencentItem setTarget:self];
[menu addItem:rencentItem];
}
}
}
_searchMenu = menu;
}
- (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
- (void)_showMenu:(id)sender
{
if (_searchMenu === nil || [_searchMenu numberOfItems] === 0 || ![self isEnabled])
return;
var aFrame = [[self superview] convertRect:[self frame] toView:nil],
location = CPMakePoint(aFrame.origin.x + 10, aFrame.origin.y + aFrame.size.height - 4);
var anEvent = [CPEvent mouseEventWithType:CPRightMouseDown location:location modifierFlags:0 timestamp:[[CPApp currentEvent] timestamp] windowNumber:[[self window] windowNumber] context:nil eventNumber:1 clickCount:1 pressure:0];
[self selectAll:nil];
[CPMenu popUpContextMenu:_searchMenu withEvent:anEvent forView:self];
[CPMenu popUpContextMenu:_searchMenu withEvent:anEvent forView:sender];
}
- (void)_sendPartialString
{
[super sendAction:[self action] to:[self target]];
[_partialStringTimer invalidate];
[[self target] performSelector:[self action] withObject:self];
}
- (void)cancelOperation:(id)sender
{
- (void)_searchFieldCancel:(id)sender
{
[self setObjectValue:@""];
[self textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:self userInfo:nil]];
[self _sendPartialString];
[self _updateCancelButtonVisibility];
}
- (void)_searchFieldSearch:(id)sender
{
var searchString = [[sender title] substringFromIndex:[RECENT_SEARCH_PREFIX length]];
var searchString = [sender title];
if ([sender tag] != CPSearchFieldRecentsMenuItemTag)
[self _addStringToRecentSearches:searchString];
[self setObjectValue:searchString];
[self _sendPartialString];
[self selectAll:nil];
[self _updateCancelButtonVisibility];
}
@@ -714,42 +608,58 @@ var RECENT_SEARCH_PREFIX = @" ";
{
[self setRecentSearches:[CPArray array]];
[self _updateSearchMenu];
[self setStringValue:@""];
[self _updateCancelButtonVisibility];
}
- (void)_registerForAutosaveNotification
{
[[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(_updateAutosavedRecents:) name:CPAutosavedRecentsChangedNotification object:_recentsAutosaveName];
[[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(_updateAutosavedRecents:) name:@"CPAutosavedRecentsChangedNotification" object:nil];
}
- (void)_deregisterForAutosaveNotification
{
[[CPNotificationCenter defaultCenter] removeObserver:self name:CPAutosavedRecentsChangedNotification object:_recentsAutosaveName];
[[CPNotificationCenter defaultCenter] removeObserver:self name:@"CPAutosavedRecentsChangedNotification" object:nil];
}
- (void)_autosaveRecentSearchList
{
if (_recentsAutosaveName != nil)
[[CPNotificationCenter defaultCenter] postNotificationName:CPAutosavedRecentsChangedNotification object:_recentsAutosaveName];
{
if (_recentsAutosaveName != nil)
[[CPNotificationCenter defaultCenter] postNotificationName:@"CPAutosavedRecentsChangedNotification" object:_recentsAutosaveName];
}
- (void)_updateAutosavedRecents:(id)notification
{
var name = [notification object];
[[CPUserDefaults standardUserDefaults] setObject:_recentSearches forKey:name];
var list = [self recentSearches],
name = [notification object],
bundle_name = [[[CPBundle mainBundle] infoDictionary] objectForKey:"CPBundleName"],
cookie_name = [bundle_name lowercaseString] + "." + [notification object],
cookie = [[CPCookie alloc] initWithName:cookie_name],
cookie_value = [list componentsJoinedByString:@","];
[cookie setValue:cookie_value
expires:[[CPDate alloc] initWithTimeIntervalSinceNow:3600*24*365]
domain:(window.location.href.hostname)];
}
- (void)_loadRecentSearchList
{
var name = [self recentsAutosaveName];
var list,
name = [self recentsAutosaveName];
if (name === nil)
return;
var list = [[CPUserDefaults standardUserDefaults] objectForKey:name];
var bundle_name = [[[CPBundle mainBundle] infoDictionary] objectForKey:"CPBundleName"],
cookie_name = [bundle_name lowercaseString] + "." + name,
if (list !== nil)
cookie = [[CPCookie alloc] initWithName:cookie_name];
if (cookie != nil)
{
var cookie_value = [cookie value];
list = (cookie_value != @"") ? [cookie_value componentsSeparatedByString:@","] : [CPArray array];
_recentSearches = list;
}
}
@end
@@ -758,7 +668,7 @@ var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
CPSendsWholeSearchStringKey = @"CPSendsWholeSearchStringKey",
CPSendsSearchStringImmediatelyKey = @"CPSendsSearchStringImmediatelyKey",
CPMaximumRecentsKey = @"CPMaximumRecentsKey",
CPSearchMenuTemplateKey = @"CPSearchMenuTemplateKey";
CPSearchMenuTemplateKey = @"CPSearchMenuTemplateKey";
@implementation CPSearchField (CPCoding)
@@ -767,7 +677,7 @@ var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
[_searchButton removeFromSuperview];
[_cancelButton removeFromSuperview];
[super encodeWithCoder:coder];
[super encodeWithCoder:coder];
if (_searchButton)
[self addSubview:_searchButton];
@@ -780,7 +690,6 @@ var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
if (_recentsAutosaveName)
[coder encodeObject:_recentsAutosaveName forKey:CPRecentsAutosaveNameKey];
if (_searchMenuTemplate)
[coder encodeObject:_searchMenuTemplate forKey:CPSearchMenuTemplateKey];
}
@@ -789,17 +698,18 @@ var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
{
if (self = [super initWithCoder:coder])
{
[self setRecentsAutosaveName:[coder decodeObjectForKey:CPRecentsAutosaveNameKey]];
[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 _init];
[self setDelegate:self];
}
return self;
-22
View File
@@ -1,28 +1,6 @@
/*
* CPSecureTextField.j
* AppKit
*
* Created by Francisco Tolmasky.
* Copyright 2008, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPTextField.j"
/*!
@ingroup appkit
*/
+137 -146
View File
@@ -24,12 +24,13 @@
@import "CPControl.j"
#include "CoreGraphics/CGGeometry.h"
CPSegmentSwitchTrackingSelectOne = 0;
CPSegmentSwitchTrackingSelectAny = 1;
CPSegmentSwitchTrackingMomentary = 2;
/*!
/*!
@ingroup appkit
@class CPSegmentedControl
@@ -48,7 +49,7 @@ CPSegmentSwitchTrackingMomentary = 2;
BOOL _trackingHighlighted;
}
+ (CPString)defaultThemeClass
+ (CPString)themeClass
{
return "segmented-control";
}
@@ -63,16 +64,16 @@ CPSegmentSwitchTrackingMomentary = 2;
{
_segments = [];
_themeStates = [];
self = [super initWithFrame:aRect];
if (self)
{
_selectedSegment = -1;
_trackingMode = CPSegmentSwitchTrackingSelectOne;
}
return self;
}
@@ -81,7 +82,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (int)selectedTag
{
return [_segments[_selectedSegment] tag];
return _segments[_selectedSegment].tag;
}
// Specifying the number of segments
@@ -93,13 +94,11 @@ CPSegmentSwitchTrackingMomentary = 2;
{
if (_segments.length == aCount)
return;
var height = CGRectGetHeight([self bounds]),
dividersBefore = MAX(0, _segments.length - 1),
dividersAfter = MAX(0, aCount - 1);
var height = CGRectGetHeight([self bounds]);
if (_segments.length < aCount)
{
{
for (var index = _segments.length; index < aCount; ++index)
{
_segments[index] = [[_CPSegmentItem alloc] init];
@@ -115,14 +114,6 @@ CPSegmentSwitchTrackingMomentary = 2;
if (_selectedSegment >= _segments.length)
_selectedSegment = -1;
// Make space for/remove space used by dividers.
var thickness = [self currentValueForThemeAttribute:@"divider-thickness"],
delta = thickness * (dividersAfter - dividersBefore),
frame = [self frame];
if (delta)
[self setFrameSize:CGSizeMake(frame.size.width + delta, frame.size.height)];
[self tileWithChangedSegment:0];
}
@@ -160,15 +151,15 @@ CPSegmentSwitchTrackingMomentary = 2;
- (BOOL)selectSegmentWithTag:(int)aTag
{
var index = 0;
for (; index < _segments.length; ++index)
if (_segments[index].tag == aTag)
{
[self setSelectedSegment:index];
return YES;
}
return NO;
}
@@ -183,28 +174,28 @@ CPSegmentSwitchTrackingMomentary = 2;
{
if (_trackingMode == aTrackingMode)
return;
_trackingMode = aTrackingMode;
if (_trackingMode == CPSegmentSwitchTrackingSelectOne)
{
var index = 0,
selected = NO;
for (; index < _segments.length; ++index)
if ([_segments[index] selected])
if (_segments[index].selected)
if (selected)
[self setSelected:NO forSegment:index];
else
selected = YES;
}
else if (_trackingMode == CPSegmentSwitchTrackingMomentary)
{
var index = 0;
for (; index < _segments.length; ++index)
if ([_segments[index] selected])
if (_segments[index].selected)
[self setSelected:NO forSegment:index];
}
}
@@ -226,8 +217,8 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (void)setWidth:(float)aWidth forSegment:(unsigned)aSegment
{
[_segments[aSegment] setWidth:aWidth];
_segments[aSegment].width = aWidth;
[self tileWithChangedSegment:aSegment];
}
@@ -238,7 +229,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (float)widthForSegment:(unsigned)aSegment
{
return [_segments[aSegment] width];
return _segments[aSegment].width;
}
/*!
@@ -249,7 +240,9 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (void)setImage:(CPImage)anImage forSegment:(unsigned)aSegment
{
[_segments[aSegment] setImage:anImage];
var segment = _segments[aSegment];
segment.image = anImage;
[self tileWithChangedSegment:aSegment];
}
@@ -261,7 +254,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (CPImage)imageForSegment:(unsigned)aSegment
{
return [_segments[aSegment] image];
return _segments[aSegment].image;
}
/*!
@@ -272,8 +265,10 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (void)setLabel:(CPString)aLabel forSegment:(unsigned)aSegment
{
[_segments[aSegment] setLabel:aLabel];
var segment = _segments[aSegment];
_segments[aSegment].label = aLabel;
[self tileWithChangedSegment:aSegment];
}
@@ -284,7 +279,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (CPString)labelForSegment:(unsigned)aSegment
{
return [_segments[aSegment] label];
return _segments[aSegment].label;
}
/*!
@@ -295,7 +290,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (void)setMenu:(CPMenu)aMenu forSegment:(unsigned)aSegment
{
[_segments[aSegment] setMenu:aMenu];
_segments[aSegment].menu = aMenu;
}
/*!
@@ -305,7 +300,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (CPMenu)menuForSegment:(unsigned)aSegment
{
return [_segments[aSegment] menu];
return _segments[aSegment].menu;
}
/*!
@@ -318,12 +313,12 @@ CPSegmentSwitchTrackingMomentary = 2;
- (void)setSelected:(BOOL)isSelected forSegment:(unsigned)aSegment
{
var segment = _segments[aSegment];
// If we're already in this state, bail.
if ([segment selected] == isSelected)
if (segment.selected == isSelected)
return;
[segment setSelected:isSelected];
segment.selected = isSelected;
_themeStates[aSegment] = isSelected ? CPThemeStateSelected : CPThemeStateNormal;
@@ -331,18 +326,18 @@ CPSegmentSwitchTrackingMomentary = 2;
if (isSelected)
{
var oldSelectedSegment = _selectedSegment;
_selectedSegment = aSegment;
if (_trackingMode == CPSegmentSwitchTrackingSelectOne && oldSelectedSegment != aSegment && oldSelectedSegment != -1)
{
[_segments[oldSelectedSegment] setSelected:NO];
_segments[oldSelectedSegment].selected = NO;
_themeStates[oldSelectedSegment] = CPThemeStateNormal;
[self drawSegmentBezel:oldSelectedSegment highlight:NO];
}
}
if (_trackingMode != CPSegmentSwitchTrackingMomentary)
[self drawSegmentBezel:aSegment highlight:NO];
@@ -357,19 +352,17 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (BOOL)isSelectedForSegment:(unsigned)aSegment
{
return [_segments[aSegment] selected];
return _segments[aSegment].selected;
}
/*!
Enables/disables the specified segment.
Enables/diables the specified segment.
@param isEnabled \c YES enables the segment
@param aSegment the segment to enable/disable
@param aSegment the segment to enable/disble
@throws CPRangeException if \c aSegment is out of bounds
*/
- (void)setEnabled:(BOOL)isEnabled forSegment:(unsigned)aSegment
{
[_segments[aSegment] setEnabled:isEnabled];
if (isEnabled)
_themeStates[aSegment] &= ~CPThemeStateDisabled;
else
@@ -386,7 +379,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (BOOL)isEnabledForSegment:(unsigned)aSegment
{
return [_segments[aSegment] enabled];
return !(_themeStates[aSegment] & CPThemeStateDisabled)
}
/*!
@@ -396,7 +389,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (void)setTag:(int)aTag forSegment:(unsigned)aSegment
{
[_segments[aSegment] setTag:aTag];
_segments[aSegment].tag = aTag;
}
/*!
@@ -405,7 +398,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (int)tagForSegment:(unsigned)aSegment
{
return [_segments[aSegment] tag];
return _segments[aSegment].tag;
}
// Drawings
@@ -468,7 +461,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)
{
@@ -502,7 +495,7 @@ CPSegmentSwitchTrackingMomentary = 2;
- (CPView)createEphemeralSubviewNamed:(CPString)aName
{
if ([aName hasPrefix:@"segment-content"])
if (aName.substring(0, "segment-content".length) == "segment-content")
return [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
return [[CPView alloc] initWithFrame:_CGRectMakeZero()];
@@ -517,10 +510,10 @@ CPSegmentSwitchTrackingMomentary = 2;
themeState |= _themeState & CPThemeStateDisabled;
var leftCapColor = [self valueForThemeAttribute:@"left-segment-bezel-color"
inState:themeState],
var leftCapColor = [self valueForThemeAttribute:@"left-segment-bezel-color"
inState:themeState];
leftBezelView = [self layoutEphemeralSubviewNamed:@"left-segment-bezel"
var leftBezelView = [self layoutEphemeralSubviewNamed:@"left-segment-bezel"
positioned:CPWindowBelow
relativeToEphemeralSubviewNamed:nil];
@@ -530,39 +523,41 @@ CPSegmentSwitchTrackingMomentary = 2;
themeState |= _themeState & CPThemeStateDisabled;
var rightCapColor = [self valueForThemeAttribute:@"right-segment-bezel-color"
inState:themeState],
var rightCapColor = [self valueForThemeAttribute:@"right-segment-bezel-color"
inState:themeState];
rightBezelView = [self layoutEphemeralSubviewNamed:@"right-segment-bezel"
var rightBezelView = [self layoutEphemeralSubviewNamed:@"right-segment-bezel"
positioned:CPWindowBelow
relativeToEphemeralSubviewNamed:nil];
[rightBezelView setBackgroundColor:rightCapColor];
for (var i = 0, count = _themeStates.length; i < count; i++)
for (var i=0, count = _themeStates.length; i<count; i++)
{
var themeState = _themeStates[i];
themeState |= _themeState & CPThemeStateDisabled;
var bezelColor = [self valueForThemeAttribute:@"center-segment-bezel-color"
inState:themeState],
var bezelColor = [self valueForThemeAttribute:@"center-segment-bezel-color"
inState:themeState];
bezelView = [self layoutEphemeralSubviewNamed:"segment-bezel-" + i
positioned:CPWindowBelow
var bezelView = [self layoutEphemeralSubviewNamed:"segment-bezel-"+i
positioned:CPWindowBelow
relativeToEphemeralSubviewNamed:nil];
[bezelView setBackgroundColor:bezelColor];
// layout image/title views
var segment = _segments[i],
contentView = [self layoutEphemeralSubviewNamed:@"segment-content-" + i
positioned:CPWindowAbove
relativeToEphemeralSubviewNamed:@"segment-bezel-" + i];
//layout image/title views
var segment = _segments[i];
[contentView setText:[segment label]];
[contentView setImage:[segment image]];
var contentView = [self layoutEphemeralSubviewNamed:@"segment-content-"+i
positioned:CPWindowAbove
relativeToEphemeralSubviewNamed:@"segment-bezel-"+i];
[contentView setText:segment.label];
[contentView setImage:segment.image];
[contentView setFont:[self valueForThemeAttribute:@"font" inState:themeState]];
[contentView setTextColor:[self valueForThemeAttribute:@"text-color" inState:themeState]];
@@ -571,27 +566,27 @@ CPSegmentSwitchTrackingMomentary = 2;
[contentView setLineBreakMode:[self valueForThemeAttribute:@"line-break-mode" inState:themeState]];
[contentView setTextShadowColor:[self valueForThemeAttribute:@"text-shadow-color" inState:themeState]];
[contentView setTextShadowOffset:[self valueForThemeAttribute:@"text-shadow-offset" inState:themeState]];
[contentView setImageScaling:[self valueForThemeAttribute:@"image-scaling" inState:themeState]];
if ([segment image] && [segment label])
[contentView setImageScaling:[self valueForThemeAttribute:@"image-scaling" inState:themeState]];
if (segment.image && segment.label)
[contentView setImagePosition:[self valueForThemeAttribute:@"image-position" inState:themeState]];
else if ([segment image])
else if (segment.image)
[contentView setImagePosition:CPImageOnly];
if (i == count - 1)
continue;
var borderState = _themeStates[i] | _themeStates[i + 1];
var borderState = _themeStates[i] | _themeStates[i+1];
borderState = (borderState & CPThemeStateSelected & ~CPThemeStateHighlighted) ? CPThemeStateSelected : CPThemeStateNormal;
borderState |= _themeState & CPThemeStateDisabled;
var borderColor = [self valueForThemeAttribute:@"divider-bezel-color"
inState:borderState],
inState:borderState];
borderView = [self layoutEphemeralSubviewNamed:"divider-bezel-" + i
positioned:CPWindowBelow
var borderView = [self layoutEphemeralSubviewNamed:"divider-bezel-"+i
positioned:CPWindowBelow
relativeToEphemeralSubviewNamed:nil];
[borderView setBackgroundColor:borderColor];
@@ -614,53 +609,48 @@ 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 font];
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 control size
// Update Contorl Size
var frame = [self frame];
[self setFrameSize:CGSizeMake(CGRectGetWidth(frame) + delta, CGRectGetHeight(frame))];
// Update segment width
[segment setWidth:segmentWidth];
[segment setFrame:[self frameForSegment:aSegment]];
// Update Segment Width
segment.width = segmentWidth;
segment.frame = [self frameForSegment:aSegment];;
// Update following segments widths
// Update Following Segments Widths
var index = aSegment + 1;
for (; index < _segments.length; ++index)
{
[_segments[index] frame].origin.x += delta;
_segments[index].frame.origin.x += delta;
[self drawSegmentBezel:index highlight:NO];
[self drawSegment:index highlight:NO];
}
[self drawSegmentBezel:aSegment highlight:NO];
[self drawSegment:aSegment highlight:NO];
@@ -706,14 +696,14 @@ CPSegmentSwitchTrackingMomentary = 2;
{
var location = [self convertPoint:aPoint fromView:nil],
count = _segments.length;
while (count--)
if (CGRectContainsPoint([_segments[count] frame], aPoint))
if (CGRectContainsPoint(_segments[count].frame, aPoint))
return count;
if (_segments.length)
{
var adjustedLastFrame = CGRectCreateCopy([_segments[_segments.length - 1] frame]);
var adjustedLastFrame = CGRectCreateCopy(_segments[_segments.length - 1].frame);
adjustedLastFrame.size.width = CGRectGetWidth([self bounds]) - adjustedLastFrame.origin.x;
if (CGRectContainsPoint(adjustedLastFrame, aPoint))
@@ -727,7 +717,7 @@ CPSegmentSwitchTrackingMomentary = 2;
{
if (![self isEnabled])
return;
[self trackSegment:anEvent];
}
@@ -741,10 +731,10 @@ CPSegmentSwitchTrackingMomentary = 2;
@param anEvent the event to handle
*/
- (void)trackSegment:(CPEvent)anEvent
{
{
var type = [anEvent type],
location = [self convertPoint:[anEvent locationInWindow] fromView:nil];
if (type == CPLeftMouseUp)
{
if (_trackingSegment == -1)
@@ -755,30 +745,30 @@ CPSegmentSwitchTrackingMomentary = 2;
if (_trackingMode == CPSegmentSwitchTrackingSelectAny)
{
[self setSelected:![self isSelectedForSegment:_trackingSegment] forSegment:_trackingSegment];
// With ANY, _selectedSegment means last pressed.
_selectedSegment = _trackingSegment;
}
else
[self setSelected:YES forSegment:_trackingSegment];
[self sendAction:[self action] to:[self target]];
if (_trackingMode == CPSegmentSwitchTrackingMomentary)
{
[self setSelected:NO forSegment:_trackingSegment];
_selectedSegment = -1;
}
}
[self drawSegmentBezel:_trackingSegment highlight:NO];
_trackingSegment = -1;
return;
}
if (type == CPLeftMouseDown)
{
var trackingSegment = [self testSegment:location];
@@ -789,7 +779,7 @@ CPSegmentSwitchTrackingMomentary = 2;
[self drawSegmentBezel:_trackingSegment highlight:YES];
}
}
else if (type == CPLeftMouseDragged)
{
if (_trackingSegment == -1)
@@ -803,14 +793,14 @@ CPSegmentSwitchTrackingMomentary = 2;
[self drawSegmentBezel:_trackingSegment highlight:_trackingHighlighted];
}
}
[CPApp setTarget:self selector:@selector(trackSegment:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
}
- (void)setFont:(CPFont)aFont
{
[super setFont:aFont];
[self tileWithChangedSegment:0];
}
@@ -826,12 +816,12 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
var frame = [self frame],
originalWidth = frame.size.width;
frame.size.width = 0;
[self setFrame:frame];
@@ -842,38 +832,38 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
if ([aCoder containsValueForKey:CPSegmentedControlSelectedKey])
_selectedSegment = [aCoder decodeIntForKey:CPSegmentedControlSelectedKey];
else
else
_selectedSegment = -1;
if ([aCoder containsValueForKey:CPSegmentedControlTrackingModeKey])
_trackingMode = [aCoder decodeIntForKey:CPSegmentedControlTrackingModeKey];
else
_trackingMode = CPSegmentSwitchTrackingSelectOne;
// HACK
for (var i = 0; i < _segments.length; i++)
{
_themeStates[i] = [_segments[i] selected] ? CPThemeStateSelected : CPThemeStateNormal;
_themeStates[i] = _segments[i].selected ? CPThemeStateSelected : CPThemeStateNormal;
[self tileWithChangedSegment:i];
}
var difference = MAX(originalWidth - [self frame].size.width, 0.0),
remainingWidth = FLOOR(difference / _segments.length);
for (var i = 0; i < _segments.length; i++)
[self setWidth:[_segments[i] width] + remainingWidth forSegment:i];
for (var i=0; i < _segments.length; i++)
[self setWidth:_segments[i].width + remainingWidth forSegment:i];
[self tileWithChangedSegment:0];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:_segments forKey:CPSegmentedControlSegmentsKey];
[aCoder encodeInt:_selectedSegment forKey:CPSegmentedControlSelectedKey];
[aCoder encodeInt:_segmentStyle forKey:CPSegmentedControlSegmentStyleKey];
@@ -885,15 +875,15 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
@implementation _CPSegmentItem : CPObject
{
CPImage image @accessors;
CPString label @accessors;
CPMenu menu @accessors;
BOOL selected @accessors;
BOOL enabled @accessors;
int tag @accessors;
int width @accessors;
CPImage image;
CPString label;
CPMenu menu;
BOOL selected;
BOOL enabled;
int tag;
int width;
CGRect frame @accessors;
CGRect frame;
}
- (id)init
@@ -904,8 +894,8 @@ var CPSegmentedControlSegmentsKey = "CPSegmentedControlSegmentsKey",
label = @"";
menu = nil;
selected = NO;
enabled = YES;
tag = -1;
enabled = NO;
tag = 0;
width = 0;
frame = CGRectMakeZero();
@@ -928,7 +918,7 @@ var CPSegmentItemImageKey = "CPSegmentItemImageKey",
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
if (self)
{
image = [aCoder decodeObjectForKey:CPSegmentItemImageKey];
@@ -941,7 +931,7 @@ var CPSegmentItemImageKey = "CPSegmentItemImageKey",
frame = CGRectMakeZero();
}
return self;
}
@@ -957,3 +947,4 @@ var CPSegmentItemImageKey = "CPSegmentItemImageKey",
}
@end
+6 -6
View File
@@ -23,8 +23,8 @@
@import <Foundation/CPObject.j>
/*!
@deprecated
/*!
@deprecated
@class CPShadow
Instances of this class contain the attributes of a drop shadow used in Cappuccino.
@@ -34,7 +34,7 @@
CPSize _offset;
float _blurRadius;
CPColor _color;
CPString _cssString;
}
@@ -54,16 +54,16 @@
- (id)_initWithOffset:(CPSize)anOffset blurRadius:(float)aBlurRadius color:(CPColor)aColor
{
self = [super init];
if (self)
{
_offset = anOffset;
_blurRadius = aBlurRadius;
_color = aColor;
_cssString = [_color cssString] + " " + Math.round(anOffset.width) + @"px " + Math.round(anOffset.height) + @"px " + Math.round(_blurRadius) + @"px";
}
return self;
}
+18 -41
View File
@@ -28,17 +28,19 @@
@import "CPView.j"
#include "CoreGraphics/CGGeometry.h"
CPLightShadow = 0;
CPHeavyShadow = 1;
var CPShadowViewLightBackgroundColor = nil,
CPShadowViewHeavyBackgroundColor = nil;
var LIGHT_LEFT_INSET = 3.0,
LIGHT_RIGHT_INSET = 3.0,
LIGHT_TOP_INSET = 3.0,
LIGHT_BOTTOM_INSET = 5.0,
HEAVY_LEFT_INSET = 7.0,
HEAVY_RIGHT_INSET = 7.0,
HEAVY_TOP_INSET = 5.0,
@@ -59,76 +61,51 @@ 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;
}
@@ -136,9 +113,9 @@ var LIGHT_LEFT_INSET = 3.0,
{
if (_weight == aWeight)
return;
_weight = aWeight;
if (_weight == CPLightShadow)
[self setBackgroundColor:CPShadowViewLightBackgroundColor];
@@ -170,7 +147,7 @@ var LIGHT_LEFT_INSET = 3.0,
{
if (_weight == CPLightShadow)
return LIGHT_LEFT_INSET + LIGHT_RIGHT_INSET;
return HEAVY_LEFT_INSET + HEAVY_RIGHT_INSET;
}
@@ -178,7 +155,7 @@ var LIGHT_LEFT_INSET = 3.0,
{
if (_weight == CPLightShadow)
return LIGHT_TOP_INSET + LIGHT_BOTTOM_INSET;
return HEAVY_TOP_INSET + HEAVY_BOTTOM_INSET;
}
+43 -44
View File
@@ -22,6 +22,7 @@
@import "CPControl.j"
#include "CoreGraphics/CGGeometry.h"
/*! SLIDER STATES */
@@ -41,7 +42,7 @@ CPCircularSlider = 1;
BOOL _isVertical;
}
+ (CPString)defaultThemeClass
+ (CPString)themeClass
{
return "slider";
}
@@ -60,14 +61,14 @@ CPCircularSlider = 1;
{
_minValue = 0.0;
_maxValue = 100.0;
[self setObjectValue:50.0];
[self setContinuous:YES];
[self _recalculateIsVertical];
}
return self;
}
@@ -75,11 +76,11 @@ CPCircularSlider = 1;
{
if (_minValue === aMinimumValue)
return;
_minValue = aMinimumValue;
var doubleValue = [self doubleValue];
if (doubleValue < _minValue)
[self setDoubleValue:_minValue];
@@ -97,11 +98,11 @@ CPCircularSlider = 1;
{
if (_maxValue === aMaximumValue)
return;
_maxValue = aMaximumValue;
var doubleValue = [self doubleValue];
if (doubleValue > _maxValue)
[self setDoubleValue:_maxValue];
@@ -168,27 +169,27 @@ CPCircularSlider = 1;
bounds.size.height = trackWidth;
}
}
return bounds;
}
- (CGRect)knobRectForBounds:(CGRect)bounds
{
var knobSize = [self currentValueForThemeAttribute:@"knob-size"];
if (knobSize.width <= 0 || knobSize.height <= 0)
return _CGRectMakeZero();
var knobRect = _CGRectMake(0.0, 0.0, knobSize.width, knobSize.height),
trackRect = [self trackRectForBounds:bounds];
// No track, do our best to approximate a place for this thing.
if (!trackRect || _CGRectIsEmpty(trackRect))
trackRect = bounds;
if ([self hasThemeState:CPThemeStateCircular])
{
var angle = 3 * PI_2 - (1.0 - [self doubleValue] - _minValue) / (_maxValue - _minValue) * PI2,
var angle = 3*PI_2 - (1.0 - [self doubleValue] - _minValue) / (_maxValue - _minValue) * PI2,
radius = CGRectGetWidth(trackRect) / 2.0 - 8.0;
knobRect.origin.x = radius * COS(angle) + CGRectGetMidX(trackRect) - 3.0;
@@ -197,7 +198,7 @@ CPCircularSlider = 1;
else if ([self isVertical])
{
knobRect.origin.x = _CGRectGetMidX(trackRect) - knobSize.width / 2.0;
knobRect.origin.y = ((_maxValue - [self doubleValue]) / (_maxValue - _minValue)) * (_CGRectGetHeight(trackRect) - knobSize.height);
knobRect.origin.y = (([self doubleValue] - _minValue) / (_maxValue - _minValue)) * (_CGRectGetHeight(trackRect) - knobSize.height);
}
else
{
@@ -212,10 +213,10 @@ CPCircularSlider = 1;
{
if (aName === "track-view")
return [self trackRectForBounds:[self bounds]];
else if (aName === "knob-view")
return [self knobRectForBounds:[self bounds]];
return [super rectForEphemeralSubviewNamed:aName];
}
@@ -224,12 +225,12 @@ CPCircularSlider = 1;
if (aName === "track-view" || aName === "knob-view")
{
var view = [[CPView alloc] init];
[view setHitTests:NO];
return view;
}
return [super createEphemeralSubviewNamed:aName];
}
@@ -255,7 +256,7 @@ CPCircularSlider = 1;
var bounds = [self bounds],
width = _CGRectGetWidth(bounds),
height = _CGRectGetHeight(bounds);
_isVertical = width < height ? 1 : (width > height ? 0 : -1);
if (_isVertical === 1)
@@ -281,7 +282,7 @@ CPCircularSlider = 1;
var knobView = [self layoutEphemeralSubviewNamed:@"knob-view"
positioned:CPWindowAbove
relativeToEphemeralSubviewNamed:@"track-view"];
if (knobView)
[knobView setBackgroundColor:[self currentValueForThemeAttribute:"knob-color"]];
}
@@ -319,7 +320,7 @@ CPCircularSlider = 1;
var minValue = [self minValue];
return MAX(0.0, MIN(1.0, (_CGRectGetMaxY(trackRect) - aPoint.y) / _CGRectGetHeight(trackRect))) * ([self maxValue] - minValue) + minValue;
return MAX(0.0, MIN(1.0, (aPoint.y - _CGRectGetMinY(trackRect)) / _CGRectGetHeight(trackRect))) * ([self maxValue] - minValue) + minValue;
}
else
{
@@ -338,43 +339,44 @@ CPCircularSlider = 1;
{
var bounds = [self bounds],
knobRect = [self knobRectForBounds:_CGRectMakeCopy(bounds)];
if (_CGRectContainsPoint(knobRect, aPoint))
_dragOffset = _CGSizeMake(_CGRectGetMidX(knobRect) - aPoint.x, _CGRectGetMidY(knobRect) - aPoint.y);
else
else
{
var trackRect = [self trackRectForBounds:bounds];
if (trackRect && _CGRectContainsPoint(trackRect, aPoint))
{
_dragOffset = _CGSizeMakeZero();
[self setObjectValue:[self _valueAtPoint:aPoint]];
}
else
return NO;
}
[self setHighlighted:YES];
[self setNeedsLayout];
[self setNeedsDisplay:YES];
return YES;
return YES;
}
- (BOOL)continueTracking:(CGPoint)lastPoint at:(CGPoint)aPoint
{
[self setObjectValue:[self _valueAtPoint:_CGPointMake(aPoint.x + _dragOffset.width, aPoint.y + _dragOffset.height)]];
return YES;
}
- (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp
{
[self setHighlighted:NO];
if ([_target respondsToSelector:@selector(sliderDidFinish:)])
[_target sliderDidFinish:self];
@@ -382,20 +384,15 @@ CPCircularSlider = 1;
[self setNeedsDisplay:YES];
}
- (BOOL)isContinuous
{
return (_sendActionOn & CPLeftMouseDraggedMask) !== 0;
}
/*!
@ignore
should we have _continuous?
shoudl we have _continuous?
*/
- (void)setContinuous:(BOOL)flag
{
if (flag)
_sendActionOn |= CPLeftMouseDraggedMask;
else
else
_sendActionOn &= ~CPLeftMouseDraggedMask;
}
@@ -430,6 +427,8 @@ var CPSliderMinValueKey = "CPSliderMinValueKey",
{
_altIncrementValue = [aCoder decodeDoubleForKey:CPSliderAltIncrValueKey];
[self setContinuous:YES];
[self _recalculateIsVertical];
[self setNeedsLayout];
@@ -455,14 +454,14 @@ var CPSliderMinValueKey = "CPSliderMinValueKey",
- (id)value
{
CPLog.warn("[CPSlider value] is deprecated, use doubleValue or objectValue instead.");
return [self doubleValue];
return [self doubleValue];
}
- (void)setValue:(id)aValue
{
CPLog.warn("[CPSlider setValue:] is deprecated, use setDoubleValue: or setObjectValue: instead.");
[self setObjectValue:aValue];
}
+211 -154
View File
@@ -20,24 +20,22 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPView.j"
@import "CPColorPicker.j"
/*
@ignore
*/
@implementation CPSliderColorPicker : CPColorPicker
{
{
CPView _contentView;
CPSlider _redSlider;
CPSlider _greenSlider;
CPSlider _blueSlider;
CPSlider _hueSlider;
CPSlider _saturationSlider;
CPSlider _brightnessSlider;
CPTextField _rgbLabel;
CPTextField _hsbLabel;
CPTextField _redLabel;
@@ -47,161 +45,262 @@
CPTextField _saturationLabel;
CPTextField _brightnessLabel;
CPTextField _hexLabel;
CPTextField _hexValue;
CPTextField _hexValue;
CPTextField _redValue;
CPTextField _greenValue;
CPTextField _blueValue;
CPTextField _hueValue;
CPTextField _saturationValue;
CPTextField _brightnessValue;
#if PLATFORM(DOM)
DOMElement _redValue;
DOMElement _greenValue;
DOMElement _blueValue;
DOMElement _hueValue;
DOMElement _saturationValue;
DOMElement _brightnessValue;
DOMElement _hexValue;
#endif
}
- (id)initWithPickerMask:(int)mask colorPanel:(CPColorPanel)owningColorPanel
- (id)initWithPickerMask:(int)mask colorPanel:(CPColorPanel)owningColorPanel
{
return [super initWithPickerMask:mask colorPanel: owningColorPanel];
}
- (id)initView
-(id)initView
{
aFrame = CGRectMake(0, 0, CPColorPickerViewWidth, CPColorPickerViewHeight);
aFrame = CPRectMake(0, 0, CPColorPickerViewWidth, CPColorPickerViewHeight);
_contentView = [[CPView alloc] initWithFrame:aFrame];
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
_rgbLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 10, 100, 20)];
[_contentView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
_rgbLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 10, 100, 20)];
[_rgbLabel setStringValue: "Red, Green, Blue"];
[_rgbLabel setTextColor:[CPColor blackColor]];
_redLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 37, 15, 20)];
_redLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 35, 15, 20)];
[_redLabel setStringValue: "R"];
[_redLabel setTextColor:[CPColor blackColor]];
_redSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 35, aFrame.size.width - 70, 20)];
_redSlider = [[CPSlider alloc] initWithFrame: CPRectMake(15, 35, aFrame.size.width - 70, 20)];
[_redSlider setMaxValue: 1.0];
[_redSlider setMinValue: 0.0];
[_redSlider setTarget: self];
[_redSlider setAction: @selector(sliderChanged:)];
[_redSlider setAutoresizingMask: CPViewWidthSizable];
// red value input box
_redValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 30, 45, 28)];
[_redValue setAutoresizingMask: CPViewMinXMargin];
[_redValue setEditable: YES];
[_redValue setBezeled: YES];
[_redValue setDelegate: self];
[_contentView addSubview: _redValue];
#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;
_greenLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 63, 15, 20)];
case _hueValue: [_hueSlider setFloatValue:MAX(MIN(ROUND(this.value), 360), 0)];
//[self sliderChanged: _hueSlider];
break;
case _saturationValue: [_saturationSlider setFloatValue:MAX(MIN(ROUND(this.value), 100), 0)];
//[self sliderChanged: _saturationSlider];
break;
case _brightnessValue: [_brightnessSlider setFloatValue:MAX(MIN(ROUND(this.value), 100), 0)];
//[self sliderChanged: _brightnessSlider];
break;
}
this.blur();
};
var keypressFunction = function(aDOMEvent)
{
aDOMEvent = aDOMEvent || window.event;
if (aDOMEvent.keyCode == 13)
{
updateFunction(aDOMEvent);
if(aDOMEvent.preventDefault)
aDOMEvent.preventDefault();
else if(aDOMEvent.stopPropagation)
aDOMEvent.stopPropagation();
}
}
//red value input box
var redValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 35, 45, 20)];
[redValue setAutoresizingMask: CPViewMinXMargin];
_redValue = document.createElement("input");
_redValue.style.width = "40px";
_redValue.style.backgroundColor = "transparent";
_redValue.style.border = "1px solid black";
_redValue.style.color = "black";
_redValue.style.position = "absolute";
_redValue.style.top = "0px";
_redValue.style.left = "0px";
_redValue.onchange = updateFunction;
redValue._DOMElement.appendChild(_redValue);
[_contentView addSubview: redValue];
#endif
_greenLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 58, 15, 20)];
[_greenLabel setStringValue: "G"];
[_greenLabel setTextColor:[CPColor blackColor]];
_greenSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 61, aFrame.size.width - 70, 20)];
_greenSlider = [[CPSlider alloc] initWithFrame: CPRectMake(15, 58, aFrame.size.width - 70, 20)];
[_greenSlider setMaxValue: 1.0];
[_greenSlider setMinValue: 0.0];
[_greenSlider setTarget: self];
[_greenSlider setAction: @selector(sliderChanged:)];
[_greenSlider setAutoresizingMask: CPViewWidthSizable];
// green value input box
_greenValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 56, 45, 28)];
[_greenValue setAutoresizingMask: CPViewMinXMargin];
[_greenValue setEditable: YES];
[_greenValue setBezeled: YES];
[_greenValue setDelegate: self];
[_contentView addSubview: _greenValue];
#if PLATFORM(DOM)
//green value input box
var greenValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 58, 45, 20)];
[greenValue setAutoresizingMask: CPViewMinXMargin];
_blueLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 90, 15, 20)];
_greenValue = _redValue.cloneNode(false);
_greenValue.onchange = updateFunction;
greenValue._DOMElement.appendChild(_greenValue);
[_contentView addSubview: greenValue];
#endif
_blueLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 81, 15, 20)];
[_blueLabel setStringValue: "B"];
[_blueLabel setTextColor:[CPColor blackColor]];
_blueSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 87, aFrame.size.width - 70, 20)];
_blueSlider = [[CPSlider alloc] initWithFrame: CPRectMake(15, 81, aFrame.size.width - 70, 20)];
[_blueSlider setMaxValue: 1.0];
[_blueSlider setMinValue: 0.0];
[_blueSlider setTarget: self];
[_blueSlider setAction: @selector(sliderChanged:)];
[_blueSlider setAutoresizingMask: CPViewWidthSizable];
// blue value input box
_blueValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 82, 45, 28)];
[_blueValue setAutoresizingMask: CPViewMinXMargin];
[_blueValue setEditable: YES];
[_blueValue setBezeled: YES];
[_blueValue setDelegate: self];
[_contentView addSubview: _blueValue];
#if PLATFORM(DOM)
//blue value input box
var blueValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 81, 45, 20)];
[blueValue setAutoresizingMask: CPViewMinXMargin];
_hsbLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 120, 190, 20)];
_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]];
_hueLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 145, 15, 20)];
_hueLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 145, 15, 20)];
[_hueLabel setStringValue: "H"];
[_hueLabel setTextColor:[CPColor blackColor]];
_hueSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 143, aFrame.size.width - 70, 20)];
_hueSlider = [[CPSlider alloc] initWithFrame: CPRectMake(15, 145, aFrame.size.width - 70, 20)];
[_hueSlider setMaxValue: 359.0];
[_hueSlider setMinValue: 0.0];
[_hueSlider setTarget: self];
[_hueSlider setAction: @selector(sliderChanged:)];
[_hueSlider setAutoresizingMask: CPViewWidthSizable];
// hue value input box
_hueValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 138, 45, 28)];
[_hueValue setAutoresizingMask: CPViewMinXMargin];
[_hueValue setEditable: YES];
[_hueValue setBezeled: YES];
[_hueValue setDelegate: self];
[_contentView addSubview: _hueValue];
#if PLATFORM(DOM)
//red value input box
var hueValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 145, 45, 20)];
[hueValue setAutoresizingMask: CPViewMinXMargin];
_saturationLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 170, 15, 20)];
_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]];
_saturationSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 168, aFrame.size.width - 70, 20)];
_saturationSlider = [[CPSlider alloc] initWithFrame: CPRectMake(15, 168, aFrame.size.width - 70, 20)];
[_saturationSlider setMaxValue: 100.0];
[_saturationSlider setMinValue: 0.0];
[_saturationSlider setTarget: self];
[_saturationSlider setAction: @selector(sliderChanged:)];
[_saturationSlider setAutoresizingMask: CPViewWidthSizable];
// saturation value input box
_saturationValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 164, 45, 28)];
[_saturationValue setAutoresizingMask: CPViewMinXMargin];
[_saturationValue setEditable: YES];
[_saturationValue setBezeled: YES];
[_saturationValue setDelegate: self];
[_contentView addSubview: _saturationValue];
#if PLATFORM(DOM)
//green value input box
var saturationValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 168, 45, 20)];
[saturationValue setAutoresizingMask: CPViewMinXMargin];
_brightnessLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 196, 15, 20)];
_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]];
_brightnessSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 194, aFrame.size.width - 70, 20)];
_brightnessSlider = [[CPSlider alloc] initWithFrame: CPRectMake(15, 191, aFrame.size.width - 70, 20)];
[_brightnessSlider setMaxValue: 100.0];
[_brightnessSlider setMinValue: 0.0];
[_brightnessSlider setTarget: self];
[_brightnessSlider setAction: @selector(sliderChanged:)];
[_brightnessSlider setAutoresizingMask: CPViewWidthSizable];
// brightness value input box
_brightnessValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 190, 45, 28)];
[_brightnessValue setAutoresizingMask: CPViewMinXMargin];
[_brightnessValue setEditable: YES];
[_brightnessValue setBezeled: YES];
[_brightnessValue setDelegate: self];
[_contentView addSubview: _brightnessValue];
#if PLATFORM(DOM)
//blue value input box
var brightnessValue = [[CPView alloc] initWithFrame: CPRectMake(aFrame.size.width - 45, 191, 45, 20)];
[brightnessValue setAutoresizingMask: CPViewMinXMargin];
_hexLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 230, 30, 20)];
_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 = [[CPTextField alloc] initWithFrame: CGRectMake(32, 225, 80, 28)];
[_hexValue setEditable: YES];
[_hexValue setBezeled: YES];
[_hexValue setDelegate: self];
[_contentView addSubview: _hexValue];
_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
[_contentView addSubview: _rgbLabel];
[_contentView addSubview: _redLabel];
@@ -210,7 +309,7 @@
[_contentView addSubview: _redSlider];
[_contentView addSubview: _greenSlider];
[_contentView addSubview: _blueSlider];
[_contentView addSubview: _hsbLabel];
[_contentView addSubview: _hueLabel];
[_contentView addSubview: _saturationLabel];
@@ -218,35 +317,35 @@
[_contentView addSubview: _hueSlider];
[_contentView addSubview: _saturationSlider];
[_contentView addSubview: _brightnessSlider];
[_contentView addSubview: _hexLabel];
}
- (CPView)provideNewView:(BOOL)initialRequest
- (CPView)provideNewView:(BOOL)initialRequest
{
if (initialRequest)
if (initialRequest)
[self initView];
return _contentView;
}
- (int)currentMode
- (int)currentMode
{
return CPSliderColorPickerMode;
}
- (BOOL)supportsMode:(int)mode
- (BOOL)supportsMode:(int)mode
{
return (mode == CPSliderColorPickerMode) ? YES : NO;
}
- (void)sliderChanged:(id)sender
-(void)sliderChanged:(id)sender
{
var newColor,
colorPanel = [self colorPanel],
alpha = [colorPanel opacity];
switch (sender)
switch(sender)
{
case _hueSlider:
case _saturationSlider:
@@ -254,27 +353,27 @@
saturation: [_saturationSlider floatValue]
brightness: [_brightnessSlider floatValue]
alpha: alpha];
[self updateRGBSliders: newColor];
break;
case _redSlider:
case _greenSlider:
case _blueSlider: newColor = [CPColor colorWithCalibratedRed: [_redSlider floatValue]
green: [_greenSlider floatValue]
blue: [_blueSlider floatValue]
alpha: alpha];
[self updateHSBSliders: newColor];
break;
}
[self updateLabels];
[self updateHex: newColor];
[colorPanel setColor: newColor];
}
- (void)setColor:(CPColor)aColor
-(void)setColor:(CPColor)aColor
{
[self updateRGBSliders: aColor];
[self updateHSBSliders: aColor];
@@ -282,10 +381,10 @@
[self updateLabels];
}
- (void)updateHSBSliders:(CPColor)aColor
-(void)updateHSBSliders:(CPColor)aColor
{
var hsb = [aColor hsbComponents];
[_hueSlider setFloatValue:hsb[0]];
[_saturationSlider setFloatValue:hsb[1]];
[_brightnessSlider setFloatValue:hsb[2]];
@@ -293,7 +392,9 @@
- (void)updateHex:(CPColor)aColor
{
[_hexValue setStringValue:[aColor hexString]];
#if PLATFORM(DOM)
_hexValue.value = [aColor hexString];
#endif
}
- (void)updateRGBSliders:(CPColor)aColor
@@ -307,13 +408,15 @@
- (void)updateLabels
{
[_hueValue setStringValue: ROUND([_hueSlider floatValue])];
[_saturationValue setStringValue: ROUND([_saturationSlider floatValue])];
[_brightnessValue setStringValue: ROUND([_brightnessSlider floatValue])];
[_redValue setStringValue: ROUND([_redSlider floatValue] * 255)];
[_greenValue setStringValue: ROUND([_greenSlider floatValue] * 255)];
[_blueValue setStringValue: ROUND([_blueSlider floatValue] * 255)];
#if PLATFORM(DOM)
_hueValue.value = ROUND([_hueSlider floatValue]);
_saturationValue.value = ROUND([_saturationSlider floatValue]);
_brightnessValue.value = ROUND([_brightnessSlider floatValue]);
_redValue.value = ROUND([_redSlider floatValue] * 255);
_greenValue.value = ROUND([_greenSlider floatValue] * 255);
_blueValue.value = ROUND([_blueSlider floatValue] * 255);
#endif
}
- (CPImage)provideNewButtonImage
@@ -326,50 +429,4 @@
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
-303
View File
@@ -1,303 +0,0 @@
/*
* CPSound.j
* AppKit
*
* Created by Antoine Mercadal
* Copyright 2010, Antoine Mercadal
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPObject.j>
CPSoundLoadStateEmpty = 0;
CPSoundLoadStateLoading = 1;
CPSoundLoadStateCanBePlayed = 2;
CPSoundLoadStateError = 3;
CPSoundPlayBackStatePlay = 0;
CPSoundPlayBackStateStop = 1;
CPSoundPlayBackStatePause = 2;
/*!
CPSound provides a way to load and play sounds. In the browser it relies on the
HTML5 audio tag being available.
CPSound delegate:
- sound:didFinishPlaying: called when sound has finished to played
*/
@implementation CPSound : CPObject
{
CPString _name @accessors(property=name);
id _delegate @accessors(property=delegate);
HTMLAudioElement _audioTag;
int _loadStatus;
int _playBackStatus;
}
#pragma mark -
#pragma mark Initialization
- (id)init
{
if (self = [super init])
{
_loadStatus = CPSoundLoadStateEmpty;
_loops = NO;
_audioTag = document.createElement("audio");
_audioTag.preload = YES;
_audioTag.addEventListener("canplay", function()
{
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
[self _soundDidload];
}, true);
_audioTag.addEventListener("ended", function()
{
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
[self _soundDidEnd];
}, true);
_audioTag.addEventListener("error", function()
{
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
[self _soundError];
}, true);
}
return self;
}
/*!
Initialize with the sound contents of the URL represented by aFile.
@param aFile CPString the path of the sound
@param byRef ignored (Cocoa compatibility)
*/
- (id)initWithContentsOfFile:(CPString)aFile byReference:(BOOL)byRef
{
if (self = [self init])
{
_loadStatus = CPSoundLoadStateLoading;
_audioTag.src = aFile;
}
return self;
}
/*!
Initialize with the sound contents of the file located at aURL.
@param aURL CPURL containing the URL of the sound
@param byRef ignored (Cocoa compatibility)
*/
- (id)initWithContentsOfURL:(CPURL)aURL byReference:(BOOL)byRef
{
return [self initWithContentsOfFile:[aURL absoluteString] byReference:NO];
}
/*!
Initialize with the sound contents of someData.
@param someData CPData containing the sound
@param byRef ignored (Cocoa compatibility)
*/
- (id)initWithData:(CPData)someData
{
if (self = [self init])
{
_loadStatus = CPSoundLoadStateLoading;
_audioTag.src = [someData rawString];
}
return self;
}
#pragma mark -
#pragma mark Events listener
/*! @ignore
*/
- (void)_soundDidload
{
_loadStatus = CPSoundLoadStateCanBePlayed;
}
/*! @ignore
*/
- (void)_soundDidEnd
{
if (![self loops])
[self stop];
}
/*! @ignore
*/
- (void)_soundError
{
_loadStatus = CPSoundLoadStateError;
CPLog.error("Cannot load sound. Maybe the format of your sound is not compatible with your browser.");
}
#pragma mark -
#pragma mark Media controls
/*!
Play the sound.
@return YES when the receiver is playing its audio data, NO otherwise.
*/
- (BOOL)play
{
if ((_loadStatus !== CPSoundLoadStateCanBePlayed)
|| (_playBackStatus === CPSoundPlayBackStatePlay))
return NO;
_audioTag.play();
_playBackStatus = CPSoundPlayBackStatePlay;
return YES;
}
/*!
Stop the sound.
@return YES when the receiver is playing its audio data, NO otherwise.
*/
- (BOOL)stop
{
if ((_loadStatus !== CPSoundLoadStateCanBePlayed)
|| (_playBackStatus === CPSoundPlayBackStateStop))
return NO;
_audioTag.pause();
_audioTag.currentTime = 0.0;
_playBackStatus = CPSoundPlayBackStateStop;
if (_delegate && [_delegate respondsToSelector:@selector(sound:didFinishPlaying:)])
[_delegate sound:self didFinishPlaying:YES];
return YES;
}
/*!
Pause the sound.
@return YES when the receiver is playing its audio data, NO otherwise.
*/
- (BOOL)pause
{
if ((_loadStatus !== CPSoundLoadStateCanBePlayed)
|| (_playBackStatus === CPSoundPlayBackStatePause))
return NO;
_audioTag.pause();
_playBackStatus = CPSoundPlayBackStatePause;
return YES;
}
/*!
Resume playback of a paused sound.
@return YES when the receiver is playing its audio data, NO otherwise.
*/
- (BOOL)resume
{
if ((_loadStatus !== CPSoundLoadStateCanBePlayed)
|| (_playBackStatus !== CPSoundPlayBackStatePause))
return NO;
_audioTag.play();
_playBackStatus = CPSoundPlayBackStatePlay;
return YES;
}
/*!
Return YES if the sound is in loop mode.
@return BOOL YES if in loop mode, NO otherwise
*/
- (BOOL)loops
{
return _audioTag.loop;
}
/*!
Specifies whether the sound should repeat.
@param BOOL YES for loop mode, NO otherwise
*/
- (void)setLoops:(BOOL)shouldLoop
{
_audioTag.loop = shouldLoop;
}
/*!
Returns the volume of the receiver.
@return double from 0.0 to 1.0
*/
- (double)volume
{
return _audioTag.volume;
}
/*!
Set the volume the sound should be played at.
@param double a volume value between 0.0 and 1.0
*/
- (void)setVolume:(double)aVolume
{
if (aVolume > 1.0)
aVolume = 1.0;
else if (aVolume < 0.0)
aVolume = 0.0;
_audioTag.volume = aVolume;
}
#pragma mark -
#pragma mark Accessors
/*!
Returns the duration in seconds of the sound.
@return double the duration
*/
- (double)duration
{
return _audioTag.duration;
}
/*!
Returns if the sound is playing or not.
@return BOOL YES if the sound is playing, NO otherwise
*/
- (BOOL)isPlaying
{
return (_playBackStatus === CPSoundPlayBackStatePlay);
}
@end
+45 -225
View File
@@ -24,6 +24,10 @@
@import "CPImage.j"
@import "CPView.j"
#include "CoreGraphics/CGGeometry.h"
#include "Platform/Platform.h"
#include "Platform/DOM/CPDOMDisplayServer.h"
CPSplitViewDidResizeSubviewsNotification = @"CPSplitViewDidResizeSubviewsNotification";
CPSplitViewWillResizeSubviewsNotification = @"CPSplitViewWillResizeSubviewsNotification";
@@ -33,14 +37,6 @@ var CPSplitViewHorizontalImage = nil,
/*!
@ingroup appkit
@class CPSplitView
CPSplitView is a view that allows you to stack several subviews vertically or horizontally. The user is given divider to resize the subviews.
The divider indices are zero-based. So the divider on the top (or left for vertical dividers) will be index 0.
CPSplitView can be supplied a delegate to provide control over the resizing of the splitview and subviews. Those methods are documented in setDelegate:
CPSplitView will add dividers for each subview you add. So just like adding subviews to a CPView you should call addSubview: to add new resizable subviews in your splitview.
*/
@implementation CPSplitView : CPView
@@ -51,7 +47,6 @@ var CPSplitViewHorizontalImage = nil,
int _currentDivider;
float _initialOffset;
float _preCollapsePosition;
CPString _originComponent;
CPString _sizeComponent;
@@ -65,17 +60,6 @@ var CPSplitViewHorizontalImage = nil,
CPArray _buttonBars;
}
+ (CPString)defaultThemeClass
{
return @"splitview";
}
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[1.0, 10.0, [CPColor grayColor]]
forKeys:[@"divider-thickness", @"pane-divider-thickness", @"pane-divider-color"]];
}
/*
@ignore
*/
@@ -104,28 +88,16 @@ var CPSplitViewHorizontalImage = nil,
return self;
}
/*!
Returns the thickness of the divider.
@return float - the thickness of the divider.
*/
- (float)dividerThickness
{
return [self currentValueForThemeAttribute:[self isPaneSplitter] ? @"pane-divider-thickness" : @"divider-thickness"];
return _isPaneSplitter ? 1.0 : 10.0;
}
/*!
Returns YES if the dividers are vertical, otherwise NO.
@return YES if vertical, otherwise NO.
*/
- (BOOL)isVertical
{
return _isVertical;
}
/*!
Sets if the splitview dividers are vertical.
@param shouldBeVertical - YES if the splitview dividers should be vertical, otherwise NO.
*/
- (void)setVertical:(BOOL)shouldBeVertical
{
if (![self _setVertical:shouldBeVertical])
@@ -167,21 +139,11 @@ var CPSplitViewHorizontalImage = nil,
return changed;
}
/*!
Use to find if the divider is a larger pane splitter.
@return BOOL - YES if the dividers are the larger pane splitters. Otherwise NO.
*/
- (BOOL)isPaneSplitter
{
return _isPaneSplitter;
}
/*!
Used to set if the split view dividers should be the larger pane splitter.
@param shouldBePaneSplitter - YES if the dividers should be the thicker pane splitter, otherwise NO.
*/
- (void)setIsPaneSplitter:(BOOL)shouldBePaneSplitter
{
if (_isPaneSplitter == shouldBePaneSplitter)
@@ -189,8 +151,8 @@ var CPSplitViewHorizontalImage = nil,
_isPaneSplitter = shouldBePaneSplitter;
if (_DOMDividerElements[_drawingDivider])
[self _setupDOMDivider];
if(_DOMDividerElements[_drawingDivider])
[self _setupDOMDivider]
// The divider changes size when pane splitter mode is toggled, so the
// subviews need to change size too.
@@ -203,22 +165,11 @@ var CPSplitViewHorizontalImage = nil,
_needsResizeSubviews = YES;
}
/*!
Returns YES if the supplied subview is collapsed, otherwise NO.
@param aSubview - the subview you are interested in.
@return BOOL - YES if the subview is collapsed, otherwise NO.
*/
- (BOOL)isSubviewCollapsed:(CPView)subview
{
return [subview frame].size[_sizeComponent] < 1 ? YES : NO;
}
/*!
Returns the CGRect of the divider at a given index.
@param int - The index of a divider.
@return CGRect - The rect of a divider.
*/
- (CGRect)rectOfDividerAtIndex:(int)aDivider
{
var frame = [_subviews[aDivider] frame],
@@ -232,16 +183,11 @@ var CPSplitViewHorizontalImage = nil,
return rect;
}
/*!
Returns the rect of the divider which the user is able to drag to resize.
@param int - The index of the divider.
@return CGRect - The rect the user can drag.
*/
- (CGRect)effectiveRectOfDividerAtIndex:(int)aDivider
{
var realRect = [self rectOfDividerAtIndex:aDivider],
padding = 2;
var realRect = [self rectOfDividerAtIndex:aDivider];
var padding = 2;
realRect.size[_sizeComponent] += padding * 2;
realRect.origin[_originComponent] -= padding;
@@ -260,35 +206,6 @@ var CPSplitViewHorizontalImage = nil,
}
}
/*!
@ignore
Because we're use drawRect: to draw the dividers, but use DOM elements instead of CoreGraphics
We must remove those DOM elements (the splitters) when the subview is removed.
*/
- (void)willRemoveSubview:(CPView)aView
{
#if PLATFORM(DOM)
var dividerToRemove = _DOMDividerElements.pop();
// The divider may not exist if we never rendered out the DOM.
if (dividerToRemove)
CPDOMDisplayServerRemoveChild(_DOMElement, dividerToRemove);
#endif
_needsResizeSubviews = YES;
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
- (void)layoutSubviews
{
[self _adjustSubviewsWithCalculatedSize]
}
/*!
Draws the divider at a given rect.
@param aRect - the rect of the divider to draw.
*/
- (void)drawDividerInRect:(CGRect)aRect
{
#if PLATFORM(DOM)
@@ -312,13 +229,13 @@ var CPSplitViewHorizontalImage = nil,
{
if (_isPaneSplitter)
{
_DOMDividerElements[_drawingDivider].style.backgroundColor = "";
_DOMDividerElements[_drawingDivider].style.backgroundImage = "url('"+_dividerImagePath+"')";
_DOMDividerElements[_drawingDivider].style.backgroundColor = "#A5A5A5";
_DOMDividerElements[_drawingDivider].style.backgroundImage = "";
}
else
{
_DOMDividerElements[_drawingDivider].style.backgroundColor = [[self currentValueForThemeAttribute:@"pane-divider-color"] cssString];
_DOMDividerElements[_drawingDivider].style.backgroundImage = "";
_DOMDividerElements[_drawingDivider].style.backgroundColor = "";
_DOMDividerElements[_drawingDivider].style.backgroundImage = "url('"+_dividerImagePath+"')";
}
}
@@ -376,7 +293,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));
}
@@ -386,9 +303,9 @@ var CPSplitViewHorizontalImage = nil,
if ([self isHidden] || ![self hitTests] || !CGRectContainsPoint([self frame], aPoint))
return nil;
var point = [self convertPoint:aPoint fromView:[self superview]],
count = [_subviews count] - 1;
var point = [self convertPoint:aPoint fromView:[self superview]];
var count = [_subviews count] - 1;
for (var i = 0; i < count; i++)
{
if ([self cursorAtPoint:point hitDividerAtIndex:i])
@@ -441,14 +358,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:_preCollapsePosition ? _preCollapsePosition : (minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i];
[self setPosition:(minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i];
else
[self setPosition:minPosition ofDividerAtIndex:i];
}
else if ([_delegate splitView:self canCollapseSubview:_subviews[i + 1]] && [_delegate splitView:self shouldCollapseSubview:_subviews[i + 1] forDoubleClickOnDividerAtIndex:i])
else if ([_delegate splitView:self canCollapseSubview:_subviews[i+1]] && [_delegate splitView:self shouldCollapseSubview:_subviews[i+1] forDoubleClickOnDividerAtIndex:i])
{
if ([self isSubviewCollapsed:_subviews[i + 1]])
[self setPosition:_preCollapsePosition ? _preCollapsePosition : (minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i];
if ([self isSubviewCollapsed:_subviews[i+1]])
[self setPosition:(minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i];
else
[self setPosition:maxPosition ofDividerAtIndex:i];
}
@@ -527,19 +444,11 @@ var CPSplitViewHorizontalImage = nil,
if (_currentDivider === i || (_currentDivider == CPNotFound && [self cursorAtPoint:point hitDividerAtIndex:i]))
{
var frame = [_subviews[i] frame],
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,
startPosition = frame.origin[_originComponent] + frame.size[_sizeComponent],
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)
@@ -561,11 +470,6 @@ var CPSplitViewHorizontalImage = nil,
[[CPCursor arrowCursor] set];
}
/*!
Returns the maximum possible position of a divider at a given index.
@param the index of the divider.
@return float - the max possible position.
*/
- (float)maxPossiblePositionOfDividerAtIndex:(int)dividerIndex
{
var frame = [_subviews[dividerIndex + 1] frame];
@@ -576,11 +480,6 @@ var CPSplitViewHorizontalImage = nil,
return [self frame].size[_sizeComponent] - [self dividerThickness];
}
/*!
Returns the minimum possible position of a divider at a given index.
@param the index of the divider.
@return float - the min possible position.
*/
- (float)minPossiblePositionOfDividerAtIndex:(int)dividerIndex
{
if (dividerIndex > 0)
@@ -604,10 +503,10 @@ var CPSplitViewHorizontalImage = nil,
actualMax = proposedMax,
actualMin = proposedMin;
if ([_delegate respondsToSelector:@selector(splitView:constrainMinCoordinate:ofSubviewAt:)])
if([_delegate respondsToSelector:@selector(splitView:constrainMinCoordinate:ofSubviewAt:)])
actualMin = [_delegate splitView:self constrainMinCoordinate:proposedMin ofSubviewAt:dividerIndex];
if ([_delegate respondsToSelector:@selector(splitView:constrainMaxCoordinate:ofSubviewAt:)])
if([_delegate respondsToSelector:@selector(splitView:constrainMaxCoordinate:ofSubviewAt:)])
actualMax = [_delegate splitView:self constrainMaxCoordinate:proposedMax ofSubviewAt:dividerIndex];
var viewA = _subviews[dividerIndex],
@@ -621,11 +520,6 @@ var CPSplitViewHorizontalImage = nil,
return realPosition;
}
/*!
Sets the position of a divider at a given index.
@param position - The float value of the position to place the divider.
@param dividerIndex - The index of the divider to position.
*/
- (void)setPosition:(float)position ofDividerAtIndex:(int)dividerIndex
{
[self _adjustSubviewsWithCalculatedSize];
@@ -637,18 +531,10 @@ 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];
@@ -703,8 +589,8 @@ var CPSplitViewHorizontalImage = nil,
var nonSizableSpace = totalSizableSpace ? bounds.size[_sizeComponent] - totalSizableSpace : 0,
remainingFlexibleSpace = bounds.size[_sizeComponent] - oldSize[_sizeComponent],
oldDimension = (oldSize[_sizeComponent] - totalDividers * dividerThickness - nonSizableSpace),
ratio = oldDimension <= 0 ? 0 : (bounds.size[_sizeComponent] - totalDividers * dividerThickness - nonSizableSpace) / oldDimension;
oldDimension = (oldSize[_sizeComponent]- totalDividers*dividerThickness - nonSizableSpace),
ratio = oldDimension <= 0 ? 0 : (bounds.size[_sizeComponent] - totalDividers*dividerThickness - nonSizableSpace) / oldDimension;
for (index = 0; index < count; ++index)
{
@@ -712,20 +598,17 @@ var CPSplitViewHorizontalImage = nil,
viewFrame = CGRectMakeCopy(bounds),
isSizable = isVertical ? [view autoresizingMask] & CPViewWidthSizable : [view autoresizingMask] & CPViewHeightSizable;
if (index + 1 === count)
viewFrame.size[_sizeComponent] = bounds.size[_sizeComponent] - viewFrame.origin[_originComponent];
else if (totalSizableSpace && isSizable && lastSizableIndex === index)
viewFrame.size[_sizeComponent] = MAX(0, ROUND([view frame].size[_sizeComponent] + remainingFlexibleSpace))
else if (isSizable || !totalSizableSpace)
{
viewFrame.size[_sizeComponent] = MAX(0, ROUND(ratio * [view frame].size[_sizeComponent]));
remainingFlexibleSpace -= (viewFrame.size[_sizeComponent] - [view frame].size[_sizeComponent]);
}
else if (totalSizableSpace && !isSizable)
viewFrame.size[_sizeComponent] = [view frame].size[_sizeComponent];
if (index + 1 == count)
viewFrame.size[_sizeComponent] = bounds.size[_sizeComponent] - viewFrame.origin[_originComponent];
else if (totalSizableSpace && isSizable && lastSizableIndex === index)
viewFrame.size[_sizeComponent] = MAX(0, ROUND([view frame].size[_sizeComponent] + remainingFlexibleSpace))
else if (isSizable || !totalSizableSpace)
{
viewFrame.size[_sizeComponent] = MAX(0, ROUND(ratio * [view frame].size[_sizeComponent]));
remainingFlexibleSpace -= (viewFrame.size[_sizeComponent] - [view frame].size[_sizeComponent]);
}
else if (totalSizableSpace && !isSizable)
viewFrame.size[_sizeComponent] = [view frame].size[_sizeComponent];
bounds.origin[_originComponent] += viewFrame.size[_sizeComponent] + dividerThickness;
@@ -735,66 +618,6 @@ var CPSplitViewHorizontalImage = nil,
[self _postNotificationDidResize];
}
/*!
Sets the delegate of the receiver.
Possible delegate methods to implement are listed below.
Notifies the delegate when the subviews have resized.
@code
- (void)splitViewDidResizeSubviews:(CPNotification)aNotification;
@endcode
Notifies the delegate when the subviews will be resized.
@code
- (void)splitViewWillResizeSubviews:(CPNotification)aNotification;
@endcode
Lets the delegate specify a different rect for which the user can drag the splitView divider.
@code
- (CGRect)splitView:(CPSplitView)aSplitView effectiveRect:(CGRect)aRect forDrawnRect:(CGRect)aDrawnRect ofDividerAtIndex:(int)aDividerIndex;
@endcode
Lets the delegate specify an additional rect for which the user can drag the splitview divider.
@code
- (CGRect)splitView:(CPSplitView)aSplitView additionalEffectiveRectOfDividerAtIndex:(int)indexOfDivider;
@endcode
Notifies the delegate that the splitview is about to be collapsed. This usually happens when the user
Double clicks on the divider. Return YES if the subview can be collapsed, otherwise NO.
@code
- (BOOL)splitView:(CPSplitView)aSplitView canCollapseSubview:(CPView)aSubview;
@endcode
Notifies the delegate that the subview at indexOfDivider is about to be collapsed. This usually happens when the user
Double clicks on the divider. Return YES if the subview should be collapsed, otherwise NO.
@code
- (BOOL)splitView:(CPSplitView)aSplitView shouldCollapseSubview:(CPView)aSubview forDoubleClickOnDividerAtIndex:(int)indexOfDivider;
@endcode
Allows the delegate to constrain the subview beings resized. This method is called continuously as the user resizes the divider.
For example if the subview needs to have a width which is a multiple of a certain number you could return that multiple with this method.
@code
- (float)splitView:(CPSplitView)aSpiltView constrainSplitPosition:(float)proposedPosition ofSubviewAt:(int)subviewIndex;
@endcode
Allows the delegate to constrain the minimum position of a subview.
@code
- (float)splitView:(CPSplitView)aSplitView constrainMinCoordinate:(float)proposedMin ofSubviewAt:(int)subviewIndex;
@endcode
Allows the delegate to constrain the maximum position of a subview.
@code
- (float)splitView:(CPSplitView)aSplitView constrainMaxCoordinate:(float)proposedMax ofSubviewAt:(int)subviewIndex;
@endcode
Allows the splitview to specify a custom resizing behavior. This is called when the splitview is resized.
The sum of the views and the sum of the dividers should be equal to the size of the splitview.
@code
- (void)splitView:(CPSplitView)aSplitView resizeSubviewsWithOldSize:(CGSize)oldSize;
@endcode
@param delegate - The delegate of the splitview.
*/
- (void)setDelegate:(id)delegate
{
if ([_delegate respondsToSelector:@selector(splitViewDidResizeSubviews:)])
@@ -818,18 +641,15 @@ The sum of the views and the sum of the dividers should be equal to the size of
/*!
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.
@param CPButtonBar - The supplied button bar.
@param unsigned int - The divider index the button bar will be assigned to.
*/
- (void)setButtonBar:(CPButtonBar)aButtonBar forDividerAtIndex:(unsigned)dividerIndex
{
@@ -849,7 +669,7 @@ The sum of the views and the sum of the dividers should be equal to the size of
}
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];
@@ -857,7 +677,7 @@ The sum of the views and the sum of the dividers should be equal to the size of
[aButtonBar setHasResizeControl:YES];
[aButtonBar setResizeControlIsLeftAligned:dividerIndex < viewIndex];
_buttonBars[dividerIndex] = aButtonBar;
_buttonBars[dividerIndex] = aButtonBar;
}
- (void)_postNotificationWillResize
@@ -894,8 +714,8 @@ var CPSplitViewDelegateKey = "CPSplitViewDelegateKey",
_DOMDividerElements = [];
_buttonBars = [aCoder decodeObjectForKey:CPSplitViewButtonBarsKey] || [];
[self setDelegate:[aCoder decodeObjectForKey:CPSplitViewDelegateKey]];
_delegate = [aCoder decodeObjectForKey:CPSplitViewDelegateKey];
_isPaneSplitter = [aCoder decodeBoolForKey:CPSplitViewIsPaneSplitterKey];
[self _setVertical:[aCoder decodeBoolForKey:CPSplitViewIsVerticalKey]];
-246
View File
@@ -1,246 +0,0 @@
/*
* CPStepper.j
* AppKit
*
* Created by Antoine Mercadal
* Copyright 2009, Antoine Mercadal
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <AppKit/CPControl.j>
@import <AppKit/CPButton.j>
@import <AppKit/CPTextField.j>
var CPStepperButtonsSize = CPSizeMake(19, 13);
/*! CPStepper is an implementation of Cocoa NSStepper.
This control display a two part button that can be used to increase or decrease a value with a given interval.
*/
@implementation CPStepper: CPControl
{
BOOL _valueWraps @accessors(property=valueWraps);
int _increment @accessors(property=increment);
int _maxValue @accessors(property=maxValue);
int _minValue @accessors(property=minValue);
CPButton _buttonDown;
CPButton _buttonUp;
}
#pragma mark -
#pragma mark Initialization
/*! Initializes a CPStepper with given values
@param aValue the initial value of the CPStepper
@param minValue the minimal acceptable value of the stepper
@param maxValue the maximal acceptable value of the stepper
@return Initialized CPStepper
*/
+ (CPStepper)stepperWithInitialValue:(float)aValue minValue:(float)aMinValue maxValue:(float)aMaxValue
{
var stepper = [[CPStepper alloc] initWithFrame:CPRectMake(0, 0, 19, 25)];
[stepper setDoubleValue:aValue];
[stepper setMinValue:aMinValue];
[stepper setMaxValue:aMaxValue];
return stepper;
}
/*! Initializes a CPStepper with default values:
- minValue = 0.0
- maxValue = 59.0
- value = 0.0
@return Initialized CPStepper
*/
+ (CPStepper)stepper
{
return [CPStepper stepperWithInitialValue:0.0 minValue:0.0 maxValue:59.0];
}
/*! Initializes the CPStepper
@param aFrame the frame of the control
@return initialized CPStepper
*/
- (id)initWithFrame:(CGRect)aFrame
{
if (self = [super initWithFrame:aFrame])
{
_maxValue = 59.0;
_minValue = 0.0;
_increment = 1.0;
_valueWraps = YES;
[self setDoubleValue:0.0];
_buttonUp = [[CPButton alloc] initWithFrame:CPRectMake(aFrame.size.width - CPStepperButtonsSize.width, 0, CPStepperButtonsSize.width, CPStepperButtonsSize.height)];
[_buttonUp setContinuous:YES];
[_buttonUp setTarget:self];
[_buttonUp setAction:@selector(_buttonDidClick:)];
[_buttonUp setAutoresizingMask:CPViewNotSizable];
[self addSubview:_buttonUp];
_buttonDown = [[CPButton alloc] initWithFrame:CPRectMake(aFrame.size.width - CPStepperButtonsSize.width, CPStepperButtonsSize.height, CPStepperButtonsSize.width, CPStepperButtonsSize.height - 1)];
[_buttonDown setContinuous:YES];
[_buttonDown setTarget:self];
[_buttonDown setAction:@selector(_buttonDidClick:)];
[_buttonDown setAutoresizingMask:CPViewNotSizable];
[self addSubview:_buttonDown];
[self setNeedsLayout];
}
return self;
}
#pragma mark -
#pragma mark Superclass overrides
/*! set if the CPStepper is enabled or not
@param shouldEnabled BOOL that define if stepper is enabled or not.
*/
- (void)setEnabled:(BOOL)shouldEnabled
{
[super setEnabled:shouldEnabled];
[_buttonUp setEnabled:shouldEnabled];
[_buttonDown setEnabled:shouldEnabled];
}
/*! set the frame of the CPStepper and check if width is not smaller than theme min-size
@param aFrame the frame
*/
- (void)setFrame:(CGRect)aFrame
{
if (aFrame.size.width >= CGRectGetWidth(aFrame))
[super setFrame:aFrame];
}
/*! @ignore
*/
- (void)layoutSubviews
{
[_buttonUp setValue:[self valueForThemeAttribute:@"bezel-color-up-button" inState:CPThemeStateBordered] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered];
[_buttonUp setValue:[self valueForThemeAttribute:@"bezel-color-up-button" inState:CPThemeStateBordered | CPThemeStateDisabled] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateDisabled];
[_buttonUp setValue:[self valueForThemeAttribute:@"bezel-color-up-button" inState:CPThemeStateBordered | CPThemeStateHighlighted] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateHighlighted];
[_buttonDown setValue:[self valueForThemeAttribute:@"bezel-color-down-button" inState:CPThemeStateBordered] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered];
[_buttonDown setValue:[self valueForThemeAttribute:@"bezel-color-down-button" inState:CPThemeStateBordered | CPThemeStateDisabled] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateDisabled];
[_buttonDown setValue:[self valueForThemeAttribute:@"bezel-color-down-button" inState:CPThemeStateBordered | CPThemeStateHighlighted] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateHighlighted];
}
/*! set if CPStepper should autorepeat
@param shouldAutoRepeat if YES, the first mouse down does one increment (decrement) and, after each delay of 0.5 seconds
*/
- (void)setAutorepeat:(BOOL)shouldAutoRepeat
{
[_buttonUp setContinuous:shouldAutoRepeat];
[_buttonDown setContinuous:shouldAutoRepeat];
}
/*! set the current value of the stepper
@param aValue a float containing the value
*/
- (void)setDoubleValue:(float)aValue
{
if (aValue > _maxValue)
[super setDoubleValue:_valueWraps ? _minValue : _maxValue];
else if (aValue < _minValue)
[super setDoubleValue:_valueWraps ? _maxValue : _minValue];
else
[super setDoubleValue:aValue];
}
#pragma mark -
#pragma mark Actions
/*! @ignore
*/
- (IBAction)_buttonDidClick:(id)aSender
{
if (![self isEnabled])
return;
if (aSender == _buttonUp)
[self setDoubleValue:([self doubleValue] + _increment)];
else
[self setDoubleValue:([self doubleValue] - _increment)];
if (_target && _action && [_target respondsToSelector:_action])
[self sendAction:_action to:_target];
}
/*! @perform a programatic click on up button
@param aSender sender of the action
*/
- (IBAction)performClickUp:(id)aSender
{
[_buttonUp performClick:aSender];
}
/*! @perform a programatic click on down button
@param aSender sender of the action
*/
- (IBAction)performClickDown:(id)aSender
{
[_buttonDown performClick:aSender];
}
#pragma mark -
#pragma mark Theming
+ (CPString)defaultThemeClass
{
return @"stepper";
}
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[[CPNull null], [CPNull null]]
forKeys:[@"bezel-color-up-button", @"bezel-color-down-button"]];
}
@end
@implementation CPStepper (CPCodingCompliance)
- (id)initWithCoder:(CPCoder)aCoder
{
if (self = [super initWithCoder:aCoder])
{
_maxValue = [aCoder decodeObjectForKey:@"_maxValue"];
_minValue = [aCoder decodeObjectForKey:@"_minValue"];
_increment = [aCoder decodeObjectForKey:@"_increment"];
_buttonUp = [aCoder decodeObjectForKey:@"_buttonUp"];
_buttonDown = [aCoder decodeObjectForKey:@"_buttonDown"];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:_maxValue forKey:@"_maxValue"];
[aCoder encodeObject:_minValue forKey:@"_minValue"];
[aCoder encodeObject:_increment forKey:@"_increment"];
[aCoder encodeObject:_buttonUp forKey:@"_buttonUp"];
[aCoder encodeObject:_buttonDown forKey:@"_buttonDown"];
}
@end
+1 -25
View File
@@ -25,20 +25,8 @@
@import "CPPlatformString.j"
var CPStringSizeWithFontInWidthCache = {};
CPStringSizeCachingEnabled = YES;
@implementation CPString (CPStringDrawing)
/*!
Returns a dictionary with the items "ascender", "descender", "lineHeight"
*/
+ (CPDictionary)metricsOfFont:(CPFont)aFont
{
return [CPPlatformString metricsOfFont:aFont];
}
/*!
Returns the string
*/
@@ -54,19 +42,7 @@ CPStringSizeCachingEnabled = YES;
- (CGSize)sizeWithFont:(CPFont)aFont inWidth:(float)aWidth
{
if (!CPStringSizeCachingEnabled)
return [CPPlatformString sizeOfString:self withFont:aFont forWidth:aWidth];
var cacheKey = self + [aFont cssString] + aWidth,
size = CPStringSizeWithFontInWidthCache[cacheKey];
if (size === undefined)
{
size = [CPPlatformString sizeOfString:self withFont:aFont forWidth:aWidth];
CPStringSizeWithFontInWidthCache[cacheKey] = size;
}
return CGSizeMakeCopy(size);
return [CPPlatformString sizeOfString:self withFont:aFont forWidth:aWidth];
}
@end
+555 -255
View File
File diff suppressed because it is too large Load Diff
+13 -13
View File
@@ -22,7 +22,7 @@
@import <Foundation/CPObject.j>
@import "CPView.j"
@import <AppKit/CPView.j>
/*
@@ -44,7 +44,7 @@ CPBackgroundTab = 1;
*/
CPPressedTab = 2;
/*!
/*!
@ingroup appkit
@class CPTabViewItem
@@ -55,10 +55,10 @@ CPPressedTab = 2;
{
id _identifier;
CPString _label;
CPView _view;
CPView _auxiliaryView;
CPTabView _tabView;
}
@@ -74,10 +74,10 @@ CPPressedTab = 2;
- (id)initWithIdentifier:(id)anIdentifier
{
self = [super init];
if (self)
_identifier = anIdentifier;
return self;
}
@@ -145,8 +145,8 @@ CPPressedTab = 2;
// Assigning an Auxiliary View
/*!
Sets the tab's auxiliary view.
@param anAuxiliaryView the new auxiliary view
Sets the tab's auxillary view.
@param anAuxillaryView the new auxillary view
*/
- (void)setAuxiliaryView:(CPView)anAuxiliaryView
{
@@ -154,7 +154,7 @@ CPPressedTab = 2;
}
/*!
Returns the tab's auxiliary view
Returns the tab's auxillary view
*/
- (CPView)auxiliaryView
{
@@ -191,16 +191,16 @@ var CPTabViewItemIdentifierKey = "CPTabViewItemIdentifierKey",
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
if (self)
{
_identifier = [aCoder decodeObjectForKey:CPTabViewItemIdentifierKey];
_label = [aCoder decodeObjectForKey:CPTabViewItemLabelKey];
_view = [aCoder decodeObjectForKey:CPTabViewItemViewKey];
_auxiliaryView = [aCoder decodeObjectForKey:CPTabViewItemAuxViewKey];
}
return self;
}
@@ -208,7 +208,7 @@ var CPTabViewItemIdentifierKey = "CPTabViewItemIdentifierKey",
{
[aCoder encodeObject:_identifier forKey:CPTabViewItemIdentifierKey];
[aCoder encodeObject:_label forKey:CPTabViewItemLabelKey];
[aCoder encodeObject:_view forKey:CPTabViewItemViewKey];
[aCoder encodeObject:_auxiliaryView forKey:CPTabViewItemAuxViewKey];
}
+56 -386
View File
@@ -22,28 +22,17 @@
@import <Foundation/CPDictionary.j>
@import <Foundation/CPObject.j>
@import <Foundation/CPIndexSet.j>
@import <Foundation/CPSortDescriptor.j>
@import <Foundation/CPString.j>
@import "CPTableHeaderView.j"
#include "CoreGraphics/CGGeometry.h"
CPTableColumnNoResizing = 0;
CPTableColumnAutoresizingMask = 1 << 0;
CPTableColumnUserResizingMask = 1 << 1;
/*!
@class CPTableColumn
A CPTableColumn contains a dataview to display for its column of the CPTableView.
A CPTableColumn determines its own size constrains and resizing behavior.
The default dataview is a CPTextField but you can set it to any view you'd like. See -setDataView: for documentation including theme states.
To customize the text of the column header you can simply call setStringValue: on the headerview of a table column.
For example: [[myTableColumn headerView] setStringValue:"My Title"];
*/
@implementation CPTableColumn : CPObject
{
CPTableView _tableView;
@@ -61,22 +50,15 @@ CPTableColumnUserResizingMask = 1 << 1;
CPSortDescriptor _sortDescriptorPrototype;
BOOL _isHidden;
CPString _headerToolTip;
BOOL _disableResizingPosting @accessors(property=disableResizingPosting);
}
/*!
@ignore
*/
- (id)init
{
return [self initWithIdentifier:@""];
}
/*!
Initializes a newly created CPTableColumn with a given identifier.
*/
- (id)initWithIdentifier:(id)anIdentifier
{
self = [super init];
@@ -90,62 +72,35 @@ CPTableColumnUserResizingMask = 1 << 1;
_maxWidth = 1000000.0;
_resizingMask = CPTableColumnAutoresizingMask | CPTableColumnUserResizingMask;
_disableResizingPosting = NO;
[self setIdentifier:anIdentifier];
var header = [[_CPTableColumnHeaderView alloc] initWithFrame:CGRectMakeZero()];
[self setHeaderView:header];
[self setDataView:[CPTextField new]];
var textDataView = [CPTextField new];
[textDataView setLineBreakMode:CPLineBreakByTruncatingTail];
[textDataView setValue:[CPColor colorWithHexString:@"333333"] forThemeAttribute:@"text-color"];
[textDataView setValue:[CPColor whiteColor] forThemeAttribute:@"text-color" inState:CPThemeStateSelected];
[textDataView setValue:[CPFont boldSystemFontOfSize:12] forThemeAttribute:@"font" inState:CPThemeStateSelected];
[textDataView setValue:CPCenterVerticalTextAlignment forThemeAttribute:@"vertical-alignment"];
[self setDataView:textDataView];
}
return self;
}
/*!
Set the columns's parent tableview
*/
- (void)setTableView:(CPTableView)aTableView
{
_tableView = aTableView;
}
/*!
Return the column's parent tableview
*/
- (CPTableView)tableView
{
return _tableView;
}
/*!
@ignore
this method tries to resize a column called via the tableview via autoresizing
it returns the delta from the actual resize and the proposed resize
for example if the column should have been resized 50px but the maxWidth was hit only
after 25px then the return value would be 25px;
if no edge has been hit zero will be returned
*/
- (int)_tryToResizeToWidth:(int)width
{
var min = [self minWidth],
max = [self maxWidth],
newWidth = MIN(MAX(width, min), max);
[self setWidth:newWidth];
return newWidth - width;
}
/*!
Set the width of the column
Default value is: 100
If the value is greater than the maxWidth the maxWidth will be reset with the supplied width here
If the value is less than the minWidth the minWidth will be reset with the supplied width.
*/
- (void)setWidth:(float)aWidth
{
aWidth = +aWidth;
@@ -168,36 +123,29 @@ CPTableColumnUserResizingMask = 1 << 1;
{
var index = [[tableView tableColumns] indexOfObjectIdenticalTo:self],
dirtyTableColumnRangeIndex = tableView._dirtyTableColumnRangeIndex;
if (dirtyTableColumnRangeIndex < 0)
tableView._dirtyTableColumnRangeIndex = index;
else
tableView._dirtyTableColumnRangeIndex = MIN(index, tableView._dirtyTableColumnRangeIndex);
var rows = tableView._exposedRows,
columns = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(index, [tableView._exposedColumns lastIndex] - index + 1)];
columns = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(index, [tableView._exposedColumns lastIndex] - index + 1)];
// FIXME: Would be faster with some sort of -setNeedsDisplayInColumns: that updates a dirtyTableColumnForDisplay cache; then marked columns would relayout their data views at display time.
[tableView _layoutDataViewsInRows:rows columns:columns];
[tableView tile];
if (!_disableResizingPosting)
[self _postDidResizeNotificationWithOldWidth:oldWidth];
}
}
/*!
Returns the column's width
*/
- (float)width
{
return _width;
}
/*!
Sets the minimum width of the column.
Default value is 10.
*/
- (void)setMinWidth:(float)aMinWidth
{
aMinWidth = +aMinWidth;
@@ -214,18 +162,11 @@ CPTableColumnUserResizingMask = 1 << 1;
[self setWidth:newWidth];
}
/*!
Returns the minimum width of the column.
*/
- (float)minWidth
{
return _minWidth;
}
/*!
Sets the maximum width of the table column.
Default value is: 1000000
*/
- (void)setMaxWidth:(float)aMaxWidth
{
aMaxWidth = +aMaxWidth;
@@ -242,42 +183,21 @@ CPTableColumnUserResizingMask = 1 << 1;
[self setWidth:newWidth];
}
/*!
Returns the maximum width of the column
*/
- (float)maxWidth
{
return _maxWidth;
}
/*!
<pre>
Set the resizing mask of the column.
By default the column can be resized automatically with the tableview and manually by the user
Possible masking values are:
CPTableColumnNoResizing
CPTableColumnAutoresizingMask
CPTableColumnUserResizingMask
</pre>
*/
- (void)setResizingMask:(unsigned)aResizingMask
{
_resizingMask = aResizingMask;
}
/*!
Returns the resizing mask of the column
*/
- (unsigned)resizingMask
{
return _resizingMask;
}
/*!
Sizes the column to fix the column header text.
*/
- (void)sizeToFit
{
var width = _CGRectGetWidth([_headerView frame]);
@@ -291,16 +211,7 @@ CPTableColumnUserResizingMask = 1 << 1;
[self setWidth:width];
}
/*!
Sets the header view for the column.
The headerview handles the display of sort indicators, text, etc.
If you do not want a headerview for you table you should call setHeaderView: on your CPTableView instance.
Passing nil here will throw an exception.
In order to customize the text of the column header see - (CPView)headerView;
*/
//Setting Component Cells
- (void)setHeaderView:(CPView)aView
{
if (!aView)
@@ -314,88 +225,35 @@ CPTableColumnUserResizingMask = 1 << 1;
[tableHeaderView setNeedsDisplay:YES];
}
/*!
Returns the headerview for the column.
In order to change the text of the headerview for a column you should call setStringValue: on the headerview.
For example: [[myTableColumn headerView] setStringValue:"My Column"];
*/
- (CPView)headerView
{
return _headerView;
}
/*!
This method sets 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
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
individual cell that is shown. As a result, changes made after calling this method won't be reflected.
Example:
@code
[tableColumn setDataView:someView]; // snapshot taken
[[tableColumn dataView] setSomething:x]; //won't work
@endcode
[tableColumn setDataView:someView]; // snapshot taken
[[tableColumn dataView] setSomething:x]; //won't work
This doesn't work because the snapshot is taken before the new property is applied. Instead, do:
@code
[someView setSomething:x];
[tableColumn setDataView:someView];
@endcode
@note You should implement CPKeyedArchiving otherwise you might see unexpected results.
This is done by adding the following methods to your class:
@endnote
@code
- (id)initWithCoder(CPCoder)aCoder;
- (void)encodeWithCoder:(CPCoder)aCoder;
@endcode
Example:
Say you have two instance variables in your object that need to be set up each time an object is create.
We will call these instance variables "image" and "text".
Your CPCoding methods will look like the following:
@code
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
image = [aCoder decodeObjectForKey:"MyDataViewImage"];
text = [aCoder decodeObjectForKey:"MyDataViewText"];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:image forKey:"MyDataViewImage"];
[aCoder encodeObject:text forKey:"MyDataViewText"];
}
@endcode
@section Theming
When you set a dataview and it is added to the tableview the theme state will be set to \c CPThemeStateTableDataView
When the dataview becomes selected the theme state will be set to \c CPThemeStateSelectedDataView.
If the dataview shows up in a group row of the tableview the theme state will be set to \c CPThemeStateGroupRow.
You should overide \c setThemeState: and \c unsetThemeState: to handle these theme state changes in your dataview.
[someView setSomething:x];
[tableColumn setDataView:someView];
*/
- (void)setDataView:(CPView)aView
{
if (_dataView === aView)
return;
if (_dataView)
_dataViewData[[_dataView UID]] = nil;
[aView setThemeState:CPThemeStateTableDataView];
_dataView = aView;
_dataViewData[[aView UID]] = [CPKeyedArchiver archivedDataWithRootObject:aView];
}
@@ -409,7 +267,7 @@ CPTableColumnUserResizingMask = 1 << 1;
Returns the CPView object used by the CPTableView to draw values for the receiver.
By default, this method just calls dataView. Subclassers can override if they need to
potentially use different "cells" or dataViews for different rows. Subclasses should expect this method
potentially use different cells for different rows. Subclasses should expect this method
to be invoked with row equal to -1 in cases where no actual row is involved but the table
view needs to get some generic cell info.
*/
@@ -418,9 +276,6 @@ CPTableColumnUserResizingMask = 1 << 1;
return [self dataView];
}
/*!
@ignore
*/
- (id)_newDataViewForRow:(int)aRowIndex
{
var dataView = [self dataViewForRow:aRowIndex],
@@ -428,7 +283,7 @@ CPTableColumnUserResizingMask = 1 << 1;
var x = [self tableView]._cachedDataViews[dataViewUID];
if (x && x.length)
return x.pop();
return x.pop();
// if we haven't cached an archive of the data view, do it now
if (!_dataViewData[dataViewUID])
@@ -437,16 +292,13 @@ CPTableColumnUserResizingMask = 1 << 1;
// unarchive the data view cache
var newDataView = [CPKeyedUnarchiver unarchiveObjectWithData:_dataViewData[dataViewUID]];
newDataView.identifier = dataViewUID;
// make sure only we have control over the size and placement
[newDataView setAutoresizingMask:CPViewNotSizable];
return newDataView;
}
//Setting the Identifier
/*!
/*
Sets the receiver identifier to anIdentifier.
*/
- (void)setIdentifier:(id)anIdentifier
@@ -454,7 +306,7 @@ CPTableColumnUserResizingMask = 1 << 1;
_identifier = anIdentifier;
}
/*!
/*
Returns the object used by the data source to identify the attribute corresponding to the receiver.
*/
- (id)identifier
@@ -464,7 +316,7 @@ CPTableColumnUserResizingMask = 1 << 1;
//Controlling Editability
/*!
/*
Controls whether the user can edit cells in the receiver by double-clicking them.
*/
- (void)setEditable:(BOOL)shouldBeEditable
@@ -472,50 +324,40 @@ CPTableColumnUserResizingMask = 1 << 1;
_isEditable = shouldBeEditable;
}
/*!
Returns YES if the user can edit cells associated with the receiver by double-clicking the
column in the CPTableView, NO otherwise.
/*
Returns YES if the user can edit cells associated with the receiver by double-clicking the
column in the NSTableView, NO otherwise.
*/
- (BOOL)isEditable
{
return _isEditable;
}
/*!
Sets the sort descriptor prototype for the column.
*/
//Sorting
- (void)setSortDescriptorPrototype:(CPSortDescriptor)aSortDescriptor
{
_sortDescriptorPrototype = aSortDescriptor;
}
/*!
Returns the sort descriptor prototype for the column.
*/
- (CPSortDescriptor)sortDescriptorPrototype
{
return _sortDescriptorPrototype;
}
/*!
If NO the tablecolumn will no longer be visible in the tableview
If YES the tablecolumn will be visible in the tableview.
*/
//Setting Column Visibility
- (void)setHidden:(BOOL)shouldBeHidden
{
shouldBeHidden = !!shouldBeHidden
if (_isHidden === shouldBeHidden)
return;
_isHidden = shouldBeHidden;
[[self headerView] setHidden:shouldBeHidden];
[[self tableView] _tableColumnVisibilityDidChange:self];
}
/*!
Returns the visibility status of the column.
*/
- (BOOL)isHidden
{
return _isHidden;
@@ -523,8 +365,8 @@ CPTableColumnUserResizingMask = 1 << 1;
//Setting Tool Tips
/*!
Sets the tooltip string that is displayed when the cursor pauses over the
/*
Sets the tooltip string that is displayed when the cursor pauses over the
header cell of the receiver.
*/
- (void)setHeaderToolTip:(CPString)aToolTip
@@ -532,21 +374,13 @@ CPTableColumnUserResizingMask = 1 << 1;
_headerToolTip = aToolTip;
}
/*!
Returns the tooltip for the column header
*/
- (CPString)headerToolTip
{
return _headerToolTip;
}
/*!
@ignore
*/
- (void)_postDidResizeNotificationWithOldWidth:(float)oldWidth
{
[[self tableView] _didResizeTableColumn:self];
[[CPNotificationCenter defaultCenter]
postNotificationName:CPTableViewColumnDidResizeNotification
object:[self tableView]
@@ -555,155 +389,16 @@ CPTableColumnUserResizingMask = 1 << 1;
@end
@implementation CPTableColumnValueBinder : CPBinder
{
}
- (void)setValueFor:(CPString)aBinding
{
var tableView = [_source tableView],
column = [[tableView tableColumns] indexOfObjectIdenticalTo:_source],
rowIndexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [tableView numberOfRows])],
columnIndexes = [CPIndexSet indexSetWithIndex:column];
[tableView reloadDataForRowIndexes:rowIndexes columnIndexes:columnIndexes];
}
@end
@implementation CPTableColumn (Bindings)
+ (id)_binderClassForBinding:(CPString)aBinding
{
if (aBinding == CPValueBinding)
return [CPTableColumnValueBinder class];
return [super _binderClassForBinding:aBinding];
}
/*!
Binds the receiver to an object.
@param CPString aBinding - The binding you wish to make. Typically CPValueBinding.
@param id anObject - The object to bind the receiver to.
@param CPString aKeyPath - The key path you wish to bind the receiver to.
@param CPDictionary options - A dictionary of options for the binding. This parameter is optional, pass nil if you do not wish to use it.
*/
- (void)bind:(CPString)aBinding toObject:(id)anObject withKeyPath:(CPString)aKeyPath options:(CPDictionary)options
{
[super bind:aBinding toObject:anObject withKeyPath:aKeyPath options:options];
if (![aBinding isEqual:@"someListOfExceptedBindings(notAcceptedBindings)"])
[[self tableView] _establishBindingsIfUnbound:anObject];
}
/*!
@ignore
*/
- (void)_prepareDataView:(CPView)aDataView forRow:(unsigned)aRow
{
var bindingsDictionary = [CPBinder allBindingsForObject:self],
keys = [bindingsDictionary allKeys];
for (var i = 0, count = [keys count]; i < count; i++)
{
var bindingName = keys[i],
bindingPath = [aDataView _replacementKeyPathForBinding:bindingName],
binding = [bindingsDictionary objectForKey:bindingName],
bindingInfo = binding._info,
destination = [bindingInfo objectForKey:CPObservedObjectKey],
keyPath = [bindingInfo objectForKey:CPObservedKeyPathKey],
dotIndex = keyPath.lastIndexOf("."),
value;
if (dotIndex === CPNotFound)
value = [[destination valueForKeyPath:keyPath] objectAtIndex:aRow];
else
{
/*
Optimize the prototypical use case where the key path describes a value
in an array. Without this optimization, we call CPArray's valueForKey
which generates as many values as objects in the array, of which we then
pick one and throw away the rest.
The optimization is to get the array and access the value directly. This
turns the operation into a single access regardless of how long the model
array is.
*/
var firstPart = keyPath.substring(0, dotIndex),
secondPart = keyPath.substring(dotIndex + 1),
firstValue = [destination valueForKeyPath:firstPart];
if ([firstValue isKindOfClass:CPArray])
value = [[firstValue objectAtIndex:aRow] valueForKeyPath:secondPart];
else
value = [[firstValue valueForKeyPath:secondPart] objectAtIndex:aRow];
}
value = [binding transformValue:value withOptions:[bindingInfo objectForKey:CPOptionsKey]];
[aDataView setValue:value forKey:@"objectValue"];
}
}
/*!
@ignore
*/
- (void)_reverseSetDataView:(CPView)aDataView forRow:(unsigned)aRow
{
var bindingsDictionary = [CPBinder allBindingsForObject:self],
keys = [bindingsDictionary allKeys],
newValue = [aDataView valueForKey:@"objectValue"];
for (var i = 0, count = [keys count]; i < count; i++)
{
var bindingName = keys[i],
bindingPath = [aDataView _replacementKeyPathForBinding:bindingName],
binding = [bindingsDictionary objectForKey:bindingName],
bindingInfo = binding._info,
destination = [bindingInfo objectForKey:CPObservedObjectKey],
keyPath = [bindingInfo objectForKey:CPObservedKeyPathKey],
dotIndex = keyPath.lastIndexOf(".");
if (dotIndex === CPNotFound)
[[destination valueForKeyPath:keyPath] replaceObjectAtIndex:aRow withObject:newValue];
else
{
var firstPart = keyPath.substring(0, dotIndex),
secondPart = keyPath.substring(dotIndex + 1),
firstValue = [destination valueForKeyPath:firstPart];
if ([firstValue isKindOfClass:CPArray])
[[firstValue objectAtIndex:aRow] setValue:newValue forKeyPath:secondPart];
else
[[firstValue valueForKeyPath:secondPart] replaceObjectAtIndex:aRow withObject:newValue];
}
}
}
//- (void)objectValue
//{
// return nil;
//}
@end
var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
CPTableColumnHeaderViewKey = @"CPTableColumnHeaderViewKey",
CPTableColumnDataViewKey = @"CPTableColumnDataViewKey",
CPTableColumnWidthKey = @"CPTableColumnWidthKey",
CPTableColumnMinWidthKey = @"CPTableColumnMinWidthKey",
CPTableColumnMaxWidthKey = @"CPTableColumnMaxWidthKey",
CPTableColumnResizingMaskKey = @"CPTableColumnResizingMaskKey",
CPTableColumnIsHiddenKey = @"CPTableColumnIsHiddenKey",
CPSortDescriptorPrototypeKey = @"CPSortDescriptorPrototypeKey",
CPTableColumnIsEditableKey = @"CPTableColumnIsEditableKey";
CPTableColumnResizingMaskKey = @"CPTableColumnResizingMaskKey";
@implementation CPTableColumn (CPCoding)
/*!
@ignore
*/
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
@@ -721,83 +416,58 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
[self setDataView:[aCoder decodeObjectForKey:CPTableColumnDataViewKey]];
[self setHeaderView:[aCoder decodeObjectForKey:CPTableColumnHeaderViewKey]];
_resizingMask = [aCoder decodeIntForKey:CPTableColumnResizingMaskKey];
_isHidden = [aCoder decodeBoolForKey:CPTableColumnIsHiddenKey];
_isEditable = [aCoder decodeBoolForKey:CPTableColumnIsEditableKey];
_sortDescriptorPrototype = [aCoder decodeObjectForKey:CPSortDescriptorPrototypeKey];
_resizingMask = [aCoder decodeBoolForKey:CPTableColumnResizingMaskKey];
}
return self;
}
/*!
@ignore
*/
- (void)encodeWithCoder:(CPCoder)aCoder
{
[aCoder encodeObject:_identifier forKey:CPTableColumnIdentifierKey];
[aCoder encodeFloat:_width forKey:CPTableColumnWidthKey];
[aCoder encodeFloat:_minWidth forKey:CPTableColumnMinWidthKey];
[aCoder encodeFloat:_maxWidth forKey:CPTableColumnMaxWidthKey];
[aCoder encodeObject:_width forKey:CPTableColumnWidthKey];
[aCoder encodeObject:_minWidth forKey:CPTableColumnMinWidthKey];
[aCoder encodeObject:_maxWidth forKey:CPTableColumnMaxWidthKey];
[aCoder encodeObject:_headerView forKey:CPTableColumnHeaderViewKey];
[aCoder encodeObject:_dataView forKey:CPTableColumnDataViewKey];
[aCoder encodeObject:_resizingMask forKey:CPTableColumnResizingMaskKey];
[aCoder encodeBool:_isHidden forKey:CPTableColumnIsHiddenKey];
[aCoder encodeBool:_isEditable forKey:CPTableColumnIsEditableKey];
[aCoder encodeObject:_sortDescriptorPrototype forKey:CPSortDescriptorPrototypeKey];
}
@end
@implementation CPTableColumn (NSInCompatibility)
/*!
@ignore
*/
- (void)setHeaderCell:(CPView)aView
{
[CPException raise:CPUnsupportedMethodException
reason:@"setHeaderCell: is not supported. Use -setHeaderView:aView instead."];
reason:@"setHeaderCell: is not supported. -setHeaderCell:aView instead."];
}
/*!
@ignore
*/
- (CPView)headerCell
{
[CPException raise:CPUnsupportedMethodException
reason:@"headCell is not supported. Use -headerView instead."];
reason:@"headCell is not supported. -headerView instead."];
}
/*!
@ignore
*/
- (void)setDataCell:(CPView)aView
{
[CPException raise:CPUnsupportedMethodException
reason:@"setDataCell: is not supported. Use -setDataView:aView instead."];
reason:@"setDataCell: is not supported. Use -setHeaderCell:aView instead."];
}
/*!
@ignore
*/
- (CPView)dataCell
{
[CPException raise:CPUnsupportedMethodException
reason:@"dataCell is not supported. Use -dataView instead."];
reason:@"dataCell is not supported. Use -dataCell instead."];
}
/*!
@ignore
*/
- (id)dataCellForRow:(int)row
{
[CPException raise:CPUnsupportedMethodException
reason:@"dataCellForRow: is not supported. Use -dataViewForRow:row instead."];
}
@end
@end
+104 -144
View File
@@ -20,64 +20,54 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPIndexSet.j>
@import "CPTableColumn.j"
@import "CPTableView.j"
@import "CPView.j"
@implementation _CPTableColumnHeaderView : CPView
{
_CPImageAndTextView _textField;
}
+ (CPString)defaultThemeClass
{
return @"columnHeader";
}
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[[CPNull null], [CPNull null], CGInsetMakeZero(), [CPNull null], [CPNull null], [CPNull null], CGSizeMakeZero()]
forKeys:[@"background-color", @"text-alignment", @"text-inset", @"text-color", @"text-font", @"text-shadow-color", @"text-shadow-offset"]];
}
- (void)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
[self _init];
}
return self;
}
- (void)_init
{
_textField = [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
[_textField setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
_textField = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(5, 1, CGRectGetWidth([self bounds]) - 10, CGRectGetHeight([self bounds]) - 1)];
[_textField setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
[_textField setLineBreakMode:CPLineBreakByTruncatingTail];
[_textField setTextColor: [CPColor colorWithHexString: @"333333"]];
[_textField setFont:[CPFont boldSystemFontOfSize:12.0]];
[_textField setAlignment:CPLeftTextAlignment];
[_textField setVerticalAlignment:CPCenterVerticalTextAlignment];
[_textField setTextShadowColor:[CPColor whiteColor]];
[_textField setTextShadowOffset:CGSizeMake(0,1)];
[self addSubview:_textField];
}
- (void)layoutSubviews
{
[self setBackgroundColor:[self currentValueForThemeAttribute:@"background-color"]];
var themeState = [self themeState];
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"]];
if(themeState & CPThemeStateSelected && themeState & CPThemeStateHighlighted)
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-highlighted-pressed.png", CGSizeMake(1.0, 22.0))]];
else if (themeState & CPThemeStateSelected)
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-highlighted.png", CGSizeMake(1.0, 22.0))]];
else if (themeState & CPThemeStateHighlighted)
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-pressed.png", CGSizeMake(1.0, 22.0))]];
else
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview.png", CGSizeMake(1.0, 22.0))]];
}
- (void)setStringValue:(CPString)string
@@ -102,20 +92,25 @@
- (void)setFont:(CPFont)aFont
{
[self setValue:aFont forThemeAttribute:"text-font"];
[_textField setFont:aFont];
}
- (void)setValue:(id)aValue forThemeAttribute:(id)aKey
{
[_textField setValue:aValue forThemeAttribute:aKey];
}
- (void)_setIndicatorImage:(CPImage)anImage
{
if (anImage)
{
[_textField setImage:anImage];
[_textField setImagePosition:CPImageRight];
}
else
{
[_textField setImagePosition:CPNoImage];
}
if (anImage)
{
[_textField setImage:anImage];
[_textField setImagePosition:CPImageRight];
}
else
{
[_textField setImagePosition:CPNoImage];
}
}
@end
@@ -152,47 +147,34 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
@implementation CPTableHeaderView : CPView
{
CGPoint _mouseDownLocation;
CGPoint _previousTrackingLocation;
CPPoint _mouseDownLocation;
CPPoint _previousTrackingLocation;
int _activeColumn;
int _pressedColumn;
BOOL _isResizing;
BOOL _isDragging;
BOOL _isTrackingColumn;
BOOL _drawsColumnLines;
float _columnOldWidth;
CPTableView _tableView @accessors(property=tableView);
}
+ (CPString)defaultThemeClass
{
return @"tableHeaderRow";
}
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[[CPNull null], [CPColor grayColor]]
forKeys:[@"background-color", @"divider-color"]];
}
- (void)_init
{
_mouseDownLocation = _CGPointMakeZero();
_previousTrackingLocation = _CGPointMakeZero();
_mouseDownLocation = CPPointMakeZero();
_previousTrackingLocation = CPPointMakeZero();
_activeColumn = -1;
_pressedColumn = -1;
_isResizing = NO;
_isDragging = NO;
_isTrackingColumn = NO;
_drawsColumnLines = YES;
_columnOldWidth = 0.0;
[self setBackgroundColor:[self currentValueForThemeAttribute:@"background-color"]];
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview.png", CGSizeMake(1.0, 22.0))]];
}
- (id)initWithFrame:(CGRect)aFrame
@@ -212,36 +194,26 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
- (CGRect)headerRectOfColumn:(int)aColumnIndex
{
var headerRect = CGRectMakeCopy([self bounds]),
var headerRect = [self bounds],
columnRect = [_tableView rectOfColumn:aColumnIndex];
headerRect.origin.x = _CGRectGetMinX(columnRect);
headerRect.size.width = _CGRectGetWidth(columnRect);
headerRect.origin.x = CPRectGetMinX(columnRect);
headerRect.size.width = CPRectGetWidth(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
@@ -250,7 +222,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
{
var headerView = [_tableView._tableColumns[_pressedColumn] headerView];
[headerView unsetThemeState:CPThemeStateHighlighted];
}
}
if (column != -1)
{
@@ -275,7 +247,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
currentLocation.x -= 5.0;
var columnIndex = [self columnAtPoint:currentLocation],
shouldResize = [self shouldResizeTableColumn:columnIndex at:_CGPointMake(currentLocation.x + 5.0, currentLocation.y)];
shouldResize = [self shouldResizeTableColumn:columnIndex at:CPPointMake(currentLocation.x + 5.0, currentLocation.y)];
if (type === CPLeftMouseUp)
{
@@ -319,7 +291,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
[self continueResizingTableColumn:_activeColumn at:currentLocation];
else
{
if (_activeColumn === columnIndex && _CGRectContainsPoint([self headerRectOfColumn:columnIndex], currentLocation))
if (_activeColumn === columnIndex && CPRectContainsPoint([self headerRectOfColumn:columnIndex], currentLocation))
{
if (_isTrackingColumn && _pressedColumn !== -1)
{
@@ -337,24 +309,24 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
[CPApp setTarget:self selector:@selector(trackMouse:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
}
- (void)startTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
- (void)startTrackingTableColumn:(int)aColumnIndex at:(CPPoint)aPoint
{
[self _setPressedColumn:aColumnIndex];
}
- (BOOL)continueTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
- (BOOL)continueTrackingTableColumn:(int)aColumnIndex at:(CPPoint)aPoint
{
if ([self _shouldDragTableColumn:aColumnIndex at:aPoint])
{
var columnRect = [self headerRectOfColumn:aColumnIndex],
offset = _CGPointMakeZero(),
offset = CPPointMakeZero(),
view = [_tableView _dragViewForColumn:aColumnIndex event:[CPApp currentEvent] offset:offset],
viewLocation = _CGPointMakeZero();
viewLocation = CPPointMakeZero();
viewLocation.x = ( _CGRectGetMinX(columnRect) + offset.x ) + ( aPoint.x - _mouseDownLocation.x );
viewLocation.y = _CGRectGetMinY(columnRect) + offset.y;
viewLocation.x = ( CPRectGetMinX(columnRect) + offset.x ) + ( aPoint.x - _mouseDownLocation.x );
viewLocation.y = CPRectGetMinY(columnRect) + offset.y;
[self dragView:view at:viewLocation offset:_CGSizeMakeZero() event:[CPApp currentEvent]
[self dragView:view at:viewLocation offset:CPSizeMakeZero() event:[CPApp currentEvent]
pasteboard:[CPPasteboard pasteboardWithName:CPDragPboard] source:self slideBack:YES];
return NO;
@@ -363,24 +335,24 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
return YES;
}
- (BOOL)_shouldStopTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
- (BOOL)_shouldStopTrackingTableColumn:(int)aColumnIndex at:(CPPoint)aPoint
{
return _isTrackingColumn && _activeColumn === aColumnIndex &&
_CGRectContainsPoint([self headerRectOfColumn:aColumnIndex], aPoint);
return _isTrackingColumn && _activeColumn === aColumnIndex &&
CPRectContainsPoint([self headerRectOfColumn:aColumnIndex], aPoint);
}
- (void)stopTrackingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
- (void)stopTrackingTableColumn:(int)aColumnIndex at:(CPPoint)aPoint
{
[self _setPressedColumn:CPNotFound];
[self _updateResizeCursor:[CPApp currentEvent]];
}
- (BOOL)_shouldDragTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
- (BOOL)_shouldDragTableColumn:(int)aColumnIndex at:(CPPoint)aPoint
{
return [_tableView allowsColumnReordering] && ABS(aPoint.x - _mouseDownLocation.x) >= 10.0;
}
- (CGRect)_headerRectOfLastVisibleColumn
- (CPRect)_headerRectOfLastVisibleColumn
{
var tableColumns = [_tableView tableColumns],
columnIndex = [tableColumns count];
@@ -396,11 +368,11 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
return nil;
}
- (void)_constrainDragView:(CPView)theDragView at:(CGPoint)aPoint
- (void)_constrainDragView:(CPView)theDragView at:(CPPoint)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];
@@ -410,10 +382,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 = _CGRectGetMinY(lastColumnRect);
frame.origin.y = CPRectGetMinY(lastColumnRect);
// Convert the calculated origin back to the window coordinate system
frame.origin = [self convertPoint:frame.origin toView:nil];
@@ -428,21 +400,21 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
[_tableView moveColumn:aFromIndex toColumn:aToIndex];
_activeColumn = aToIndex;
_pressedColumn = _activeColumn;
[_tableView _setDraggedColumn:_activeColumn];
}
- (void)draggedView:(CPView)aView beganAt:(CGPoint)aPoint
- (void)draggedView:(CPView)aView beganAt:(CPPoint)aPoint
{
_isDragging = YES;
var column = [[_tableView tableColumns] objectAtIndex:_activeColumn];
[[column headerView] setHidden:YES];
[_tableView _setDraggedColumn:column];
[[[[_tableView tableColumns] objectAtIndex:_activeColumn] headerView] setHidden:YES];
[_tableView _setDraggedColumn:_activeColumn];
[self setNeedsDisplay:YES];
}
- (void)draggedView:(CPView)aView movedTo:(CGPoint)aPoint
- (void)draggedView:(CPView)aView movedTo:(CPPoint)aPoint
{
[self _constrainDragView:aView at:aPoint];
@@ -452,9 +424,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];
@@ -466,7 +438,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)
@@ -481,14 +453,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:nil];
[_tableView _setDraggedColumn:-1];
[[[[_tableView tableColumns] objectAtIndex:_activeColumn] headerView] setHidden:NO];
[self stopTrackingTableColumn:_activeColumn at:aLocation];
[self setNeedsDisplay:YES];
}
- (BOOL)shouldResizeTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
- (BOOL)shouldResizeTableColumn:(int)aColumnIndex at:(CPPoint)aPoint
{
if (_isResizing)
return YES;
@@ -496,10 +468,10 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
if (_isTrackingColumn)
return NO;
return [_tableView allowsColumnResizing] && _CGRectContainsPoint([self _cursorRectForColumn:aColumnIndex], aPoint);
return [_tableView allowsColumnResizing] && CPRectContainsPoint([self _cursorRectForColumn:aColumnIndex], aPoint);
}
- (void)startResizingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
- (void)startResizingTableColumn:(int)aColumnIndex at:(CPPoint)aPoint
{
_isResizing = YES;
@@ -509,7 +481,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
[_tableView setDisableAutomaticResizing:YES];
}
- (void)continueResizingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
- (void)continueResizingTableColumn:(int)aColumnIndex at:(CPPoint)aPoint
{
var tableColumn = [[_tableView tableColumns] objectAtIndex:aColumnIndex],
newWidth = [tableColumn width] + aPoint.x - _previousTrackingLocation.x;
@@ -529,7 +501,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
}
}
- (void)stopResizingTableColumn:(int)aColumnIndex at:(CGPoint)aPoint
- (void)stopResizingTableColumn:(int)aColumnIndex at:(CPPoint)aPoint
{
var tableColumn = [[_tableView tableColumns] objectAtIndex:aColumnIndex];
[tableColumn _postDidResizeNotificationWithOldWidth:_columnOldWidth];
@@ -548,11 +520,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];
@@ -569,7 +541,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
}
- (void)mouseEntered:(CPEvent)theEvent
{
{
[self _updateResizeCursor:theEvent];
}
@@ -587,33 +559,31 @@ 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],
frame = [self headerRectOfColumn:i];
headerView = [column headerView];
// Make space for the gridline on the right.
frame.origin.x -= 0.5;
frame.size.width -= 1.0;
var frame = [self headerRectOfColumn:i];
frame.size.height -= 0.5;
// Note: we're not adding in intercell spacing here. This setting only affects the regular
// table cell data views, not the header. Verified in Cocoa on March 29th, 2011.
if (i > 0)
{
frame.origin.x += 0.5;
frame.size.width -= 1;
}
[headerView setFrame:frame];
if ([headerView superview] != self)
if([headerView superview] != self)
[self addSubview:headerView];
}
[self setBackgroundColor:[self currentValueForThemeAttribute:@"background-color"]];
}
- (void)drawRect:(CGRect)aRect
{
if (!_tableView || ![self drawsColumnLines])
if (!_tableView)
return;
var context = [[CPGraphicsContext currentContext] graphicsPort],
@@ -625,7 +595,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
exposedRange = CPMakeRange(firstIndex, [exposedTableColumns lastIndex] - firstIndex + 1);
CGContextSetLineWidth(context, 1);
CGContextSetStrokeColor(context, [self currentValueForThemeAttribute:@"divider-color"]);
CGContextSetStrokeColor(context, [_tableView gridColor]);
[exposedColumnIndexes getIndexes:columnsArray maxCount:-1 inIndexRange:exposedRange];
@@ -634,31 +604,31 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
columnMaxX;
CGContextBeginPath(context);
for (; columnArrayIndex < columnArrayCount; columnArrayIndex++)
for(; columnArrayIndex < columnArrayCount; columnArrayIndex++)
{
// grab each column rect and add vertical lines
var columnIndex = columnsArray[columnArrayIndex],
columnToStroke = [self headerRectOfColumn:columnIndex];
columnMaxX = _CGRectGetMaxX(columnToStroke);
columnMaxX = CGRectGetMaxX(columnToStroke);
CGContextMoveToPoint(context, FLOOR(columnMaxX) - 0.5, ROUND(_CGRectGetMinY(columnToStroke)));
CGContextAddLineToPoint(context, FLOOR(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",
CPTableHeaderViewDrawsColumnLines = @"CPTableHeaderViewDrawsColumnLines";
var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey";
@implementation CPTableHeaderView (CPCoding)
@@ -668,15 +638,6 @@ var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey",
{
[self _init];
_tableView = [aCoder decodeObjectForKey:CPTableHeaderViewTableViewKey];
// FIX ME: Take this out before 1.0
if ([aCoder containsValueForKey:CPTableHeaderViewDrawsColumnLines])
_drawsColumnLines = [aCoder decodeBoolForKey:CPTableHeaderViewDrawsColumnLines];
else
{
_drawsColumnLines = YES;
CPLog.warn("The tableview header being decoded is using an old cib. Please run Nib2Cib.");
}
}
return self;
@@ -686,7 +647,6 @@ var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey",
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:_tableView forKey:CPTableHeaderViewTableViewKey];
[aCoder encodeBool:_drawsColumnLines forKey:CPTableHeaderViewDrawsColumnLines];
}
@end
@end
+809 -2304
View File
File diff suppressed because it is too large Load Diff
-30
View File
@@ -1,30 +0,0 @@
/*
* CPText.j
* AppKit
*
* Created by Alexander Ljungberg.
* Copyright 2010, WireLoad, LLC.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
CPEnterCharacter = "\u0003";
CPBackspaceCharacter = "\u0008";
CPTabCharacter = "\u0009";
CPNewlineCharacter = "\u000a";
CPFormFeedCharacter = "\u000c";
CPCarriageReturnCharacter = "\u000d";
CPBackTabCharacter = "\u0019";
CPDeleteCharacter = "\u007f";
+144 -402
View File
@@ -26,6 +26,9 @@
@import "CPCompatibility.j"
@import "_CPImageAndTextView.j"
#include "CoreGraphics/CGGeometry.h"
#include "Platform/Platform.h"
#include "Platform/DOM/CPDOMDisplayServer.h"
CPTextFieldSquareBezel = 0; /*! A textfield bezel with a squared corners. */
CPTextFieldRoundedBezel = 1; /*! A textfield bezel with rounded corners. */
@@ -46,7 +49,7 @@ var CPTextFieldDOMInputElement = nil,
CPTextFieldCachedSelectStartFunction = nil,
CPTextFieldCachedDragFunction = nil,
CPTextFieldBlurFunction = nil;
#endif
var CPSecureTextFieldCharacter = "\u2022";
@@ -77,16 +80,15 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
BOOL _isEditable;
BOOL _isSelectable;
BOOL _isSecure;
BOOL _willBecomeFirstResponderByClick;
BOOL _drawsBackground;
CPColor _textFieldBackgroundColor;
id _placeholderString;
id _delegate;
CPString _textDidChangeValue;
// NS-style Display Properties
@@ -153,19 +155,11 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
return textField;
}
+ (CPString)defaultThemeClass
+ (CPString)themeClass
{
return "textfield";
}
+ (Class)_binderClassForBinding:(CPString)theBinding
{
if (theBinding === CPValueBinding)
return [_CPTextFieldValueBinder class];
return [super _binderClassForBinding:theBinding];
}
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[_CGInsetMakeZero(), _CGInsetMake(2.0, 2.0, 2.0, 2.0), [CPNull null]]
@@ -205,7 +199,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
}
CPTextFieldHandleBlur = function(anEvent)
{
{
CPTextFieldInputOwner = nil;
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
@@ -213,10 +207,10 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
//FIXME make this not onblur
CPTextFieldDOMInputElement.onblur = CPTextFieldBlurFunction;
CPTextFieldDOMStandardInputElement = CPTextFieldDOMInputElement;
}
if (CPFeatureIsCompatible(CPInputTypeCanBeChangedFeature))
{
if ([self isSecure])
@@ -243,14 +237,14 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
CPTextFieldDOMPasswordInputElement.onblur = CPTextFieldBlurFunction;
}
CPTextFieldDOMInputElement = CPTextFieldDOMPasswordInputElement;
}
else
{
CPTextFieldDOMInputElement = CPTextFieldDOMStandardInputElement;
}
return CPTextFieldDOMInputElement;
}
#endif
@@ -268,29 +262,18 @@ 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. If NO, any
ongoing edit is ended.
/*!
Sets whether or not the receiver text field can be edited
*/
- (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];
}
/*!
@@ -301,19 +284,6 @@ 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
@@ -376,7 +346,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
- (void)setBezelStyle:(CPTextFieldBezelStyle)aBezelStyle
{
var shouldBeRounded = aBezelStyle === CPTextFieldRoundedBezel;
if (shouldBeRounded)
[self setThemeState:CPTextFieldStateRounded];
else
@@ -422,9 +392,9 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
{
if (_drawsBackground == shouldDrawBackground)
return;
_drawsBackground = shouldDrawBackground;
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
@@ -445,9 +415,9 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
{
if (_textFieldBackgroundColor == aColor)
return;
_textFieldBackgroundColor = aColor;
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
@@ -485,15 +455,11 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
#if PLATFORM(DOM)
var string = [self stringValue],
element = [self _inputElement],
font = [self currentValueForThemeAttribute:@"font"];
// generate the font metric
[font _getMetrics];
element = [self _inputElement];
element.value = string;
element.style.color = [[self currentValueForThemeAttribute:@"text-color"] cssString];
element.style.font = [font cssString];
element.style.font = [[self currentValueForThemeAttribute:@"font"] cssString];
element.style.zIndex = 1000;
switch ([self alignment])
@@ -505,60 +471,33 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
default: element.style.textAlign = "left";
}
var contentRect = [self contentRectForBounds:[self bounds]],
verticalAlign = [self currentValueForThemeAttribute:"vertical-alignment"];
var contentRect = [self contentRectForBounds:[self bounds]];
switch (verticalAlign)
{
case CPTopVerticalTextAlignment:
var topPoint = (_CGRectGetMinY(contentRect) + 1) + "px"; // for the same reason we have a -1 for the left, we also have a + 1 here
break;
case CPCenterVerticalTextAlignment:
var topPoint = (_CGRectGetMidY(contentRect) - (font._lineHeight / 2) + 1) + "px";
break;
case CPBottomVerticalTextAlignment:
var topPoint = (_CGRectGetMaxY(contentRect) - font._lineHeight) + "px";
break;
default:
var topPoint = (_CGRectGetMinY(contentRect) + 1) + "px";
break;
}
element.style.top = topPoint;
element.style.top = _CGRectGetMinY(contentRect) + "px";
element.style.left = (_CGRectGetMinX(contentRect) - 1) + "px"; // why -1?
element.style.width = _CGRectGetWidth(contentRect) + "px";
element.style.height = font._lineHeight + "px"; // private ivar for the line height of the DOM text at this particular size
element.style.height = _CGRectGetHeight(contentRect) + "px";
_DOMElement.appendChild(element);
window.setTimeout(function()
{
window.setTimeout(function()
{
element.focus();
// Select the text if the textfield became first responder through keyboard interaction
if (!_willBecomeFirstResponderByClick)
[self selectText:self];
_willBecomeFirstResponderByClick = NO;
[self textDidFocus:[CPNotification notificationWithName:CPTextFieldDidFocusNotification object:self userInfo:nil]];
CPTextFieldInputOwner = self;
}, 0.0);
element.value = [self stringValue];
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
CPTextFieldInputIsActive = YES;
if (document.attachEvent)
{
CPTextFieldCachedSelectStartFunction = [[self window] platformWindow]._DOMBodyElement.onselectstart;
CPTextFieldCachedDragFunction = [[self window] platformWindow]._DOMBodyElement.ondrag;
[[self window] platformWindow]._DOMBodyElement.ondrag = function () {};
[[self window] platformWindow]._DOMBodyElement.onselectstart = function () {};
}
@@ -580,17 +519,14 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
var element = [self _inputElement];
if ([self stringValue] !== element.value)
[self _setStringValue:element.value];
[self setObjectValue:element.value];
CPTextFieldInputResigning = YES;
if (CPTextFieldInputIsActive)
element.blur();
element.blur();
if (!CPTextFieldInputDidBlur)
CPTextFieldBlurFunction();
CPTextFieldInputDidBlur = NO;
CPTextFieldInputResigning = NO;
@@ -601,13 +537,13 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
if (document.attachEvent)
{
[[self window] platformWindow]._DOMBodyElement.ondrag = CPTextFieldCachedDragFunction;
[[self window] platformWindow]._DOMBodyElement.onselectstart = CPTextFieldCachedSelectStartFunction;
CPTextFieldCachedSelectStartFunction = nil;
CPTextFieldCachedDragFunction = nil;
[[self window] platformWindow]._DOMBodyElement.ondrag = CPTextFieldCachedDragFunction;
[[self window] platformWindow]._DOMBodyElement.onselectstart = CPTextFieldCachedSelectStartFunction;
}
#endif
//post CPControlTextDidEndEditingNotification
@@ -637,50 +573,21 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
{
// Don't track! (ever?)
if ([self isEditable] && [self isEnabled])
{
_willBecomeFirstResponderByClick = YES;
[[self window] makeFirstResponder:self];
}
else if ([self isSelectable])
{
if (document.attachEvent)
{
CPTextFieldCachedSelectStartFunction = [[self window] platformWindow]._DOMBodyElement.onselectstart;
CPTextFieldCachedDragFunction = [[self window] platformWindow]._DOMBodyElement.ondrag;
[[self window] platformWindow]._DOMBodyElement.ondrag = function () {};
[[self window] platformWindow]._DOMBodyElement.onselectstart = function () {};
}
return [[[anEvent window] platformWindow] _propagateCurrentDOMEvent:YES];
}
return [[self window] makeFirstResponder:self];
else
return [[self nextResponder] mouseDown:anEvent];
}
- (void)mouseUp:(CPEvent)anEvent
{
if (![self isSelectable] && (![self isEditable] || ![self isEnabled]))
if (![self isEditable] || ![self isEnabled])
[[self nextResponder] mouseUp:anEvent];
else if ([self isSelectable])
{
if (document.attachEvent)
{
[[self window] platformWindow]._DOMBodyElement.ondrag = CPTextFieldCachedDragFunction;
[[self window] platformWindow]._DOMBodyElement.onselectstart = CPTextFieldCachedSelectStartFunction;
CPTextFieldCachedSelectStartFunction = nil
CPTextFieldCachedDragFunction = nil;
}
return [[[anEvent window] platformWindow] _propagateCurrentDOMEvent:YES];
}
}
- (void)mouseDragged:(CPEvent)anEvent
{
if (![self isSelectable] && (![self isEditable] || ![self isEnabled]))
if (![self isEditable] || ![self isEnabled])
[[self nextResponder] mouseDragged:anEvent];
else if ([self isSelectable])
return [[[anEvent window] platformWindow] _propagateCurrentDOMEvent:YES];
}
- (void)keyUp:(CPEvent)anEvent
@@ -704,88 +611,42 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
- (void)keyDown:(CPEvent)anEvent
{
// CPTextField uses an HTML input element to take the input so we need to
// propagate the dom event so the element is updated. This has to be done
// before interpretKeyEvents: though so individual commands have a chance
// to override this (escape to clear the text in a search field for example).
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
if ([anEvent keyCode] === CPReturnKeyCode)
{
if (_isEditing)
{
_isEditing = NO;
[self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:nil]];
}
[self interpretKeyEvents:[anEvent]];
[self sendAction:[self action] to:[self target]];
[self selectText:nil];
[[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
}
else if ([anEvent keyCode] === CPTabKeyCode)
{
if ([anEvent modifierFlags] & CPShiftKeyMask)
[[self window] selectPreviousKeyView:self];
else
[[self window] selectNextKeyView:self];
if ([[[self window] firstResponder] respondsToSelector:@selector(selectText:)])
[[[self window] firstResponder] selectText:self];
[[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
}
else
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
}
/*!
Invoke the action specified by aSelector on the current responder.
This is implemented by CPResponder and by default it passes any unrecognized
actions on to the next responder but text fields apparently aren't supposed
to do that according to this documentation by Apple:
http://developer.apple.com/mac/library/documentation/cocoa/reference/NSTextInputClient_Protocol/Reference/Reference.html#//apple_ref/occ/intfm/NSTextInputClient/doCommandBySelector:
*/
- (void)doCommandBySelector:(SEL)aSelector
{
if ([self respondsToSelector:aSelector])
[self performSelector:aSelector];
}
- (void)insertNewline:(id)sender
{
if (_isEditing)
{
_isEditing = NO;
[self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:nil]];
}
[self sendAction:[self action] to:[self target]];
[self selectText:nil];
[[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
}
- (void)insertNewlineIgnoringFieldEditor:(id)sender
{
var oldValue = [self stringValue];
[self _inputElement].value += CPNewlineCharacter;
[self _setStringValue:[self _inputElement].value];
if (oldValue !== [self stringValue])
{
if (!_isEditing)
{
_isEditing = YES;
[self textDidBeginEditing:[CPNotification notificationWithName:CPControlTextDidBeginEditingNotification object:self userInfo:nil]];
}
[self textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:self userInfo:nil]];
}
}
- (void)insertTabIgnoringFieldEditor:(id)sender
{
var oldValue = [self stringValue];
[self _inputElement].value += CPTabCharacter;
[self _setStringValue:[self _inputElement].value];
if (oldValue !== [self stringValue])
{
if (!_isEditing)
{
_isEditing = YES;
[self textDidBeginEditing:[CPNotification notificationWithName:CPControlTextDidBeginEditingNotification object:self userInfo:nil]];
}
[self textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:self userInfo:nil]];
}
}
- (void)textDidBlur:(CPNotification)note
{
// this looks to prevent false propagation of notifications for other objects
if ([note object] != self)
//this looks to prevent false propagation of notifications for other objects
if([note object] != self)
return;
[[CPNotificationCenter defaultCenter] postNotification:note];
@@ -793,30 +654,13 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
- (void)textDidFocus:(CPNotification)note
{
// this looks to prevent false propagation of notifications for other objects
if ([note object] != self)
//this looks to prevent false propagation of notifications for other objects
if([note object] != self)
return;
[[CPNotificationCenter defaultCenter] postNotification:note];
}
- (void)textDidChange:(CPNotification)note
{
if ([note object] !== self)
return;
[self _continuouslyReverseSetBinding];
[super textDidChange:note];
}
- (void)sendAction:(SEL)anAction to:(id)anObject
{
[self _reverseSetBinding];
[CPApp sendAction:anAction to:anObject from:self];
}
/*!
Returns the string the text field.
*/
@@ -827,7 +671,6 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
/*
@ignore
Sets the internal string value without updating the value in the input element
*/
- (void)_setStringValue:(id)aValue
{
@@ -840,7 +683,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
- (void)setObjectValue:(id)aValue
{
[super setObjectValue:aValue];
#if PLATFORM(DOM)
if (CPTextFieldInputOwner === self || [[self window] firstResponder] === self)
@@ -864,11 +707,11 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
Sets a placeholder string for the receiver. The placeholder is displayed until editing begins,
and after editing ends, if the text field has an empty string value
*/
- (void)setPlaceholderString:(CPString)aStringValue
-(void)setPlaceholderString:(CPString)aStringValue
{
if (_placeholderString === aStringValue)
return;
_placeholderString = aStringValue;
// Only update things if we need to show the placeholder
@@ -888,97 +731,63 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
}
/*!
For non-bezeled text fields (typically a label), sizeToFit has two behaviors, depending
on the line break mode of the receiver.
For non-bezeled receivers with a non-wrapping line break mode, sizeToFit will change the frame of the
receiver to perfectly fit the current text in stringValue in the current font, respecting
the current theme value for content-inset. For receivers with a wrapping line break mode,
sizeToFit will wrap the text within the current width (respecting the current content-inset),
so it will ONLY change the HEIGHT.
For bezeled text fields (typically editable fields), sizeToFit will ONLY change the HEIGHT
of the text field. It will not change the width of the text field. sizeToFit will attempt to
change the height to fit a single line of text, respecting the current theme values for min-size,
max-size and content-inset.
Size to fit has two behavior, depending on if the receiver is an editable text field or not.
For non-editable text fields (typically, a label), sizeToFit will change the frame of the
receiver to perfectly fit the current text in stringValue in the current font, and respecting
the current theme values for content-inset, min-size, and max-size.
For editable text fields, sizeToFit will ONLY change the HEIGHT of the text field. It will not
change the width of the text field. You can use setFrameSize: with the current height to set the
width, and you can get the size of a string with [CPString sizeWithFont:].
The logic behind this decision is that most of the time you do not know what content will be placed
in a bezeled text field, so you want to just choose a fixed width and leave it at that size.
in an editable text field, so you want to just choose a fixed width and leave it at that size.
However, since you don't know how tall it needs to be if you change the font, sizeToFit will still be
useful for making the textfield an appropriate height.
*/
- (void)sizeToFit
{
[self setFrameSize:[self _minimumFrameSize]];
}
- (CGSize)_minimumFrameSize
{
var frameSize = [self frameSize],
var size = [([self stringValue] || " ") sizeWithFont:[self currentValueForThemeAttribute:@"font"]],
contentInset = [self currentValueForThemeAttribute:@"content-inset"],
minSize = [self currentValueForThemeAttribute:@"min-size"],
maxSize = [self currentValueForThemeAttribute:@"max-size"],
lineBreakMode = [self lineBreakMode],
text = ([self stringValue] || @" "),
textSize = _CGSizeMakeCopy(frameSize),
font = [self currentValueForThemeAttribute:@"font"];
maxSize = [self currentValueForThemeAttribute:@"max-size"];
textSize.width -= contentInset.left + contentInset.right;
textSize.height -= contentInset.top + contentInset.bottom;
size.width = MAX(size.width + contentInset.left + contentInset.right, minSize.width);
size.height = MAX(size.height + contentInset.top + contentInset.bottom, minSize.height);
if (frameSize.width !== 0 &&
![self isBezeled] &&
(lineBreakMode === CPLineBreakByWordWrapping || lineBreakMode === CPLineBreakByCharWrapping))
{
textSize = [text sizeWithFont:font inWidth:textSize.width];
}
else
textSize = [text sizeWithFont:font];
if (maxSize.width >= 0.0)
size.width = MIN(size.width, maxSize.width);
frameSize.height = textSize.height + contentInset.top + contentInset.bottom;
if (maxSize.height >= 0.0)
size.height = MIN(size.height, maxSize.height);
if ([self isBezeled])
{
frameSize.height = MAX(frameSize.height, minSize.height);
if ([self isEditable])
size.width = CGRectGetWidth([self frame]);
if (maxSize.width > 0.0)
frameSize.width = MIN(frameSize.width, maxSize.width);
if (maxSize.height > 0.0)
frameSize.height = MIN(frameSize.height, maxSize.height);
}
else
frameSize.width = textSize.width + contentInset.left + contentInset.right;
frameSize.width = MAX(frameSize.width, minSize.width);
return frameSize;
[self setFrameSize:size];
}
/*!
Make the receiver the first responder and select all the text in the field.
Select all the text in the CPTextField.
*/
- (void)selectText:(id)sender
{
// FIXME Should this really make the text field the first responder?
#if PLATFORM(DOM)
var element = [self _inputElement];
if (([self isEditable] || [self isSelectable]))
{
#if PLATFORM(DOM)
var element = [self _inputElement];
if ([[self window] firstResponder] === self)
window.setTimeout(function() { element.select(); }, 0);
else if ([self window] !== nil && [[self window] makeFirstResponder:self])
window.setTimeout(function() {[self selectText:sender];}, 0);
#else
// Even if we can't actually select the text we need to preserve the first
// responder side effect.
if ([self window] !== nil && [[self window] firstResponder] !== self)
else
{
[[self window] makeFirstResponder:self];
#endif
window.setTimeout(function() {[self selectText:sender];}, 0);
}
}
#endif
}
- (void)copy:(id)sender
@@ -1006,8 +815,6 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
[self copy:sender];
[self deleteBackward:sender];
}
else
[CPTimer scheduledTimerWithTimeInterval:0.0 target:self selector:@selector(keyUp:) userInfo:nil repeats:NO];
}
- (void)paste:(id)sender
@@ -1027,10 +834,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:pasteString];
[self setStringValue:newValue];
[self setSelectedRange:CPMakeRange(selectedRange.location + pasteString.length, 0)];
[self setSelectedRange:CPMakeRange(selectedRange.location+pasteString.length, 0)];
}
else
[CPTimer scheduledTimerWithTimeInterval:0.0 target:self selector:@selector(keyUp:) userInfo:nil repeats:NO];
}
- (CPRange)selectedRange
@@ -1039,14 +844,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,
@@ -1058,13 +863,13 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
range.setEndPoint('EndToStart', selectionRange);
return CPMakeRange(range.text.length, selectionRange.text.length);
}
}
catch (e)
}
catch (e)
{
// fall through to the return
}
return CPMakeRange(0, 0);
return CGMakeRange(0, 0);
}
- (void)setSelectedRange:(CPRange)aRange
@@ -1074,7 +879,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
var inputElement = [self _inputElement];
try
try
{
if ([inputElement.selectionStart isKindOfClass:CPNumber])
{
@@ -1087,7 +892,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
var theDocument = inputElement.ownerDocument || inputElement.document,
existingRange = theDocument.selection.createRange(),
range = inputElement.createTextRange();
if (range.inRange(existingRange))
{
range.collapse(true);
@@ -1109,15 +914,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
- (void)deleteBackward:(id)sender
{
var selectedRange = [self selectedRange];
if (selectedRange.length < 2)
return;
selectedRange.location += 1;
selectedRange.length -= 1;
var stringValue = [self stringValue],
var selectedRange = [self selectedRange],
stringValue = [self stringValue],
newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:""];
[self setStringValue:newValue];
@@ -1129,7 +927,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
- (void)setDelegate:(id)aDelegate
{
var defaultCenter = [CPNotificationCenter defaultCenter];
//unsubscribe the existing delegate if it exists
if (_delegate)
{
@@ -1139,24 +937,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
@@ -1187,15 +985,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;
}
@@ -1205,12 +1003,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;
}
@@ -1218,10 +1016,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];
}
@@ -1232,19 +1030,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];
}
@@ -1253,10 +1051,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"];
@@ -1266,7 +1064,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
[contentView setHidden:[self hasThemeState:CPThemeStateEditing]];
var string = "";
if ([self hasThemeState:CPTextFieldStatePlaceholder])
string = [self placeholderString];
else
@@ -1313,7 +1111,7 @@ var secureStringForString = function(aString)
if (!aString)
return "";
return Array(aString.length + 1).join(CPSecureTextFieldCharacter);
return Array(aString.length+1).join(CPSecureTextFieldCharacter);
}
@@ -1324,7 +1122,6 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
CPTextFieldBezelStyleKey = "CPTextFieldBezelStyleKey",
CPTextFieldDrawsBackgroundKey = "CPTextFieldDrawsBackgroundKey",
CPTextFieldLineBreakModeKey = "CPTextFieldLineBreakModeKey",
CPTextFieldAlignmentKey = "CPTextFieldAlignmentKey",
CPTextFieldBackgroundColorKey = "CPTextFieldBackgroundColorKey",
CPTextFieldPlaceholderStringKey = "CPTextFieldPlaceholderStringKey";
@@ -1338,7 +1135,7 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
[self setEditable:[aCoder decodeBoolForKey:CPTextFieldIsEditableKey]];
@@ -1348,12 +1145,9 @@ 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;
}
@@ -1364,68 +1158,16 @@ 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];
}
@end
@implementation _CPTextFieldValueBinder : CPBinder
{
}
- (void)setValueFor:(CPString)theBinding
{
var destination = [_info objectForKey:CPObservedObjectKey],
keyPath = [_info objectForKey:CPObservedKeyPathKey],
options = [_info objectForKey:CPOptionsKey],
newValue = [destination valueForKeyPath:keyPath],
isPlaceholder = CPIsControllerMarker(newValue);
if (isPlaceholder)
{
switch (newValue)
{
case CPMultipleValuesMarker:
newValue = [options objectForKey:CPMultipleValuesPlaceholderBindingOption] || @"Multiple Values";
break;
case CPNoSelectionMarker:
newValue = [options objectForKey:CPNoSelectionPlaceholderBindingOption] || @"No Selection";
break;
case CPNotApplicableMarker:
if ([options objectForKey:CPRaisesForNotApplicableKeysBindingOption])
[CPException raise:CPGenericException
reason:@"can't transform non applicable key on: "+_source+" value: "+newValue];
newValue = [options objectForKey:CPNotApplicablePlaceholderBindingOption] || @"Not Applicable";
break;
case CPNullMarker:
newValue = [options objectForKey:CPNullPlaceholderBindingOption] || @"";
break;
}
[_source setPlaceholderString:newValue];
[_source setObjectValue:nil];
}
else
{
newValue = [self transformValue:newValue withOptions:options];
[_source setObjectValue:newValue];
}
}
@end
+26 -243
View File
@@ -24,11 +24,8 @@
@import <Foundation/CPString.j>
@import <Foundation/CPKeyedUnarchiver.j>
var CPThemesByName = { },
CPThemeNamesByInheritance = [],
CPThemeDefaultTheme = nil,
CPThemeDefaultHudTheme = nil;
var CPThemesByName = { },
CPThemeDefaultTheme = nil;
/*!
@@ -51,78 +48,11 @@ 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];
}
/*!
Returns an array of names of all loaded themes, in the order they were loaded.
*/
+ (CPArray)allThemeNames
{
return [CPThemeNamesByInheritance copy];
}
/*!
Returns the closest matching theme for a given view or view class.
The matching proceeds as follows:
- The default theme class name for the class is retrieved.
- Starting with the last loaded theme and proceeding towards the default theme,
each theme is checked to see if it defines that theme class.
- If the theme defines the class name, that theme is returned.
- If no themes match, the default theme is returned.
@param aViewOrClass The view or view class to match with a theme
@return The first matching theme
*/
+ (CPTheme)themeForView:(id)aViewOrClass
{
var themeClass = nil;
if (class_isMetaClass(aViewOrClass.isa))
themeClass = [aViewOrClass defaultThemeClass];
else
themeClass = [aViewOrClass themeClass];
if (themeClass)
{
var count = CPThemeNamesByInheritance.length;
while (count--)
{
var theme = CPThemesByName[CPThemeNamesByInheritance[count]];
if ([theme._attributes containsKey:themeClass])
return theme;
}
}
return CPThemeDefaultTheme;
}
- (id)initWithName:(CPString)aName
{
self = [super init];
@@ -133,9 +63,6 @@ var CPThemesByName = { },
_attributes = [CPDictionary dictionary];
CPThemesByName[_name] = self;
if (![CPThemeNamesByInheritance containsObject:_name])
CPThemeNamesByInheritance.push(_name);
}
return self;
@@ -146,110 +73,9 @@ var CPThemesByName = { },
return _name;
}
/*!
Returns an array of names of themed classes defined in this theme, as found in its
ThemeDescriptors.j file.
NOTE: The names are not class names (such as "CPButton"), but the names returned
by the class' +defaultThemeClass method. For example, the name for CPCheckBox is "check-box",
as defined in CPCheckBox::themeClass.
*/
- (CPArray)classNames
- (_CPThemeAttribute)_attributeWithName:(CPString)aName forClass:(CPString)aClass
{
return [_attributes allKeys];
}
/*!
Returns a dictionary of all theme attributes defined for the given class, as found in the
theme's ThemeDescriptors.j file. The keys of the dictionary are attribute names, and the values
are instances of _CPThemeAttribute.
For a description of valid values for \c aClass, see \ref attributeNamesForClass:.
@param aClass The themed class whose attributes you want to retrieve
@return A dictionary of attributes or nil
*/
- (CPDictionary)attributesForClass:(id)aClass
{
if (!aClass)
return nil;
var className = nil;
if ([aClass isKindOfClass:[CPString class]])
{
// See if it is a class name
var theClass = CPClassFromString(aClass);
if (theClass)
aClass = theClass;
else
className = aClass;
}
if (!className)
{
if ([aClass isKindOfClass:[CPView class]])
{
if ([aClass respondsToSelector:@selector(defaultThemeClass)])
className = [aClass defaultThemeClass];
else if ([aClass respondsToSelector:@selector(themeClass)])
{
CPLog.warn(@"%@ themeClass is deprecated in favor of defaultThemeClass",CPStringFromClass([anObject class]));
className = [aClass themeClass];
}
else
return nil;
}
else
[CPException raise:CPInvalidArgumentException reason:@"aClass must be a class object or a string."];
}
return [_attributes objectForKey:className];
}
/*!
Returns an array of names of all theme attributes defined for the given class, as found in the
theme's ThemeDescriptors.j file.
The \c aClass parameter can be one of the following:
- A class instance, for example the result of [CPCheckBox class]. The class must be a subclass
of CPView.
- A class name, for example "CPCheckBox".
- A themed class name, for example "check-box".
If \c aClass does not refer to a themed class in this theme, nil is returned.
@param aClass The themed class whose attributes you want to retrieve
@return An array of attribute names or nil
*/
- (CPDictionary)attributeNamesForClass:(id)aClass
{
var attributes = [self attributesForClass:aClass];
if (attributes)
return [attributes allKeys];
else
return [CPArray array];
}
/*!
Returns a theme attribute defined for the given class, as found in the
theme's ThemeDescriptors.j file.
\c aName should be the attribute name as you would pass to the method
CPView::valueForThemeAttribute:.
For a description of valid values for \c aClass, see \ref attributeNamesForClass:.
@param aName The name of the attribute you want to retrieve
@param aClass The themed class in which to look for the attribute
@return An instance of _CPThemeAttribute or nil
*/
- (_CPThemeAttribute)attributeWithName:(CPString)aName forClass:(id)aClass
{
var attributes = [self attributesForClass:aClass];
var attributes = [_attributes objectForKey:aClass];
if (!attributes)
return nil;
@@ -257,53 +83,12 @@ var CPThemesByName = { },
return [attributes objectForKey:aName];
}
/*!
Returns the value for a theme attribute in its normal state, as defined for the given class
in the theme's ThemeDescriptors.j file.
\c aName should be the attribute name as you would pass to the method
CPView::valueForThemeAttribute:.
For a description of valid values for \c aClass, see \ref attributeNamesForClass:.
@param aName The name of the attribute whose value you want to retrieve
@param aClass The themed class in which to look for the attribute
@return A value or nil
*/
- (id)valueForAttributeWithName:(CPString)aName forClass:(id)aClass
{
return [self valueForAttributeWithName:aName inState:CPThemeStateNormal forClass:aClass];
}
/*!
Returns the value for a theme attribute in a given state, as defined for the given class
in the theme's ThemeDescriptors.j file. This is the equivalent of the method
CPView::valueForThemeAttribute:inState:, but retrieves the value from the theme definition as
opposed to a single view's current theme state.
For a description of valid values for \c aClass, see \ref attributeNamesForClass:.
@param aName The name of the attribute whose value you want to retrieve
@param aState The state qualifier for the attribute
@param aClass The themed class in which to look for the attribute
@return A value or nil
*/
- (id)valueForAttributeWithName:(CPString)aName inState:(CPThemeState)aState forClass:(id)aClass
{
var attribute = [self attributeWithName:aName forClass:aClass];
if (!attribute)
return nil;
return [attribute valueForState:aState];
}
- (void)takeThemeFromObject:(id)anObject
{
var attributes = [anObject _themeAttributeDictionary],
attributeName = nil,
attributeNames = [attributes keyEnumerator],
objectThemeClass = [anObject themeClass];
objectThemeClass = [[anObject class] themeClass];
while (attributeName = [attributeNames nextObject])
[self _recordAttribute:[attributes objectForKey:attributeName] forClass:objectThemeClass];
@@ -349,9 +134,6 @@ var CPThemeNameKey = @"CPThemeNameKey",
_attributes = [aCoder decodeObjectForKey:CPThemeAttributesKey];
CPThemesByName[_name] = self;
if (![CPThemeNamesByInheritance containsObject:_name])
CPThemeNamesByInheritance.push(_name);
}
return self;
@@ -458,12 +240,8 @@ function CPThemeStateName(aState)
CPThemeStateNames[0] = "normal";
CPThemeStateNormal = CPThemeStates["normal"] = 0;
CPThemeStateDisabled = CPThemeState("disabled");
CPThemeStateHovered = CPThemeState("hovered");
CPThemeStateHighlighted = CPThemeState("highlighted");
CPThemeStateSelected = CPThemeState("selected");
CPThemeStateTableDataView = CPThemeState("tableDataView");
CPThemeStateSelectedDataView = CPThemeStateSelectedTableDataView = CPThemeState("selectedTableDataView");
CPThemeStateGroupRow = CPThemeState("CPThemeStateGroupRow");
CPThemeStateBezeled = CPThemeState("bezeled");
CPThemeStateBordered = CPThemeState("bordered");
CPThemeStateEditable = CPThemeState("editable");
@@ -476,10 +254,10 @@ CPThemeStateCircular = CPThemeState("circular");
{
CPString _name;
id _defaultValue;
CPDictionary _values @accessors(readonly, getter=values);
CPDictionary _values;
JSObject _cache;
_CPThemeAttribute _parentAttribute;
CPThemeAttribute _parentAttribute;
}
- (id)initWithName:(CPString)aName defaultValue:(id)aDefaultValue
@@ -519,7 +297,12 @@ CPThemeStateCircular = CPThemeState("circular");
- (void)setValue:(id)aValue
{
[self setValue:aValue forState:CPThemeStateNormal];
_cache = {};
if (aValue === undefined || aValue === nil)
_values = [CPDictionary dictionary];
else
_values = [CPDictionary dictionaryWithObject:aValue forKey:String(CPThemeStateNormal)];
}
- (void)setValue:(id)aValue forState:(CPThemeState)aState
@@ -595,7 +378,7 @@ CPThemeStateCircular = CPThemeState("circular");
return value;
}
- (void)setParentAttribute:(_CPThemeAttribute)anAttribute
- (void)setParentAttribute:(CPThemeAttribute)anAttribute
{
if (_parentAttribute === anAttribute)
return;
@@ -604,7 +387,7 @@ CPThemeStateCircular = CPThemeState("circular");
_parentAttribute = anAttribute;
}
- (_CPThemeAttribute)attributeMergedWithAttribute:(_CPThemeAttribute)anAttribute
- (CPThemeAttribute)attributeMergedWithAttribute:(_CPThemeAttribute)anAttribute
{
var mergedAttribute = [[_CPThemeAttribute alloc] initWithName:_name defaultValue:_defaultValue];
@@ -689,15 +472,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)
@@ -768,7 +551,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;
}
@@ -802,4 +585,4 @@ for (i = 0;i < Math.pow(2,6);++i)
}
print(str+']');
*/
*/
+10 -34
View File
@@ -22,10 +22,9 @@
@import <Foundation/CPObject.j>
@import "CPTheme.j"
@import "_CPCibCustomResource.j"
@import "_CPCibKeyedUnarchiver.j"
@import <AppKit/CPTheme.j>
@import <AppKit/_CPCibCustomResource.j>
@import <AppKit/_CPCibKeyedUnarchiver.j>
/*!
@ingroup appkit
@@ -34,60 +33,37 @@
@implementation CPThemeBlend : CPObject
{
CPBundle _bundle;
CPArray _themes;
CPArray _themes @accessors(readonly, getter=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
{
_themes = [_bundle objectForInfoDictionaryKey:@"CPKeyedThemes"];
var count = _themes.length;
var themes = [_bundle objectForInfoDictionaryKey:@"CPKeyedThemes"],
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];
File diff suppressed because it is too large Load Diff
+14 -42
View File
@@ -28,6 +28,8 @@
@import "CPPopUpButton.j"
@import "CPToolbarItem.j"
#include "CoreGraphics/CGGeometry.h"
/*
@global
@@ -50,8 +52,8 @@ CPToolbarDisplayModeIconOnly = 2;
*/
CPToolbarDisplayModeLabelOnly = 3;
var CPToolbarsByIdentifier = nil,
CPToolbarConfigurationsByIdentifier = nil;
var CPToolbarsByIdentifier = nil;
var CPToolbarConfigurationsByIdentifier = nil;
/*!
@ingroup appkit
@@ -327,11 +329,7 @@ var CPToolbarsByIdentifier = nil,
return _itemsSortedByVisibilityPriority;
}
/*!
Validates the visible toolbar items by sending a validate message to
each visible toolbar item.
*/
- (void)validateVisibleItems
- (void)validateVisibleToolbarItems
{
var toolbarItems = [self visibleItems],
count = [toolbarItems count];
@@ -464,18 +462,11 @@ var CPToolbarIdentifierKey = @"CPToolbarIdentifierKey",
// Because we don't know if a delegate will be set later (it is optional
// as of OS X 10.5), we need to call -_reloadToolbarItems here.
// In order to load any toolbar items that may have been configured in the
// Cib. Unfortunately this means that if there is a delegate
// Cib. Unfortunatelly this means that if there is a delegate
// specified, it will be read later and the resulting call to -setDelegate:
// will cause -_reloadToolbarItems] to run again :-(
// FIXME: Can we make this better?
// Do this at the end of the run loop to allow all the cib-stuff to
// finish (establishing connections, etc.).
[[CPRunLoop currentRunLoop]
performSelector:@selector(_reloadToolbarItems)
target:self
argument:nil
order:0 modes:[CPDefaultRunLoopMode]];
[self _reloadToolbarItems];
}
return self;
@@ -568,7 +559,6 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
[_additionalItemsButton setImagePosition:CPImageOnly];
[[_additionalItemsButton menu] setShowsStateColumn:NO];
[[_additionalItemsButton menu] setAutoenablesItems:NO];
[_additionalItemsButton setAlternateImage:_CPToolbarViewExtraItemsAlternateImage];
}
@@ -667,7 +657,7 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
// Determine all the items that have flexible width.
// Also determine the height of the toolbar.
var count = _visibleItems.length,
var count = _visibleItems.length
flexibleItemIndexes = [CPIndexSet indexSet];
while (count--)
@@ -799,32 +789,20 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
hasNonSeparatorItem = YES;
var menuItem = [[CPMenuItem alloc] initWithTitle:[item label] action:@selector(didSelectMenuItem:) keyEquivalent:nil];
[_additionalItemsButton addItemWithTitle:[item label]];
var menuItem = [_additionalItemsButton itemArray][index + 1];
[menuItem setRepresentedObject:item];
[menuItem setImage:[item image]];
[menuItem setTarget:self];
[menuItem setEnabled:[item isEnabled]];
[_additionalItemsButton addItem:menuItem];
[menuItem setTarget:[item target]];
[menuItem setAction:[item action]];
}
}
else
[_additionalItemsButton removeFromSuperview];
}
/*
Used privately.
@ignore
*/
- (void)didSelectMenuItem:(id)aSender
{
var toolbarItem = [aSender representedObject];
[CPApp sendAction:[toolbarItem action] to:[toolbarItem target] from:toolbarItem];
}
- (void)reloadToolbarItems
{
// Get rid of all our current subviews.
@@ -849,10 +827,6 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
view = [[_CPToolbarItemView alloc] initWithToolbarItem:item toolbar:self];
_viewsForToolbarItems[[item UID]] = view;
if ([item toolTip] && [view respondsToSelector:@selector(setToolTip:)])
[view setToolTip:[item toolTip]];
[self addSubview:view];
_minWidth += [view minSize].width + TOOLBAR_ITEM_MARGIN;
@@ -996,7 +970,7 @@ var TOP_MARGIN = 5.0,
{
_imageView = [[CPImageView alloc] initWithFrame:[self bounds]];
[_imageView setImageScaling:CPScaleProportionally];
[_imageView setImageScaling:CPScaleNone];
[self addSubview:_imageView];
}
@@ -1077,8 +1051,6 @@ var TOP_MARGIN = 5.0,
[_imageView setAlphaValue:0.5];
[_labelField setAlphaValue:0.5];
}
[_toolbar tile];
}
- (CPColor)FIXME_labelColor
+38 -39
View File
@@ -23,9 +23,8 @@
@import <Foundation/CPObject.j>
@import <Foundation/CPString.j>
@import "CPImage.j"
@import "CPView.j"
@import <AppKit/CPImage.j>
@import <AppKit/CPView.j>
CPToolbarItemVisibilityPriorityStandard = 0;
CPToolbarItemVisibilityPriorityLow = -1000;
@@ -40,7 +39,7 @@ CPToolbarShowFontsItemIdentifier = @"CPToolbarShowFontsItem";
CPToolbarCustomizeToolbarItemIdentifier = @"CPToolbarCustomizeToolbarItem";
CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
/*!
/*!
@ingroup appkit
@class CPToolbarItem
@@ -49,9 +48,9 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
@implementation CPToolbarItem : CPObject
{
CPString _itemIdentifier;
CPToolbar _toolbar;
CPString _label;
CPString _paletteLabel;
CPString _toolTip;
@@ -61,12 +60,12 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
BOOL _isEnabled;
CPImage _image;
CPImage _alternateImage;
CPView _view;
CGSize _minSize;
CGSize _maxSize;
CGSize _maxSize;
int _visibilityPriority;
BOOL _autovalidates;
@@ -86,21 +85,21 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
- (id)initWithItemIdentifier:(CPString)anItemIdentifier
{
self = [super init];
if (self)
{
_itemIdentifier = anItemIdentifier;
_tag = 0;
_isEnabled = YES;
_minSize = CGSizeMakeZero();
_maxSize = CGSizeMakeZero();
_visibilityPriority = CPToolbarItemVisibilityPriorityStandard;
_autovalidates = YES;
}
return self;
}
@@ -170,7 +169,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
{
if ([_view respondsToSelector:@selector(toolTip)])
return [_view toolTip];
return _toolTip;
}
@@ -182,7 +181,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
{
if ([_view respondsToSelector:@selector(setToolTip:)])
[_view setToolTip:aToolTip];
_toolTip = aToolTip;
}
@@ -193,7 +192,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
{
if ([_view respondsToSelector:@selector(tag)])
return [_view tag];
return _tag;
}
@@ -205,7 +204,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
{
if ([_view respondsToSelector:@selector(setTag:)])
[_view setTag:aTag];
_tag = aTag;
}
@@ -216,12 +215,12 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
{
if (_view)
return [_view respondsToSelector:@selector(target)] ? [_view target] : nil;
return _target;
}
/*!
Sets the target of the action that is triggered when the user clicks this item. \c nil will cause
Sets the target of the action that is triggered when the user clicks this item. \c nil will cause
the action to be passed on to the first responder.
@param aTarget the new target
*/
@@ -229,7 +228,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
{
if (!_view)
_target = aTarget;
else if ([_view respondsToSelector:@selector(setTarget:)])
[_view setTarget:aTarget];
}
@@ -241,7 +240,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
{
if (_view)
return [_view respondsToSelector:@selector(action)] ? [_view action] : nil;
return _action;
}
@@ -265,7 +264,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
{
if ([_view respondsToSelector:@selector(isEnabled)])
return [_view isEnabled];
return _isEnabled;
}
@@ -277,7 +276,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
{
if ([_view respondsToSelector:@selector(setEnabled:)])
[_view setEnabled:shouldBeEnabled];
_isEnabled = shouldBeEnabled;
}
@@ -288,7 +287,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
{
if ([_view respondsToSelector:@selector(image)])
return [_view image];
return _image;
}
@@ -302,11 +301,11 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
[_view setImage:anImage];
_image = anImage;
if (!_image)
return;
if (_minSize.width === 0 && _minSize.height === 0 &&
if (_minSize.width === 0 && _minSize.height === 0 &&
_maxSize.width === 0 && _maxSize.height === 0)
{
var imageSize = [_image size];
@@ -327,7 +326,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
{
if ([_view respondsToSelector:@selector(setAlternateImage:)])
[_view setAlternateImage:anImage];
_alternateImage = anImage;
}
@@ -338,7 +337,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
{
if ([_view respondsToSelector:@selector(alternateIamge)])
return [_view alternateImage];
return _alternateImage;
}
@@ -358,7 +357,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
{
if (_view == aView)
return;
_view = aView;
if (_view)
@@ -366,7 +365,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
// Tags get forwarded.
if (_tag !== 0 && [_view respondsToSelector:@selector(setTag:)])
[_view setTag:_tag];
_target = nil;
_action = nil;
}
@@ -386,11 +385,11 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
*/
- (void)setMinSize:(CGSize)aMinSize
{
if (!aMinSize.height || !aMinSize.width)
if(!aMinSize.height || !aMinSize.width)
return;
_minSize = CGSizeMakeCopy(aMinSize);
// Try to provide some sanity: Make maxSize >= minSize
_maxSize = CGSizeMake(MAX(_minSize.width, _maxSize.width), MAX(_minSize.height, _maxSize.height));
}
@@ -409,11 +408,11 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
*/
- (void)setMaxSize:(CGSize)aMaxSize
{
if (!aMaxSize.height || !aMaxSize.width)
if(!aMaxSize.height || !aMaxSize.width)
return;
_maxSize = CGSizeMakeCopy(aMaxSize);
// Try to provide some sanity: Make minSize <= maxSize
_minSize = CGSizeMake(MIN(_minSize.width, _maxSize.width), MIN(_minSize.height, _maxSize.height));
}
@@ -623,7 +622,7 @@ var CPToolbarItemItemIdentifierKey = @"CPToolbarItemItemIdentifierKey",
case CPToolbarCustomizeToolbarItemIdentifier: return nil;
case CPToolbarPrintItemIdentifier: return nil;
}
return nil;
}
+1 -14
View File
@@ -1,12 +1,11 @@
@import <Foundation/CPObject.j>
@import <Foundation/CPIndexPath.j>
@implementation CPTreeNode : CPObject
{
id _representedObject @accessors(readonly, property=representedObject);
CPTreeNode _parentNode @accessors(readonly, property=parentNode);
CPMutableArray _childNodes;
}
@@ -88,18 +87,6 @@
[_childNodes[count] sortWithSortDescriptors:sortDescriptors recursively:YES];
}
- (CPTreeNode)descendantNodeAtIndexPath:(CPIndexPath)indexPath
{
var index = 0,
count = [indexPath length],
node = self;
for (; index < count; ++index)
node = [node objectInChildNodesAtIndex:[indexPath indexAtPosition:index]];
return node;
}
@end
var CPTreeNodeRepresentedObjectKey = @"CPTreeNodeRepresentedObjectKey",
-267
View File
@@ -1,267 +0,0 @@
/*
* CPUserDefaultsController.j
* AppKit
*
* Portions based on NSUserDefaultsController.m (2009-06-04) in Cocotron (http://www.cocotron.org/)
* Copyright (c) 2006-2007 Christopher J. W. Lloyd
*
* Created by Alexander Ljungberg.
* Copyright 2011, WireLoad 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/CPString.j>
@import <AppKit/CPController.j>
var SharedUserDefaultsController = nil;
@implementation CPUserDefaultsController : CPController
{
CPUserDefaults _defaults @accessors(readonly, property=defaults);
CPDictionary _initialValues @accessors(property=initialValues);
BOOL _appliesImmediately @accessors(property=appliesImmediately);
}
+ (id)sharedUserDefaultsController
{
if (!SharedUserDefaultsController)
SharedUserDefaultsController = [[CPUserDefaultsController alloc] initWithDefaults:nil initialValues:nil];
return SharedUserDefaultsController;
}
- (id)initWithDefaults:(CPUserDefaults)someDefaults initialValues:(CPDictionary)initialValues
{
if (self = [super init])
{
if (!someDefaults)
someDefaults = [CPUserDefaults standardUserDefaults];
_defaults = someDefaults;
_initialValues = [initialValues copy];
_appliesImmediately = YES;
_valueProxy = [[_CPUserDefaultsControllerProxy alloc] initWithController:self];
}
return self;
}
- (id)values
{
return _valueProxy;
}
- (BOOL)hasUnappliedChanges
{
return [_valueProxy hasUnappliedChanges];
}
- (void)save:(id)sender
{
[_valueProxy save];
}
- (void)revert:(id)sender
{
[_valueProxy revert];
}
- (void)revertToInitialValues:(id)sender
{
[_valueProxy revertToInitialValues];
}
@end
var CPUserDefaultsControllerSharedKey = "CPUserDefaultsControllerSharedKey";
@implementation CPUserDefaultsController (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
if ([aCoder decodeBoolForKey:CPUserDefaultsControllerSharedKey])
return [CPUserDefaultsController sharedUserDefaultsController];
self = [super initWithCoder:aCoder];
if (self)
{
[CPException raise:CPUnsupportedMethodException reason:@"decoding of non-shared CPUserDefaultsController not implemented"];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
if (self === SharedUserDefaultsController)
{
[aCoder encodeBool:YES forKey:CPUserDefaultsControllerSharedKey];
return;
}
[CPException raise:CPUnsupportedMethodException reason:@"encoding of non-shared CPUserDefaultsController not implemented"];
}
@end
@implementation _CPUserDefaultsControllerProxy : CPObject
{
CPUserDefaultsController _controller;
// TODO Could be optimised with a JS dict.
CPMutableDictionary _cachedValues;
}
- (id)initWithController:(CPUserDefaultsController)aController
{
if (self = [super init])
{
_controller = aController;
_cachedValues = [CPMutableDictionary dictionary];
[[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(userDefaultsDidChange:) name:CPUserDefaultsDidChangeNotification object:[_controller defaults]];
}
return self;
}
- (void)dealloc
{
// FIXME No dealloc in Cappuccino.
[[CPNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
- (id)valueForKey:(CPString)aKey
{
var value = [_cachedValues objectForKey:aKey];
if (value === nil)
{
value = [[_controller defaults] objectForKey:aKey];
if (value === nil)
value = [[_controller initialValues] objectForKey:aKey];
if (value !== nil)
[_cachedValues setObject:value forKey:aKey];
}
return value;
}
- (void)setValue:(id)aValue forKey:(CPString)aKey
{
[self willChangeValueForKey:aKey];
[_cachedValues setObject:aValue forKey:aKey];
if ([_controller appliesImmediately])
[[_controller defaults] setObject:aValue forKey:aKey];
[self didChangeValueForKey:aKey];
}
- (void)revert
{
var keys = [_cachedValues allKeys],
keysCount = [keys count];
while(keysCount--)
{
var key = keys[keysCount];
[self willChangeValueForKey:key];
[_cachedValues removeObjectForKey:key];
[self didChangeValueForKey:key];
}
}
- (void)save
{
var keys = [_cachedValues allKeys],
keysCount = [keys count];
while(keysCount--)
{
var key = keys[keysCount];
[[_controller defaults] setObject:[_cachedValues objectForKey:key] forKey:key];
}
}
- (void)revertToInitialValues
{
var initial = [_controller initialValues],
keys = [_cachedValues allKeys],
keysCount = [keys count];
while(keysCount--)
{
var key = keys[keysCount];
[self willChangeValueForKey:key];
var initialValue = [initial objectForKey:key];
if (initialValue !== nil)
[_cachedValues setObject:initialValue forKey:key];
else
[_cachedValues removeObjectForKey:key];
[self didChangeValueForKey:key];
}
}
- (void)userDefaultsDidChange:(CPNotification)aNotification
{
var defaults = [_controller defaults],
keys = [_cachedValues allKeys],
keysCount = [keys count];
while(keysCount--)
{
var key = keys[keysCount],
value = [_cachedValues objectForKey:key],
newValue = [defaults objectForKey:key];
if (![value isEqual:newValue])
{
[self willChangeValueForKey:key];
[_cachedValues setObject:newValue forKey:key];
[self didChangeValueForKey:key];
}
}
}
- (BOOL)hasUnappliedChanges
{
var defaults = [_controller defaults],
keys = [_cachedValues allKeys],
keysCount = [keys count];
while(keysCount--)
{
var key = keys[keysCount],
value = [_cachedValues objectForKey:key],
newValue = [defaults objectForKey:key];
if (![value isEqual:newValue])
return YES;
}
return NO;
}
@end
+210 -396
View File
File diff suppressed because it is too large Load Diff
+19 -68
View File
@@ -1,5 +1,5 @@
/*
* CPViewAnimation.j
* CPFlashView.j
* AppKit
*
* Created by Klaas Pieter Annema on September 3, 2009.
@@ -20,52 +20,21 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPAnimation.j"
@import <AppKit/CPAnimation.j>
CPViewAnimationTargetKey = @"CPViewAnimationTarget";
CPViewAnimationStartFrameKey = @"CPViewAnimationStartFrame";
CPViewAnimationEndFrameKey = @"CPViewAnimationEndFrame";
CPViewAnimationEffectKey = @"CPViewAnimationEffect";
CPViewAnimationTargetKey = @"CPViewAnimationTargetKey";
CPViewAnimationStartFrameKey = @"CPViewAnimationStartFrameKey";
CPViewAnimationEndFrameKey = @"CPViewAnimationEndFrameKey";
CPViewAnimationEffectKey = @"CPViewAnimationEffectKey";
CPViewAnimationFadeInEffect = @"CPViewAnimationFadeInEffect";
CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOutEffect";
/*!
@class CPViewAnimation
CPViewAnimation is a subclass of CPAnimation that makes it easy to do
basic animations on views.
*/
CPViewAnimationFadeInEffect = @"CPViewAnimationFadeIn";
CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut";
@implementation CPViewAnimation : CPAnimation
{
CPArray _viewAnimations;
}
/*!
Designated initializer.
This method takes an array of CPDictionaries. Each dictionary should
contain values for the following keys:
<pre>
CPViewAnimationTargetKey - (Required) The view to animate.
CPViewAnimationStartFrameKey - (Optional) The start frame of the target.
CPViewAnimationEndFrameKey - (Optional) The end frame of the target.
CPViewAnimationEffectKey - (Optional) a fade effect to use for the animation.
</pre>
For example:
<pre>
var animation = [CPDictionary dictionaryWithObjects:[myViewToAnimate, aStartFrame, anEndFrame, CPViewAnimationFadeInEffect]
forKeys:[CPViewAnimationTargetKey, CPViewAnimationStartFrameKey, CPViewAnimationEndFrameKey, CPViewAnimationEffectKey]];
</pre>
If you pass nil instead of an array of dictionaries you should later call setViewAnimations:.
@param viewAnimations - An array of CPDictionaries for each animation.
*/
- (id)initWithViewAnimations:(CPArray)viewAnimations
{
if (self = [super initWithDuration:0.5 animationCurve:CPAnimationLinear])
@@ -91,7 +60,7 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOutEffect";
if (effect === CPViewAnimationFadeInEffect)
{
[view setAlphaValue:0.0];
[self _targetView:view setHidden:NO];
[view setHidden:NO];
}
else if (effect === CPViewAnimationFadeOutEffect)
[view setAlphaValue:1.0];
@@ -100,7 +69,7 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOutEffect";
[super startAnimation];
}
- (void)setCurrentProgress:(CPAnimationProgress)progress
- (void)setCurrentProgress:(NSAnimationProgress)progress
{
[super setCurrentProgress:progress];
@@ -108,17 +77,17 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOutEffect";
while (animationIndex--)
{
var dictionary = [_viewAnimations objectAtIndex:animationIndex],
view = [self _targetView:dictionary],
startFrame = [self _startFrame:dictionary],
endFrame = [self _endFrame:dictionary],
differenceFrame = _CGRectMakeZero();
view = [self _targetView:dictionary]
startFrame = [self _startFrame:dictionary]
endFrame = [self _endFrame:dictionary]
differenceFrame = CPRectMakeZero();
differenceFrame.origin.x = endFrame.origin.x - startFrame.origin.x;
differenceFrame.origin.y = endFrame.origin.y - startFrame.origin.y;
differenceFrame.size.width = endFrame.size.width - startFrame.size.width;
differenceFrame.size.height = endFrame.size.height - startFrame.size.height;
var intermediateFrame = _CGRectMakeZero();
var intermediateFrame = CPRectMakeZero();
intermediateFrame.origin.x = startFrame.origin.x + differenceFrame.origin.x * progress;
intermediateFrame.origin.y = startFrame.origin.y + differenceFrame.origin.y * progress;
intermediateFrame.size.width = startFrame.size.width + differenceFrame.size.width * progress;
@@ -134,7 +103,7 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOutEffect";
[view setAlphaValue:1.0 + ( 0.0 - 1.0 ) * progress];
if (progress === 1.0)
[self _targetView:view setHidden:_CGRectIsNull(endFrame) || [view alphaValue] === 0.0];
[view setHidden:CPRectIsNull(endFrame) || [view alphaValue] === 0.0];
}
}
@@ -155,25 +124,12 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOutEffect";
else if (effect === CPViewAnimationFadeOutEffect)
[view setAlphaValue:0.0];
[self _targetView:view setHidden:_CGRectIsNull(endFrame) || [view alphaValue] === 0.0];
[view setHidden:CPRectIsNull(endFrame) || [view alphaValue] === 0.0];
}
[super stopAnimation];
}
- (void)_targetView:(id)theView setHidden:(BOOL)isHidden
{
if ([theView isKindOfClass:[CPWindow class]])
{
if (isHidden)
[theView orderOut:self];
else
[theView orderFront:self];
}
else
[theView setHidden:isHidden];
}
- (id)_targetView:(CPDictionary)dictionary
{
var targetView = [dictionary valueForKey:CPViewAnimationTargetKey];
@@ -183,7 +139,7 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOutEffect";
return targetView;
}
- (CGRect)_startFrame:(CPDictionary)dictionary
- (CPRect)_startFrame:(CPDictionary)dictionary
{
var startFrame = [dictionary valueForKey:CPViewAnimationStartFrameKey];
if (!startFrame)
@@ -192,7 +148,7 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOutEffect";
return startFrame;
}
- (CGRect)_endFrame:(CPDictionary)dictionary
- (CPRect)_endFrame:(CPDictionary)dictionary
{
var endFrame = [dictionary valueForKey:CPViewAnimationEndFrameKey];
if (!endFrame)
@@ -211,11 +167,6 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOutEffect";
return _viewAnimations;
}
/*!
Takes an array of CPDictionaries as documented in initWithViewAnimations:.
@param viewAnimations - An array of dictionaries describing the animation.
*/
- (void)setViewAnimations:(CPArray)viewAnimations
{
if (viewAnimations != _viewAnimations)

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