Merge branch 'jake'

Conflicts:
	Tools/press/objj-analysis-tools.j
This commit is contained in:
Francisco Tolmasky committed 2010-02-17 13:50:18 -08:00
commit 96ee92695c
463 files changed
+24904 -22625

No files matched your search

+1
View File
@@ -4,3 +4,4 @@ Build
Demos
./Aristo
WebSite
.push-package
-12
View File
@@ -1,12 +0,0 @@
[submodule "External/narwhal"]
path = External/narwhal
url = git://github.com/tlrobinson/narwhal.git
[submodule "External/jack"]
path = External/jack
url = git://github.com/tlrobinson/jack.git
[submodule "External/browserjs"]
path = External/browserjs
url = git://github.com/tlrobinson/browserjs.git
[submodule "External/ojunit"]
path = External/ojunit
url = git://github.com/280north/ojunit.git
+1
View File
@@ -43,6 +43,7 @@
@import "CPCompatibility.j"
@import "CPControl.j"
@import "CPCookie.j"
@import "CPCursor.j"
@import "CPDocument.j"
@import "CPDocumentController.j"
@import "CPEvent.j"
+21 -1
View File
@@ -197,6 +197,20 @@
return indexSet;
}
- (void)setEnabled:(BOOL)isEnabled forItemAtIndex:(CPInteger)anIndex
{
var itemView = _itemViews[anIndex];
if (!itemView)
return;
if (!isEnabled)
[self collapseItemAtIndex:anIndex];
else
[self expandItemAtIndex:anIndex];
[itemView setEnabled:isEnabled];
}
- (void)_invalidateItemsStartingAtIndex:(CPInteger)anIndex
{
if (_dirtyItemIndex === CPNotFound)
@@ -301,6 +315,12 @@
[_headerView setStringValue:aLabel];
}
- (void)setEnabled:(BOOL)isEnabled
{
if ([_headerView respondsToSelector:@selector(setEnabled:)])
[_headerView setEnabled:isEnabled];
}
- (void)setContentView:(CPView)aView
{
if (_contentView === aView)
@@ -312,7 +332,7 @@
_contentView = aView;
[_contentView addObserver:self forKeyPath:@"frame" options:0 context:NULL];
[_contentView addObserver:self forKeyPath:@"frame" options:CPKeyValueObservingOptionOld | CPKeyValueObservingOptionNew context:NULL];
[self addSubview:_contentView];
+6 -2
View File
@@ -148,8 +148,9 @@ var CPAlertWarningImage,
var button = _buttons[i];
[button setFrameSize:CGSizeMake([button frame].size.width, (styleMask == CPHUDBackgroundWindowMask) ? 20.0 : 24.0)];
[button setBezelStyle:(styleMask & CPHUDBackgroundWindowMask) ? CPHUDBezelStyle : CPRoundedBezelStyle];
[button setTheme:(_windowStyle === CPHUDBackgroundWindowMask) ? [CPTheme themeNamed:"Aristo-HUD"] : [CPTheme defaultTheme]];
[[_alertPanel contentView] addSubview:button];
}
@@ -161,6 +162,7 @@ var CPAlertWarningImage,
[_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)];
}
@@ -262,7 +264,9 @@ var CPAlertWarningImage,
[button setTag:_buttonCount];
[button setAction:@selector(_notifyDelegate:)];
[button setBezelStyle:(_windowStyle == CPHUDBackgroundWindowMask) ? CPHUDBezelStyle : CPRoundRectBezelStyle];
[button setTheme:(_windowStyle === CPHUDBackgroundWindowMask) ? [CPTheme themeNamed:"Aristo-HUD"] : [CPTheme defaultTheme]];
[button setAutoresizingMask:CPViewMinXMargin | CPViewMinYMargin];
[[_alertPanel contentView] addSubview:button];
if (_buttonCount == 0)
+150 -28
View File
@@ -96,6 +96,10 @@ CPRunContinuesResponse = -1002;
CPDictionary _namedArgs;
CPArray _args;
CPString _fullArgsString;
CPImage _applicationIconImage;
CPPanel _aboutPanel;
}
/*!
@@ -250,6 +254,14 @@ CPRunContinuesResponse = -1002;
*/
- (void)finishLaunching
{
// At this point we clear the window.status to eliminate Safari's "Cancelled" error message
// The message shouldn't be displayed, because only an XHR is cancelled, but it is a usability issue.
// We do it here so that applications can change it in willFinish or didFinishLaunching
window.status = " ";
// We also want to set the default cursor on the body, so that buttons and things don't have an iBeam
[[CPCursor arrowCursor] set];
var bundle = [CPBundle mainBundle],
types = [bundle objectForInfoDictionaryKey:@"CPBundleDocumentTypes"];
@@ -275,15 +287,15 @@ CPRunContinuesResponse = -1002;
postNotificationName:CPApplicationWillFinishLaunchingNotification
object:self];
var filename = window.cpOpeningFilename && window.cpOpeningFilename(),
needsUntitled = !!_documentController;
var needsUntitled = !!_documentController,
URLStrings = window.cpOpeningURLStrings && window.cpOpeningURLStrings(),
index = 0,
count = [URLStrings count];
if ([filename length])
{
needsUntitled = ![self _openFile:filename];
}
for (; index < count; ++index)
needsUntitled = ![self _openURL:[CPURL URLWithString:URLStrings[index]]] || needsUntitled;
if (needsUntitled && [_delegate respondsToSelector: @selector(applicationShouldOpenUntitledFile:)])
if (needsUntitled && [_delegate respondsToSelector:@selector(applicationShouldOpenUntitledFile:)])
needsUntitled = [_delegate applicationShouldOpenUntitledFile:self];
if (needsUntitled)
@@ -302,11 +314,88 @@ CPRunContinuesResponse = -1002;
- (void)terminate:(id)aSender
{
[[CPDocumentController sharedDocumentController] closeAllDocumentsWithDelegate:self
didCloseAllSelector:@selector(_documentController:didCloseAll:context:)
contextInfo:nil];
if (![CPPlatform isBrowser])
{
[[CPDocumentController sharedDocumentController] closeAllDocumentsWithDelegate:self
didCloseAllSelector:@selector(_documentController:didCloseAll:context:)
contextInfo:nil];
}
else
{
[[[self keyWindow] platformWindow] _propagateCurrentDOMEvent:YES];
}
}
- (void)setApplicationIconImage:(CPImage)anImage
{
_applicationIconImage = anImage;
}
- (CPImage)applicationIconImage
{
if (_applicationIconImage)
return _applicationIconImage;
var imagePath = [[CPBundle mainBundle] objectForInfoDictionaryKey:@"CPApplicationIcon"];
if (imagePath)
_applicationIconImage = [[CPImage alloc] initWithContentsOfFile:imagePath];
return _applicationIconImage;
}
- (void)orderFrontStandardAboutPanel:(id)sender
{
[self orderFrontStandardAboutPanelWithOptions:nil];
}
- (void)orderFrontStandardAboutPanelWithOptions:(CPDictionary)options
{
if (!_aboutPanel)
{
var mainInfo = [[CPBundle mainBundle] infoDictionary],
applicationTitle = [options objectForKey:"ApplicationName"] || [mainInfo objectForKey:@"CPBundleName"],
applicationIcon = [options objectForKey:@"ApplicationIcon"] || [self applicationIconImage],
version = [options objectForKey:@"Version"] || [mainInfo objectForKey:@"CPBundleVersion"],
applicationVersion = [options objectForKey:@"ApplicationVersion"] || [mainInfo objectForKey:@"CPBundleShortVersionString"],
copyright = [options objectForKey:@"Copyright"] || [mainInfo objectForKey:@"CPHumanReadableCopyright"];
var aboutPanelController = [[CPWindowController alloc] initWithWindowCibName:@"AboutPanel"],
aboutPanel = [aboutPanelController window],
contentView = [aboutPanel contentView],
imageView = [contentView viewWithTag:1],
applicationLabel = [contentView viewWithTag:2],
versionLabel = [contentView viewWithTag:3],
copyrightLabel = [contentView viewWithTag:4],
standardPath = [[CPBundle bundleForClass:[self class]] pathForResource:@"standardApplicationIcon.png"];
// FIXME move this into the CIB eventually
[applicationLabel setFont:[CPFont boldSystemFontOfSize:14.0]];
[applicationLabel setAlignment:CPCenterTextAlignment];
[versionLabel setAlignment:CPCenterTextAlignment];
[copyrightLabel setAlignment:CPCenterTextAlignment];
[imageView setImage:applicationIcon || [[CPImage alloc] initWithContentsOfFile:standardPath
size:CGSizeMake(256, 256)]];
[applicationLabel setStringValue:applicationTitle || ""];
if (version && applicationVersion)
[versionLabel setStringValue:sprintf(@"Version %@ (%@)", applicationVersion, version)];
else if (applicationVersion || version)
[versionLabel setStringValue:sprintf(@"Version %@", applicationVersion || version)];
else
[versionLabel setStringValue:@""];
[copyrightLabel setStringValue:copyright || ""];
[aboutPanel center];
_aboutPanel = aboutPanel;
}
[_aboutPanel orderFront:self];
}
- (void)_documentController:(NSDocumentController *)docController didCloseAll:(BOOL)didCloseAll context:(Object)info
{
// callback method for terminate:
@@ -333,6 +422,11 @@ CPRunContinuesResponse = -1002;
[CPPlatform activateIgnoringOtherApps:shouldIgnoreOtherApps];
}
- (void)hideOtherApplications:(id)aSender
{
[CPPlatform hideOtherApplications:self];
}
/*!
Calls \c -finishLaunching method which results in starting
the main event loop.
@@ -457,13 +551,28 @@ CPRunContinuesResponse = -1002;
{
_currentEvent = anEvent;
var willPropagate = [[[anEvent window] platformWindow] _willPropagateCurrentDOMEvent];
// temporarily pretend we won't propagate the event. we'll restore the saved value later
// we do this outside the if so that changes user code might make in _handleKeyEquiv. are preserved
[[[anEvent window] platformWindow] _propagateCurrentDOMEvent:NO];
// Check if this is a candidate for key equivalent...
if ([anEvent _couldBeKeyEquivalent] && [self _handleKeyEquivalent:anEvent])
{
[[[anEvent window] platformWindow] _propagateCurrentDOMEvent:NO];
var characters = [anEvent characters],
modifierFlags = [anEvent modifierFlags];
// Unconditionally propagate on these keys to solve browser copy paste bugs
if ((characters == "c" || characters == "x" || characters == "v") && (modifierFlags & CPPlatformActionKeyMask))
[[[anEvent window] platformWindow] _propagateCurrentDOMEvent:YES];
return;
}
// if we make it this far, then restore the original willPropagate value
[[[anEvent window] platformWindow] _propagateCurrentDOMEvent:willPropagate];
if (_eventListeners.length)
{
if (_eventListeners[_eventListeners.length - 1]._mask & (1 << [anEvent type]))
@@ -515,6 +624,11 @@ CPRunContinuesResponse = -1002;
return _windows;
}
- (void)hide:(id)aSender
{
[CPPlatform hide:self];
}
// Accessing the Main Menu
/*!
Returns the application's main menu
@@ -549,16 +663,6 @@ CPRunContinuesResponse = -1002;
[[CPColorPanel sharedColorPanel] orderFront:self];
}
- (void)orderFrontStandardAboutPanel:(id)aSender
{
[self orderFrontStandardAboutPanelWithOptions:nil];
}
- (void)orderFrontStandardAboutPanelWithOptions:(CPDictionary)aDictionary
{
// FIXME: Implement.
}
// Posting Actions
/*!
Tries to perform the action with an argument. Performs
@@ -597,7 +701,7 @@ CPRunContinuesResponse = -1002;
- (BOOL)sendAction:(SEL)anAction to:(id)aTarget from:(id)aSender
{
var target = [self targetForAction:anAction to:aTarget from:aSender];
if (!target)
return NO;
@@ -759,6 +863,7 @@ CPRunContinuesResponse = -1002;
return;
}
[aWindow orderFront:self];
[aWindow _attachSheet:aSheet modalDelegate:aModalDelegate didEndSelector:aDidEndSelector contextInfo:aContextInfo];
}
@@ -834,12 +939,18 @@ CPRunContinuesResponse = -1002;
return _namedArgs;
}
- (BOOL)_openFile:(CPString)aFilename
- (BOOL)_openURL:(CPURL)aURL
{
if (_delegate && [_delegate respondsToSelector:@selector(application:openFile:)])
return [_delegate application:self openFile:aFilename];
else
return [_documentController openDocumentWithContentsOfURL:aFilename display:YES error:NULL];
{
CPLog.warn("application:openFile: is deprecated, use application:openURL: instead.");
return [_delegate application:self openFile:[aURL absoluteString]];
}
if (_delegate && [_delegate respondsToSelector:@selector(application:openURL:)])
return [_delegate application:self openURL:aURL];
return !![_documentController openDocumentWithContentsOfURL:aURL display:YES error:NULL];
}
- (void)_didResignActive
@@ -848,6 +959,12 @@ CPRunContinuesResponse = -1002;
[self._activeMenu cancelTracking];
}
+ (CPString)defaultThemeName
{
// FIXME: don't hardcode
return ([[CPBundle mainBundle] objectForInfoDictionaryKey:"CPDefaultTheme"] || @"Aristo");
}
@end
var _CPModalSessionMake = function(aWindow, aStopCode)
@@ -952,7 +1069,7 @@ var _CPAppBootstrapperActions = nil;
+ (BOOL)loadDefaultTheme
{
var blend = [[CPThemeBlend alloc] initWithContentsOfURL:[[CPBundle bundleForClass:[CPApplication class]] pathForResource:@"Aristo.blend"]];
var blend = [[CPThemeBlend alloc] initWithContentsOfURL:[[CPBundle bundleForClass:[CPApplication class]] pathForResource:[CPApplication defaultThemeName] + ".blend"]];
[blend loadWithDelegate:self];
@@ -961,7 +1078,7 @@ var _CPAppBootstrapperActions = nil;
+ (void)blendDidFinishLoading:(CPBundle)aBundle
{
[CPTheme setDefaultTheme:[CPTheme themeNamed:@"Aristo"]];
[CPTheme setDefaultTheme:[CPTheme themeNamed:[CPApplication defaultThemeName]]];
[self performActions];
}
@@ -988,4 +1105,9 @@ var _CPAppBootstrapperActions = nil;
[self performActions];
}
+ (void)reset
{
_CPAppBootstrapperActions = nil;
}
@end
+4 -4
View File
@@ -145,7 +145,7 @@ CPButtonStateMixed = CPThemeState("mixed");
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[_CGInsetMakeZero(), _CGInsetMakeZero(), nil]
return [CPDictionary dictionaryWithObjects:[_CGInsetMakeZero(), _CGInsetMakeZero(), [CPNull null]]
forKeys:[@"bezel-inset", @"content-inset", @"bezel-color"]];
}
@@ -192,8 +192,8 @@ CPButtonStateMixed = CPThemeState("mixed");
_allowsMixedState = aFlag;
if (!_allowsMixedState)
[self unsetThemeState:CPButtonStateMixed];
if (!_allowsMixedState && [self state] === CPMixedState)
[self setState:CPOnState];
}
- (void)setObjectValue:(id)anObjectValue
@@ -460,7 +460,7 @@ CPButtonStateMixed = CPThemeState("mixed");
return bounds;
}
- (CGRect)bezelRectForBounds:(CFRect)bounds
- (CGRect)bezelRectForBounds:(CGRect)bounds
{
if (![self isBordered])
return _CGRectMakeZero();
+11 -1
View File
@@ -8,6 +8,16 @@
{
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
[self setNeedsLayout];
return self;
}
+ (CPString)themeClass
{
return @"button-bar";
@@ -15,7 +25,7 @@
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[nil]
return [CPDictionary dictionaryWithObjects:[[CPNull null]]
forKeys:[@"bezel-color"]];
}
+105 -2
View File
@@ -321,7 +321,7 @@
*/
- (CPIndexSet)selectionIndexes
{
return _selectionIndexes;
return [_selectionIndexes copy];
}
/* @ignore */
@@ -333,6 +333,8 @@
while (count--)
{
[[_items[count] view] removeFromSuperview];
[_items[count] setSelected:NO];
_cachedItems.push(_items[count]);
}
@@ -351,7 +353,11 @@
[self addSubview:[_items[index] view]];
}
index = CPNotFound;
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound)
[_items[index] setSelected:YES];
[self tile];
}
@@ -672,6 +678,103 @@
@end
@implementation CPCollectionView (KeyboardInteraction)
- (CGRect)rectForItemAtIndex:(int)index
{
// Don't re-compute anything just grab the current frame
// This allows subclasses to override tile without messing this up.
return [[_items[index] view] frame];
}
- (CGRect)rectForItemsAtIndexes:(CPIndexSet)indexSet
{
var indexArray = [],
rect = nil;
[indexSet getIndexes:indexArray maxCount:-1 inIndexRange:nil];
for (var i = 0, count = indexArray.length; i < count; ++i)
{
var index = indexArray[i];
if (rect == nil)
rect = [self rectForItemAtIndex:index];
else
rect = CGRectUnion(rect, [self rectForItemAtIndex:index]);
}
return rect;
}
- (void)_scrollToSelection
{
var rect = [self rectForItemsAtIndexes:[self selectionIndexes]];
if (rect)
[self scrollRectToVisible:rect];
}
- (void)moveLeft:(id)sender
{
var index = [[self selectionIndexes] firstIndex];
if (index === CPNotFound)
index = [[self items] count];
index = MAX(index - 1, 0);
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
[self _scrollToSelection];
}
- (void)moveRight:(id)sender
{
var index = MIN([[self selectionIndexes] firstIndex] + 1, [[self items] count]-1);
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
[self _scrollToSelection];
}
- (void)moveDown:(id)sender
{
var index = MIN([[self selectionIndexes] firstIndex] + [self numberOfColumns], [[self items] count]-1);
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
[self _scrollToSelection];
}
- (void)moveUp:(id)sender
{
var index = [[self selectionIndexes] firstIndex];
if (index == CPNotFound)
index = [[self items] count];
index = MAX(0, index - [self numberOfColumns]);
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
[self _scrollToSelection];
}
- (void)deleteBackwards:(id)sender
{
if ([[self delegate] respondsToSelector:@selector(collectionView:shouldDeleteItemsAtIndexes:)])
{
[[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]];
[self _scrollToSelection];
[self setNeedsDisplay:YES];
}
}
- (void)keyDown:(CPEvent)anEvent
{
[self interpretKeyEvents:[anEvent]];
}
@end
var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeKey",
CPCollectionViewMaxItemSizeKey = @"CPCollectionViewMaxItemSizeKey",
CPCollectionViewVerticalMarginKey = @"CPCollectionViewVerticalMarginKey",
+3
View File
@@ -735,6 +735,9 @@ var CPColorComponentsKey = @"CPColorComponentsKey",
var hexCharacters = "0123456789ABCDEF";
// HACK: prevent these from becoming globals. workaround for obj-j "function foo(){}" behavior
var hexToRGB, integerToBytes, rgbToHex, byteToHex;
/*!
Used for the CPColor \c +colorWithHexString: implementation
@ignore
+10 -9
View File
@@ -140,7 +140,7 @@ CPColorPickerViewHeight = 370;
Sets the color of the panel, and updates the picker. Also posts a \c CPColorPanelDidChangeNotification.
*/
- (void)setColor:(CPColor)aColor
{
{
_color = aColor;
[_previewView setBackgroundColor: _color];
@@ -518,9 +518,10 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
- (void)mouseUp:(CPEvent)anEvent
{
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil],
bounds = [self bounds];
if(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];
@@ -563,7 +564,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
{
if(aType == CPColorDragType)
[aPasteboard setData:_dragColor forType:aType];
[aPasteboard setData:[CPKeyedArchiver archivedDataWithRootObject:_dragColor] forType:aType];
}
- (void)performDragOperation:(id <CPDraggingInfo>)aSender
@@ -575,7 +576,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
if(![pasteboard availableTypeFromArray:[CPColorDragType]] || location.x > [self bounds].size.width - 1 || location.x < 1)
return NO;
[self setColor:[pasteboard dataForType:CPColorDragType] atIndex: FLOOR(location.x / 13)];
[self setColor:[CPKeyedUnarchiver unarchiveObjectWithData:[pasteboard dataForType:CPColorDragType]] atIndex: FLOOR(location.x / 13)];
}
@end
@@ -612,8 +613,8 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
if(![pasteboard availableTypeFromArray:[CPColorDragType]])
return NO;
var color = [pasteboard dataForType:CPColorDragType];
[_colorPanel setColor: color updatePicker: YES];
var color = [CPKeyedUnarchiver unarchiveObjectWithData:[pasteboard dataForType:CPColorDragType]];
[_colorPanel setColor:color updatePicker:YES];
}
- (BOOL)isOpaque
@@ -625,7 +626,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
{
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:[CPArray arrayWithObject:CPColorDragType] owner:self];
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:[CPColorDragType] owner:self];
var bounds = CPRectMake(0, 0, 15, 15);
@@ -650,7 +651,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
{
if(aType == CPColorDragType)
[aPasteboard setData:[self backgroundColor] forType:aType];
[aPasteboard setData:[CPKeyedArchiver archivedDataWithRootObject:[self backgroundColor]] forType:aType];
}
@end
+33 -3
View File
@@ -21,6 +21,7 @@
*/
@import "CPEvent.j"
@import "CPPlatform.j"
// Browser Engines
CPUnknownBrowserEngine = 0;
@@ -30,6 +31,11 @@ CPKHTMLBrowserEngine = 3;
CPOperaBrowserEngine = 4;
CPWebKitBrowserEngine = 5;
// Operating Systems
CPMacOperatingSystem = 0;
CPWindowsOperatingSystem = 1;
CPOtherOperatingSystem = 2;
// Features
CPCSSRGBAFeature = 1 << 5;
@@ -56,6 +62,7 @@ CPOpacityRequiresFilterFeature = 1 << 24;
//Internet explorer does not allow dynamically changing the type of an input element
CPInputTypeCanBeChangedFeature = 1 << 25;
CPHTML5DragAndDropSourceYOffBy1 = 1 << 26;
@@ -102,7 +109,10 @@ else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
// Features we can only be sure of with WebKit (no known independent tests)
PLATFORM_FEATURES |= CPCSSRGBAFeature;
PLATFORM_FEATURES |= CPHTMLContentEditableFeature;
PLATFORM_FEATURES |= CPHTMLDragAndDropFeature;
if (USER_AGENT.indexOf("Chrome") === -1)
PLATFORM_FEATURES |= CPHTMLDragAndDropFeature;
PLATFORM_FEATURES |= CPJavascriptClipboardEventsFeature;
PLATFORM_FEATURES |= CPJavascriptClipboardAccessFeature;
PLATFORM_FEATURES |= CPJavaScriptShadowFeature;
@@ -116,6 +126,14 @@ else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
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;
if (majorVersion < 532 || (majorVersion === 532 && minorVersion < 6))
PLATFORM_FEATURES |= CPHTML5DragAndDropSourceYOffBy1;
}
// KHTML
@@ -173,11 +191,20 @@ function CPFeatureIsCompatible(aFeature)
function CPBrowserIsEngine(anEngine)
{
return PLATFORM_ENGINE == anEngine;
return PLATFORM_ENGINE === anEngine;
}
if (USER_AGENT.indexOf("Mac") != -1)
function CPBrowserIsOperatingSystem(anOperatingSystem)
{
return OPERATING_SYSTEM === anOperatingSystem;
}
OPERATING_SYSTEM = CPOtherOperatingSystem;
if (USER_AGENT.indexOf("Mac") !== -1)
{
OPERATING_SYSTEM = CPMacOperatingSystem;
CPPlatformActionKeyMask = CPCommandKeyMask;
CPUndoKeyEquivalent = @"Z";
@@ -188,6 +215,9 @@ if (USER_AGENT.indexOf("Mac") != -1)
}
else
{
if (USER_AGENT.indexOf("Windows") !== -1)
OPERATING_SYSTEM = CPWindowsOperatingSystem;
CPPlatformActionKeyMask = CPControlKeyMask;
CPUndoKeyEquivalent = @"Z";
+29 -42
View File
@@ -27,47 +27,22 @@
#include "CoreGraphics/CGGeometry.h"
#include "Platform/Platform.h"
/*
@global
@group CPTextAlignment
*/
CPLeftTextAlignment = 0;
/*
@global
@group CPTextAlignment
*/
CPRightTextAlignment = 1;
/*
@global
@group CPTextAlignment
*/
CPCenterTextAlignment = 2;
/*
@global
@group CPTextAlignment
*/
CPJustifiedTextAlignment = 3;
/*
@global
@group CPTextAlignment
*/
CPNaturalTextAlignment = 4;
CPLeftTextAlignment = 0;
CPRightTextAlignment = 1;
CPCenterTextAlignment = 2;
CPJustifiedTextAlignment = 3;
CPNaturalTextAlignment = 4;
/*
@global
@group CPControlSize
*/
CPRegularControlSize = 0;
/*
@global
@group CPControlSize
*/
CPSmallControlSize = 1;
/*
@global
@group CPControlSize
*/
CPMiniControlSize = 2;
CPRegularControlSize = 0;
CPSmallControlSize = 1;
CPMiniControlSize = 2;
CPLineBreakByWordWrapping = 0;
CPLineBreakByCharWrapping = 1;
CPLineBreakByClipping = 2;
CPLineBreakByTruncatingHead = 3;
CPLineBreakByTruncatingTail = 4;
CPLineBreakByTruncatingMiddle = 5;
CPControlNormalBackgroundColor = "CPControlNormalBackgroundColor";
CPControlSelectedBackgroundColor = "CPControlSelectedBackgroundColor";
@@ -112,7 +87,7 @@ var CPControlBlackColor = [CPColor blackColor];
CPLineBreakByClipping,
[CPColor blackColor],
[CPFont systemFontOfSize:12.0],
nil,
[CPNull null],
_CGSizeMakeZero(),
CPImageLeft,
CPScaleToFit,
@@ -308,6 +283,12 @@ var CPControlBlackColor = [CPColor blackColor];
[self highlight:YES];
[self setState:[self nextState]];
[self sendAction:[self action] to:[self target]];
[CPTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(unhighlightButtonTimerDidFinish:) userInfo:nil repeats:NO];
}
- (void)unhighlightButtonTimerDidFinish:(id)sender
{
[self highlight:NO];
}
@@ -572,7 +553,9 @@ var CPControlValueKey = "CPControlValueKey",
CPControlTargetKey = "CPControlTargetKey",
CPControlActionKey = "CPControlActionKey",
CPControlSendActionOnKey = "CPControlSendActionOnKey";
CPControlSendActionOnKey = "CPControlSendActionOnKey",
CPControlSendsActionOnEndEditingKey = "CPControlSendsActionOnEndEditingKey";
var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
@@ -595,6 +578,7 @@ var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
[self setAction:[aCoder decodeObjectForKey:CPControlActionKey]];
[self sendActionOn:[aCoder decodeIntForKey:CPControlSendActionOnKey]];
[self setSendsActionOnEndEditing:[aCoder decodeBoolForKey:CPControlSendsActionOnEndEditingKey]];
}
return self;
@@ -608,6 +592,9 @@ var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
{
[super encodeWithCoder:aCoder];
if (_sendsActionOnEndEditing)
[aCoder encodeBool:_sendsActionOnEndEditing forKey:CPControlSendsActionOnEndEditingKey];
if (_value !== nil)
[aCoder encodeObject:_value forKey:CPControlValueKey];
+274
View File
@@ -0,0 +1,274 @@
/*
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
*/
#include "Platform/Platform.h"
var currentCursor = nil,
cursorStack = [],
cursors = {},
cursorURLFormat = nil;
@implementation CPCursor : CPObject
{
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])
_cssString = aString;
return self;
}
+ (CPCursor)cursorWithCSSString:(CPString)cssString
{
var cursor = cursors[cssString];
if (typeof cursor == 'undefined')
{
cursor = [[CPCursor alloc] initWithCSSString:cssString];
cursors[cssString] = cursor;
}
return cursor;
}
+ (CPCursor)cursorWithImageNamed:(CPString)imageName
{
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
{
[self _setCursorCSS:"none"]; // Not supported in IE
}
+ (void)unhide
{
[self _setCursorCSS:[currentCursor _cssString]]
}
+ (void)setHiddenUntilMouseMoves:(BOOL)flag
{
if (flag)
[CPCursor hide];
else
[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)
[CPPlatformWindow primaryPlatformWindow]._DOMBodyElement.style.cursor = aString;
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];
}
+ (void)pop
{
if (cursorStack.length > 1)
{
cursorStack.pop();
currentCursor = cursorStack[cursorStack.length - 1];
}
}
- (id)initWithCoder:(CPCoder)coder
{
if (self = [super init])
_cssString = [coder decodeObjectForKey:@"CPCursorNameKey"];
return self;
}
- (void)encodeWithCoder:(CPCoder)coder
{
[coder encodeObject:_cssString forKey:@"CPCursorNameKey"];
}
@end
+7 -3
View File
@@ -280,7 +280,11 @@ var CPDocumentUntitledCount = 0;
else if (viewController)
{
var view = [viewController view],
theWindow = [[CPWindow alloc] initWithContentRect:[view frame] styleMask:CPTitledWindowMask | CPClosableWindowMask | CPMiniaturizableWindowMask | CPResizableWindowMask];
viewFrame = [view frame];
viewFrame.origin = CGPointMake(50, 50);
var theWindow = [[CPWindow alloc] initWithContentRect:viewFrame styleMask:CPTitledWindowMask | CPClosableWindowMask | CPMiniaturizableWindowMask | CPResizableWindowMask];
windowController = [[CPWindowController alloc] initWithWindow:theWindow];
}
@@ -480,7 +484,7 @@ var CPDocumentUntitledCount = 0;
else
[_writeRequest setHTTPMethod:@"PUT"];
[_writeRequest setHTTPBody:[data string]];
[_writeRequest setHTTPBody:[data encodedString]];
[_writeRequest setValue:@"close" forHTTPHeaderField:@"Connection"];
@@ -563,7 +567,7 @@ var CPDocumentUntitledCount = 0;
// READ
if (aConnection == _readConnection)
{
[self readFromData:[CPData dataWithString:aData] ofType:session.fileType error:nil];
[self readFromData:[CPData dataWithEncodedString:aData] ofType:session.fileType error:nil];
objj_msgSend(session.delegate, session.didReadSelector, self, YES, session.contextInfo);
}
+12 -5
View File
@@ -146,6 +146,8 @@ var CPSharedDocumentController = nil;
result = [self makeDocumentWithContentsOfURL:anAbsoluteURL ofType:type delegate:self didReadSelector:@selector(document:didRead:contextInfo:) contextInfo:[CPDictionary dictionaryWithObject:shouldDisplay forKey:@"shouldDisplay"]];
[self addDocument:result];
if (result)
[self noteNewRecentDocument:result];
}
@@ -207,7 +209,6 @@ var CPSharedDocumentController = nil;
if (!didRead)
return;
[self addDocument:aDocument];
[aDocument makeWindowControllers];
if ([aContextInfo objectForKey:@"shouldDisplay"])
@@ -276,7 +277,8 @@ var CPSharedDocumentController = nil;
var index = 0,
count = _documentTypes.length,
extension = [[anAbsoluteURL pathExtension] lowercaseString];
extension = [[anAbsoluteURL pathExtension] lowercaseString],
starType = nil;
for (; index < count; ++index)
{
@@ -286,12 +288,17 @@ var CPSharedDocumentController = nil;
extensionCount = extensions.length;
for (; extensionIndex < extensionCount; ++extensionIndex)
if ([extensions[extensionIndex] lowercaseString] == extension)
{
var thisExtension = [extensions[extensionIndex] lowercaseString];
if (thisExtension === extension)
return [documentType objectForKey:@"CPBundleTypeName"];
if (thisExtension === "****")
starType = [documentType objectForKey:@"CPBundleTypeName"];
}
}
// FIXME?
return [self defaultType];//nil;
return starType || [self defaultType];
}
// Managing Document Types
+10 -5
View File
@@ -189,6 +189,11 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
return self;
}
- (id)draggingDestination
{
return _draggingDestination;
}
- (CGPoint)draggingLocation
{
return _draggingLocation
@@ -251,7 +256,7 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
return dragOperation;
}
- (void)draggingEndedInPlatformWindow:(CPPlatformWindow)aPlatformWindow globalLocation:(CGPoint)aLocation
- (void)draggingEndedInPlatformWindow:(CPPlatformWindow)aPlatformWindow globalLocation:(CGPoint)aLocation operation:(CPDragOperation)anOperation
{
[_draggedView removeFromSuperview];
@@ -259,10 +264,10 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
[_draggedWindow orderOut:self];
if (_implementedDraggingSourceMethods & CPDraggingSource_draggedImage_endAt_operation_)
[_draggingSource draggedImage:[_draggedView image] endedAt:aLocation operation:NO];
[_draggingSource draggedImage:[_draggedView image] endedAt:aLocation operation:anOperation];
else if (_implementedDraggingSourceMethods & CPDraggingSource_draggedView_endedAt_operation_)
[_draggingSource draggedView:_draggedView endedAt:aLocation operation:NO];
[_draggingSource draggedView:_draggedView endedAt:aLocation operation:anOperation];
_isDragging = NO;
}
@@ -310,7 +315,7 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
_draggingOffset = _CGSizeMake(mouseDownEventLocation.x - viewLocation.x, mouseDownEventLocation.y - viewLocation.y);
}
else
_draggingOffset = _CGSizeMakerZero();
_draggingOffset = _CGSizeMakeZero();
if ([CPPlatform isBrowser])
[_draggedWindow setPlatformWindow:[aWindow platformWindow]];
@@ -386,7 +391,7 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
if (type === CPLeftMouseUp)
{
[self performDragOperationInPlatformWindow:platformWindow];
[self draggingEndedInPlatformWindow:platformWindow globalLocation:platformWindowLocation];
[self draggingEndedInPlatformWindow:platformWindow globalLocation:platformWindowLocation operation:CPDragOperationNone];
// Stop tracking events.
return;
+11 -84
View File
@@ -25,110 +25,26 @@
#include "CoreGraphics/CGGeometry.h"
/*
@global
@group CPEventType
*/
CPLeftMouseDown = 1;
/*
@global
@group CPEventType
*/
CPLeftMouseUp = 2;
/*
@global
@group CPEventType
*/
CPRightMouseDown = 3;
/*
@global
@group CPEventType
*/
CPRightMouseUp = 4;
/*
@global
@group CPEventType
*/
CPMouseMoved = 5;
/*
@global
@group CPEventType
*/
CPLeftMouseDragged = 6;
/*
@global
@group CPEventType
*/
CPRightMouseDragged = 7;
/*
@global
@group CPEventType
*/
CPMouseEntered = 8;
/*
@global
@group CPEventType
*/
CPMouseExited = 9;
/*
@global
@group CPEventType
*/
CPKeyDown = 10;
/*
@global
@group CPEventType
*/
CPKeyUp = 11;
/*
@global
@group CPEventType
*/
CPFlagsChanged = 12;
/*
@global
@group CPEventType
*/
CPAppKitDefined = 13;
/*
@global
@group CPEventType
*/
CPSystemDefined = 14;
/*
@global
@group CPEventType
*/
CPApplicationDefined = 15;
/*
@global
@group CPEventType
*/
CPPeriodic = 16;
/*
@global
@group CPEventType
*/
CPCursorUpdate = 17;
/*
@global
@group CPEventType
*/
CPScrollWheel = 22;
/*
@global
@group CPEventType
*/
CPOtherMouseDown = 25;
/*
@global
@group CPEventType
*/
CPOtherMouseUp = 26;
/*
@global
@group CPEventType
*/
CPOtherMouseDragged = 27;
// iPhone Event Types
@@ -369,6 +285,17 @@ var _CPEventPeriodicEventPeriod = 0,
return _CGPointMakeCopy(_location);
}
- (CGPoint)globalLocation
{
var theWindow = [self window],
location = [self locationInWindow];
if (theWindow)
return [theWindow convertBaseToGlobal:location];
return location;
}
/*!
Returns event information as a bit mask
*/
+28 -5
View File
@@ -30,7 +30,7 @@
*/
@implementation CPFlashMovie : CPObject
{
CPString _fileName;
CPString _filename;
}
/*!
@@ -38,9 +38,9 @@
@param aFilename the swf to load
@return the initialized CPFlashMovie
*/
+ (id)flashMovieWithFile:(CPString)aFileName
+ (id)flashMovieWithFile:(CPString)aFilename
{
return [[self alloc] initWithFile:aFileName];
return [[self alloc] initWithFile:aFilename];
}
/*!
@@ -48,14 +48,37 @@
@param aFilename the swf to load
@return the initialized CPFlashMovie
*/
- (id)initWithFile:(CPString)aFileName
- (id)initWithFile:(CPString)aFilename
{
self = [super init];
if (self)
_fileName = aFileName;
_filename = aFilename;
return self;
}
- (CPString)filename
{
return _filename;
}
@end
var CPFlashMovieFilenameKey = "CPFlashMovieFilenameKey";
@implementation CPFlashMovie (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
_filename = [aCoder decodeObjectForKey:CPFlashMovieFilenameKey];
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[aCoder encodeObject:_filename forKey:CPFlashMovieFilenameKey];
}
@end
+118 -35
View File
@@ -24,6 +24,8 @@
@import "CPView.j"
var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
/*!
@ingroup appkit
*/
@@ -31,9 +33,12 @@
{
CPFlashMovie _flashMovie;
DOMElement _DOMEmbedElement;
DOMElement _DOMMParamElement;
CPDictionary _params;
CPDictionary _paramElements;
DOMElement _DOMParamElement;
DOMElement _DOMObjectElement;
DOMElement _DOMInnerObjectElement;
}
- (id)initWithFrame:(CGRect)aFrame
@@ -42,35 +47,30 @@
if (self)
{
_DOMObjectElement = document.createElement("object");
_DOMObjectElement.width = "100%";
_DOMObjectElement.height = "100%";
_DOMObjectElement.style.top = "0px";
_DOMObjectElement.style.left = "0px";
_DOMParamElement = document.createElement("param");
_DOMParamElement.name = "movie";
_DOMObjectElement.appendChild(_DOMParamElement);
var param = document.createElement("param");
param.name = "wmode";
param.value = "transparent";
_DOMObjectElement.appendChild(param);
_DOMEmbedElement = document.createElement("embed");
_DOMEmbedElement.type = "application/x-shockwave-flash";
_DOMEmbedElement.setAttribute("wmode", "transparent");
_DOMEmbedElement.width = "100%";
_DOMEmbedElement.height = "100%";
// IE requires this thing to be in the _DOMElement and not the _DOMObjectElement.
_DOMElement.appendChild(_DOMEmbedElement);
_DOMElement.appendChild(_DOMObjectElement);
if (!CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
{
_DOMObjectElement = document.createElement(@"object");
_DOMObjectElement.width = @"100%";
_DOMObjectElement.height = @"100%";
_DOMObjectElement.style.top = @"0px";
_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];
}
return self;
@@ -83,10 +83,13 @@
_flashMovie = aFlashMovie;
_DOMParamElement.value = aFlashMovie._fileName;
if (_DOMEmbedElement)
_DOMEmbedElement.src = aFlashMovie._fileName;
if (!CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
{
_DOMParamElement.value = [aFlashMovie filename];
_DOMInnerObjectElement.data = [aFlashMovie filename];
}
else
[self _rebuildIEObjects];
}
- (CPFlashMovie)flashMovie
@@ -94,6 +97,86 @@
return _flashMovie;
}
- (void)setFlashVars:(CPDictionary)aDictionary
{
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];
}
- (CPDictionary)flashVars
{
return [_params objectForKey:@"flashvars"];
}
- (void)setParameters:(CPDictionary)aDictionary
{
if (_paramElements && !CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
{
var elements = [_paramElements allValues],
count = [elements count];
for (var i = 0; i < count; i++)
_DOMObjectElement.removeChild([elements objectAtIndex:i]);
}
_params = aDictionary;
if (!CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
{
_paramElements = [CPDictionary dictionary];
var enumerator = [_params keyEnumerator],
key;
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];
}
}
else
[self _rebuildIEObjects];
}
- (CPDictionary)parameters
{
return _params;
}
- (void)_rebuildIEObjects
{
_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];
}
- (void)mouseDragged:(CPEvent)anEvent
{
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
+8 -5
View File
@@ -20,10 +20,13 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
var _CPFonts = {};
_CPFontSystemFontFace = @"Arial";
var _CPFonts = {},
_CPFontSystemFontFace = @"Arial, sans-serif",
_CPWrapRegExp = new RegExp("\\s*,\\s*", "g");
#define _CPCachedFont(aName, aSize, isBold) _CPFonts[(isBold ? @"bold " : @"") + ROUND(aSize) + @"px '" + aName + @"'"]
#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
@@ -95,7 +98,7 @@ var _CPFonts = {};
_size = aSize;
_isBold = isBold;
_cssString = (_isBold ? @"bold " : @"") + ROUND(aSize) + @"px '" + aName + @"'";
_cssString = _CPCreateCSSString(_name, _size, _isBold);
_CPFonts[_cssString] = self;
}
@@ -158,4 +161,4 @@ var CPFontNameKey = @"CPFontNameKey",
[aCoder encodeBool:_isBold forKey:CPFontIsBoldKey];
}
@end
@end
+2 -2
View File
@@ -234,9 +234,9 @@ function CPRectContainsPoint(aRect, aPoint)
@param possibleInner the CGRect to test if it fits inside \c possibleOuter.
@return BOOL \c YES if \c possibleInner fits inside \c possibleOuter.
*/
function CPRectContainsRect(lhsRect, rhsRect)
function CPRectContainsRect(possibleOuter, possibleInner)
{
return CPRectEqualToRect(CPUnionRect(lhsRect, rhsRect), rhsRect);
return CGRectContainsRect(possibleOuter, possibleInner);
}
/*!
+86 -33
View File
@@ -19,7 +19,7 @@
* 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/CPBundle.j>
@import <Foundation/CPNotificationCenter.j>
@import <Foundation/CPObject.j>
@@ -28,6 +28,9 @@
@import "CPGeometry.j"
#include "Platform/DOM.h"
CPImageLoadStatusInitialized = 0;
CPImageLoadStatusLoading = 1;
CPImageLoadStatusCompleted = 2;
@@ -38,26 +41,32 @@ CPImageLoadStatusReadError = 6;
CPImageDidLoadNotification = @"CPImageDidLoadNotification";
// Image Names
CPImageNameColorPanel = @"CPImageNameColorPanel";
CPImageNameColorPanelHighlighted = @"CPImageNameColorPanelHighlighted";
var imagesForNames = { },
AppKitImageForNames = { };
AppKitImageForNames[CPImageNameColorPanel] = CGSizeMake(26.0, 29.0);
AppKitImageForNames[CPImageNameColorPanelHighlighted] = CGSizeMake(26.0, 29.0);
function CPImageInBundle(aFilename, aSize, aBundle)
{
if (!aBundle)
aBundle = [CPBundle mainBundle];
if (aSize)
return [[CPImage alloc] initWithContentsOfFile:[aBundle pathForResource:aFilename] size:aSize];
return [[CPImage alloc] initWithContentsOfFile:[aBundle pathForResource:aFilename]];
}
@implementation CPBundle (CPImageAdditions)
- (CPString)pathForResource:(CPString)aFilename
function CPAppKitImage(aFilename, aSize)
{
return [self resourcePath] + '/' + aFilename;
return CPImageInBundle(aFilename, aSize, [CPBundle bundleForClass:[CPView class]]);
}
@end
/*!
@ingroup appkit
@class CPImage
@@ -83,10 +92,11 @@ function CPImageInBundle(aFilename, aSize, aBundle)
{
CGSize _size;
CPString _filename;
CPString _name;
id _delegate;
unsigned _loadStatus;
Image _image;
}
@@ -106,14 +116,14 @@ function CPImageInBundle(aFilename, aSize, aBundle)
- (id)initByReferencingFile:(CPString)aFilename size:(CGSize)aSize
{
self = [super init];
if (self)
{
_size = CPSizeCreateCopy(aSize);
_filename = aFilename;
_loadStatus = CPImageLoadStatusInitialized;
}
return self;
}
@@ -126,10 +136,10 @@ function CPImageInBundle(aFilename, aSize, aBundle)
- (id)initWithContentsOfFile:(CPString)aFilename size:(CGSize)aSize
{
self = [self initByReferencingFile:aFilename size:aSize];
if (self)
[self load];
return self;
}
@@ -142,10 +152,10 @@ function CPImageInBundle(aFilename, aSize, aBundle)
- (id)initWithContentsOfFile:(CPString)aFilename
{
self = [self initByReferencingFile:aFilename size:CGSizeMake(-1, -1)];
if (self)
[self load];
return self;
}
@@ -174,6 +184,45 @@ function CPImageInBundle(aFilename, aSize, aBundle)
return _size;
}
+ (id)imageNamed:(CPString)aName
{
var image = imagesForNames[aName];
if (image)
return image;
var imageOrSize = AppKitImageForNames[aName];
if (!imageOrSize.isa)
{
imageOrSize = CPAppKitImage("CPImage/" + aName + ".png", imageOrSize);
[imageOrSize setName:aName];
AppKitImageForNames[aName] = imageOrSize;
}
return imageOrSize;
}
- (void)setName:(CPString)aName
{
if (_name === aName)
return;
if (imagesForNames[aName] === self)
imagesForNames[aName] = nil;
_name = aName;
imagesForNames[aName] = self;
}
- (CPString)name
{
return _name;
}
/*!
Sets the receiver's delegate.
@param the delegate
@@ -209,9 +258,10 @@ function CPImageInBundle(aFilename, aSize, aBundle)
{
if (_loadStatus == CPImageLoadStatusLoading || _loadStatus == CPImageLoadStatusCompleted)
return;
_loadStatus = CPImageLoadStatusLoading;
#if PLATFORM(DOM)
_image = new Image();
var isSynchronous = YES;
@@ -228,7 +278,7 @@ function CPImageInBundle(aFilename, aSize, aBundle)
}
[self _derefFromImage];
}
_image.onerror = function ()
{
if (isSynchronous)
@@ -240,7 +290,7 @@ function CPImageInBundle(aFilename, aSize, aBundle)
}
[self _derefFromImage];
}
_image.onabort = function ()
{
if (isSynchronous)
@@ -252,10 +302,13 @@ function CPImageInBundle(aFilename, aSize, aBundle)
}
[self _derefFromImage];
}
_image.src = _filename;
isSynchronous = NO;
// onload and friends may fire after this point but BEFORE the end of the run loop,
// crazy, I know. So don't set isSynchronous here, rather wait a bit longer.
window.setTimeout(function() { isSynchronous = NO; }, 0);
#endif
}
- (BOOL)isThreePartImage
@@ -288,7 +341,7 @@ function CPImageInBundle(aFilename, aSize, aBundle)
[[CPNotificationCenter defaultCenter]
postNotificationName:CPImageDidLoadNotification
object:self];
if ([_delegate respondsToSelector:@selector(imageDidLoad:)])
[_delegate imageDidLoad:self];
}
@@ -297,7 +350,7 @@ function CPImageInBundle(aFilename, aSize, aBundle)
- (void)_imageDidError
{
_loadStatus = CPImageLoadStatusReadError;
if ([_delegate respondsToSelector:@selector(imageDidError:)])
[_delegate imageDidError:self];
}
@@ -306,7 +359,7 @@ function CPImageInBundle(aFilename, aSize, aBundle)
- (void)_imageDidAbort
{
_loadStatus = CPImageLoadStatusCancelled;
if ([_delegate respondsToSelector:@selector(imageDidAbort:)])
[_delegate imageDidAbort:self];
}
@@ -346,7 +399,7 @@ function CPImageInBundle(aFilename, aSize, aBundle)
- (id)initWithImageSlices:(CPArray)imageSlices isVertical:(BOOL)isVertical
{
self = [super init];
if (self)
{
_imageSlices = imageSlices;
@@ -391,13 +444,13 @@ var CPThreePartImageImageSlicesKey = @"CPThreePartImageImageSlicesKey",
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
if (self)
{
_imageSlices = [aCoder decodeObjectForKey:CPThreePartImageImageSlicesKey];
_isVertical = [aCoder decodeBoolForKey:CPThreePartImageIsVerticalKey];
}
return self;
}
@@ -418,10 +471,10 @@ var CPThreePartImageImageSlicesKey = @"CPThreePartImageImageSlicesKey",
- (id)initWithImageSlices:(CPArray)imageSlices
{
self = [super init];
if (self)
_imageSlices = imageSlices;
return self;
}
@@ -454,10 +507,10 @@ var CPNinePartImageImageSlicesKey = @"CPNinePartImageImageSlicesKey";
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
if (self)
_imageSlices = [aCoder decodeObjectForKey:CPNinePartImageImageSlicesKey];
return self;
}
-2014
View File
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+557
View File
@@ -0,0 +1,557 @@
#include "../CoreGraphics/CGGeometry.h"
#include "../Platform/Platform.h"
@import "_CPMenuWindow.j"
var MENUBAR_HEIGHT = 28.0,
MENUBAR_MARGIN = 10.0,
MENUBAR_LEFT_MARGIN = 10.0,
MENUBAR_RIGHT_MARGIN = 10.0;
var _CPMenuBarWindowBackgroundColor = nil,
_CPMenuBarWindowFont = nil;
@implementation _CPMenuBarWindow : CPPanel
{
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;
}
+ (void)initialize
{
if (self != [_CPMenuBarWindow class])
return;
var bundle = [CPBundle bundleForClass:self];
_CPMenuBarWindowFont = [CPFont boldSystemFontOfSize:12.0];
}
+ (CPFont)font
{
return _CPMenuBarWindowFont;
}
- (id)init
{
// This only shows up in browser land, so don't bother calculating metrics in desktop.
var contentRect = [[CPPlatformWindow primaryPlatformWindow] contentBounds];
contentRect.size.height = MENUBAR_HEIGHT;
self = [super initWithContentRect:contentRect styleMask:CPBorderlessWindowMask];
if (self)
{
// FIXME: http://280north.lighthouseapp.com/projects/13294-cappuccino/tickets/39-dont-allow-windows-to-go-above-menubar
[self setLevel:-1];//CPTornOffMenuWindowLevel];
[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;
}
- (void)setTitle:(CPString)aTitle
{
#if PLATFORM(DOM)
var bundleName = [[CPBundle mainBundle] objectForInfoDictionaryKey:@"CPBundleName"];
if (![bundleName length])
document.title = aTitle;
else if ([aTitle length])
document.title = aTitle + @" - " + bundleName;
else
document.title = bundleName;
#endif
[_titleField setStringValue:aTitle];
[_titleField sizeToFit];
[self tile];
}
- (void)setIconImage:(CPImage)anImage
{
[_iconImageView setImage:anImage];
[_iconImageView setHidden:anImage == nil];
[self tile];
}
- (void)setIconImageAlphaValue:(float)anAlphaValue
{
[_iconImageView setAlphaValue:anAlphaValue];
}
- (void)setColor:(CPColor)aColor
{
if (!aColor)
{
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
[[self contentView] setBackgroundColor:aColor];
}
- (void)setTextColor:(CPColor)aColor
{
if (_textColor == aColor)
return;
_textColor = aColor;
[_menuItemViews makeObjectsPerformSelector:@selector(setTextColor:) withObject:_textColor];
}
- (void)setTitleColor:(CPColor)aColor
{
if (_titleColor == aColor)
return;
_titleColor = aColor;
[_titleField setTextColor:aColor ? aColor : [CPColor blackColor]];
}
- (void)setTextShadowColor:(CPColor)aColor
{
if (_textShadowColor == aColor)
return;
_textShadowColor = aColor;
[_menuItemViews makeObjectsPerformSelector:@selector(setTextShadowColor:) withObject:_textShadowColor];
}
- (void)setTitleShadowColor:(CPColor)aColor
{
if (_titleShadowColor == aColor)
return;
_titleShadowColor = aColor;
[_titleField setTextShadowColor:aColor ? aColor : [CPColor whiteColor]];
}
- (void)setHighlightColor:(CPColor)aColor
{
if (_highlightColor == aColor)
return;
_highlightColor = aColor;
}
- (void)setHighlightTextColor:(CPColor)aColor
{
if (_highlightTextColor == aColor)
return;
_highlightTextColor = aColor;
// [_menuItemViews makeObjectsPerformSelector:@selector(setActivateColor:) withObject:_highlightTextColor];
}
- (void)setHighlightTextShadowColor:(CPColor)aColor
{
if (_highlightTextShadowColor == aColor)
return;
_highlightTextShadowColor = aColor;
// [_menuItemViews makeObjectsPerformSelector:@selector(setActivateShadowColor:) withObject:_highlightTextShadowColor];
}
- (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];
var items = [_menu itemArray],
count = items.length;
while (count--)
[[items[count] _menuItemView] removeFromSuperview];
}
_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];
}
_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];
}
- (void)menuDidChangeItem:(CPNotification)aNotification
{
var menuItem = [_menu itemAtIndex:[[aNotification userInfo] objectForKey:@"CPMenuItemIndex"]],
menuItemView = [menuItem _menuItemView];
[menuItemView setHidden:[menuItem isHidden]];
[menuItemView synchronizeWithMenuItem];
[self tile];
}
- (void)menuDidAddItem:(CPNotification)aNotification
{
var index = [[aNotification userInfo] objectForKey:@"CPMenuItemIndex"],
menuItem = [_menu itemAtIndex:index],
menuItemView = [menuItem _menuItemView];
[_menuItemViews insertObject:menuItemView atIndex:index];
[menuItemView setTextColor:_textColor];
[menuItemView setHidden:[menuItem isHidden]];
[menuItemView synchronizeWithMenuItem];
[[self contentView] addSubview:menuItemView];
[self tile];
}
- (void)menuDidRemoveItem:(CPNotification)aNotification
{
var index = [[aNotification userInfo] objectForKey:@"CPMenuItemIndex"],
menuItemView = [_menuItemViews objectAtIndex:index];
[_menuItemViews removeObjectAtIndex:index];
[menuItemView removeFromSuperview];
[self tile];
}
- (void)mouseDown:(CPEvent)anEvent
{
var constraintRect = CGRectInset([[self platformWindow] visibleFrame], 5.0, 0.0);
constraintRect.size.height -= 5.0;
[[_CPMenuManager sharedMenuManager]
beginTracking:anEvent
menuContainer:self
constraintRect:constraintRect
callback:function(aMenuContainer, aMenu)
{
[aMenu _performActionOfHighlightedItemChain];
[aMenu _highlightItemAtIndex:CPNotFound];
}];
}
- (CPFont)font
{
[CPFont systemFontOfSize:12.0];
}
- (void)tile
{
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)];
x += CGRectGetWidth([menuItemView frame]);
}
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
{
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)];
}
}
- (void)setFrame:(CGRect)aRect display:(BOOL)shouldDisplay animate:(BOOL)shouldAnimate
{
var size = [self frame].size;
[super setFrame:aRect display:shouldDisplay animate:shouldAnimate];
if (!_CGSizeEqualToSize(size, aRect.size))
[self tile];
}
@end
@implementation _CPMenuBarWindow (CPMenuContainer)
- (BOOL)isMenuBar
{
return YES;
}
- (CGRect)globalFrame
{
return [self frame];
}
- (_CPManagerScrollingState)scrollingStateForPoint:(CGPoint)aGlobalLocation
{
return _CPMenuManagerScrollingStateNone;
}
- (CPInteger)itemIndexAtPoint:(CGPoint)aPoint
{
var items = [_menu itemArray],
index = items.length;
while (index--)
{
var item = items[index];
if ([item isHidden] || [item isSeparatorItem])
continue;
if (CGRectContainsPoint([self rectForItemAtIndex:index], aPoint))
return index;
}
return CPNotFound;
}
- (CGRect)rectForItemAtIndex:(CPInteger)anIndex
{
var menuItem = [_menu itemAtIndex:anIndex === CPNotFound ? 0 : anIndex];
return [[menuItem _menuItemView] frame];
}
@end
@implementation _CPMenuBarView : _CPMenuView
{
}
- (CGRect)rectForItemAtIndex:(int)anIndex
{
return [_menuItemViews[anIndex === CPNotFound ? 0 : anIndex] frame];
}
- (int)itemIndexAtPoint:(CGPoint)aPoint
{
var bounds = [self bounds];
if (!CGRectContainsPoint(bounds, aPoint))
return CPNotFound;
var x = aPoint.x,
low = 0,
high = _visibleMenuItemInfos.length - 1;
while (low <= high)
{
var middle = FLOOR(low + (high - low) / 2),
info = _visibleMenuItemInfos[middle],
frame = [info.view frame];
if (x < CGRectGetMinX(frame))
high = middle - 1;
else if (x > CGRectGetMaxX(frame))
low = middle + 1;
else
return info.index;
}
return CPNotFound;
}
- (void)tile
{
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 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
{
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)];
}
}
@end
+322
View File
@@ -0,0 +1,322 @@
#include "../CoreGraphics/CGGeometry.h"
@import <Foundation/CPObject.j>
_CPMenuManagerScrollingStateUp = -1,
_CPMenuManagerScrollingStateDown = 1,
_CPMenuManagerScrollingStateNone = 0;
var STICKY_TIME_INTERVAL = 500;
var SharedMenuManager = nil;
@implementation _CPMenuManager: CPObject
{
CPTimeInterval _startTime;
int _scrollingState;
CGPoint _lastGlobalLocation;
CPView _lastMouseOverMenuView;
CGRect _constraintRect;
CPMutableArray _menuContainerStack;
Function _trackingCallback;
}
+ (_CPMenuManager)sharedMenuManager
{
if (!SharedMenuManager)
SharedMenuManager = [[_CPMenuManager alloc] init];
return SharedMenuManager;
}
- (id)init
{
if (SharedMenuManager)
return SharedMenuManager;
return [super init];
}
- (id)trackingMenuContainer
{
return _menuContainerStack[0];
}
- (CPMenu)trackingMenu
{
return [[self trackingMenuContainer] menu];
}
- (void)beginTracking:(CPEvent)anEvent
menuContainer:(id)aMenuContainer
constraintRect:(CGRect)aRect
callback:(Function)aCallback
{
CPApp._activeMenu = [aMenuContainer menu];
_startTime = [anEvent timestamp];//new Date();
_scrollingState = _CPMenuManagerScrollingStateNone;
_constraintRect = aRect;
_trackingCallback = aCallback;
_menuContainerStack = [aMenuContainer];
[self trackEvent:anEvent];
}
- (void)trackEvent:(CPEvent)anEvent
{
var type = [anEvent type],
trackingMenu = [self trackingMenu];
// Close Menu Event.
if (type === CPAppKitDefined)
{
// 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];
var delegate = [trackingMenu delegate];
if ([delegate respondsToSelector:@selector(menuDidClose:)])
[delegate menuDidClose:trackingMenu];
if (_trackingCallback)
_trackingCallback([self trackingMenuContainer], trackingMenu);
[[CPNotificationCenter defaultCenter]
postNotificationName:CPMenuDidEndTrackingNotification
object:trackingMenu];
CPApp._activeMenu = nil;
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];
// Remember this for the next periodic event.
_lastGlobalLocation = globalLocation;
// Find which menu window the mouse is currently on top of
var activeMenuContainer = [self menuContainerForPoint:globalLocation],
activeMenu = [activeMenuContainer menu],
menuLocation = [activeMenuContainer convertGlobalToBase:globalLocation];
// 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.
if (![activeItem isEnabled])
{
activeItemIndex = CPNotFound;
activeItem = nil;
}
var mouseOverMenuView = [activeItem view];
if (type === CPPeriodic)
{
if (_scrollingState === _CPMenuManagerScrollingStateUp)
[activeMenuContainer scrollUp];
else if (_scrollingState === _CPMenuManagerScrollingStateDown)
[activeMenuContainer scrollDown];
}
// If we're over a custom menu view...
if (mouseOverMenuView)
{
if (!_lastMouseOverMenuView)
[activeMenu _highlightItemAtIndex:CPNotFound];
if (_lastMouseOverMenuView != mouseOverMenuView)
{
[mouseOverMenuView mouseExited:anEvent];
// FIXME: Possibly multiple of these?
[_lastMouseOverMenuView mouseEntered:anEvent];
_lastMouseOverMenuView = mouseOverMenuView;
}
var menuContainerWindow = activeMenuContainer;
if (![menuContainerWindow isKindOfClass:[CPWindow class]])
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]]];
}
else
{
if (_lastMouseOverMenuView)
{
[_lastMouseOverMenuView mouseExited:anEvent];
_lastMouseOverMenuView = nil;
}
[activeMenu _highlightItemAtIndex:activeItemIndex];
if (type === CPMouseMoved || type === CPLeftMouseDragged || type === CPLeftMouseDown)
{
var oldScrollingState = _scrollingState;
_scrollingState = [activeMenuContainer scrollingStateForPoint:globalLocation];
if (_scrollingState !== oldScrollingState)
{
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))
[trackingMenu cancelTracking];
}
// If the item has a submenu, show it.
if ([activeItem hasSubmenu])// && [activeItem action] === @selector(submenuAction:))
{
var activeItemRect = [activeMenuContainer rectForItemAtIndex:activeItemIndex];
if ([activeMenuContainer isMenuBar])
var newMenuOrigin = CGPointMake(CGRectGetMinX(activeItemRect), CGRectGetMaxY(activeItemRect));
else
var newMenuOrigin = CGPointMake(CGRectGetMaxX(activeItemRect), CGRectGetMinY(activeItemRect));
newMenuOrigin = [activeMenuContainer convertBaseToGlobal: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
// we've moved to an item without a submenu.
else
[self showMenu:nil fromMenu:activeMenu atPoint:CGPointMakeZero()];
}
- (id)menuContainerForPoint:(float)aGlobalLocation
{
var count = [_menuContainerStack count],
firstMenuContainer = _menuContainerStack[0];
// Trivial case.
if (count === 1)
return firstMenuContainer;
var firstMenuWindowIndex = 0,
lastMenuWindowIndex = count - 1;
// If the first menu container is a bar, then it has to fall strictly within its bounds.
if ([firstMenuContainer isMenuBar])
{
if (CGRectContainsPoint([firstMenuContainer globalFrame], aGlobalLocation))
return firstMenuContainer;
firstMenuWindowIndex = 1;
}
var index = count,
x = aGlobalLocation.x,
closerDeltaX = Infinity,
closerMenuContainer = nil;
while (index-- > firstMenuWindowIndex)
{
var menuContainer = _menuContainerStack[index],
menuContainerFrame = [menuContainer globalFrame],
menuContainerMinX = _CGRectGetMinX(menuContainerFrame),
menuContainerMaxX = _CGRectGetMaxX(menuContainerFrame);
// If within the x bounds of this menu container, return it.
if (x < menuContainerMaxX && x >= menuContainerMinX)
return menuContainer;
// If this is either the first or last menu *window*, check to see how close we are to it.
if (index === firstMenuWindowIndex || index === lastMenuWindowIndex)
{
var deltaX = ABS(x < menuContainerMinX ? menuContainerMinX - x : menuContainerMaxX - x);
if (deltaX < closerDeltaX)
{
closerMenuContainer = menuContainer;
closerDeltaX = deltaX;
}
}
}
return closerMenuContainer;
}
- (void)showMenu:(CPMenu)newMenu fromMenu:(CPMenu)baseMenu atPoint:(CGPoint)aGlobalLocation
{
var count = _menuContainerStack.length,
index = count;
// Hide all menus up to the base menu...
while (index--)
{
var menuContainer = _menuContainerStack[index],
menu = [menuContainer menu];
// If we reach the base menu, or this menu is already being shown, break.
if (menu === baseMenu)
break;
// If this menu is already being shown, unhighlight and return.
if (menu === newMenu)//&& [menu supermenu] === baseMenu)
return [newMenu _highlightItemAtIndex:CPNotFound];
[menuContainer orderOut:self];
[menuContainer setMenu:nil];
[_CPMenuWindow poolMenuWindow:menuContainer];
[_menuContainerStack removeObjectAtIndex:index];
}
if (!newMenu)
return;
// Unhighlight any previously highlighted item.
[newMenu _highlightItemAtIndex:CPNotFound];
var menuWindow = [_CPMenuWindow menuWindowWithMenu:newMenu font:[_menuContainerStack[0] font]];
[_menuContainerStack addObject:menuWindow];
[menuWindow setConstraintRect:_constraintRect];
// If our parent menu is a menu bar...
if (baseMenu === [self trackingMenu] && [[self trackingMenuContainer] isMenuBar])
[menuWindow setBackgroundStyle:_CPMenuWindowMenuBarBackgroundStyle];
else
[menuWindow setBackgroundStyle:_CPMenuWindowPopUpBackgroundStyle];
[menuWindow setFrameOrigin:aGlobalLocation];
[menuWindow orderFront:self];
}
@end
+548
View File
@@ -0,0 +1,548 @@
#include "../CoreGraphics/CGGeometry.h"
var _CPMenuWindowPool = [],
_CPMenuWindowPoolCapacity = 5,
_CPMenuWindowBackgroundColors = [];
_CPMenuWindowMenuBarBackgroundStyle = 0;
_CPMenuWindowPopUpBackgroundStyle = 1;
_CPMenuWindowAttachedMenuBackgroundStyle = 2;
var STICKY_TIME_INTERVAL = 500,
TOP_MARGIN = 5.0,
LEFT_MARGIN = 1.0,
RIGHT_MARGIN = 1.0,
BOTTOM_MARGIN = 5.0,
SCROLL_INDICATOR_HEIGHT = 16.0;
/*
@ignore
*/
@implementation _CPMenuWindow : CPWindow
{
_CPMenuView _menuView;
CPClipView _menuClipView;
CPImageView _moreAboveView;
CPImageView _moreBelowView;
CGRect _unconstrainedFrame;
CGRect _constraintRect;
}
+ (id)menuWindowWithMenu:(CPMenu)aMenu font:(CPFont)aFont
{
var menuWindow = nil;
if (_CPMenuWindowPool.length)
{
menuWindow = _CPMenuWindowPool.pop();
// Do this so that coordinates will be accurate.
[menuWindow setFrameOrigin:CGPointMakeZero()];
}
else
menuWindow = [[_CPMenuWindow alloc] init];
[menuWindow setFont:aFont];
[menuWindow setMenu:aMenu];
[menuWindow setMinWidth:[aMenu minimumWidth]];
return menuWindow;
}
+ (void)poolMenuWindow:(_CPMenuWindow)aMenuWindow
{
if (!aMenuWindow || _CPMenuWindowPool.length >= _CPMenuWindowPoolCapacity)
return;
_CPMenuWindowPool.push(aMenuWindow);
}
+ (void)initialize
{
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)];
}
- (id)initWithContentRect:(CGRect)aRect styleMask:(unsigned)aStyleMask
{
_constraintRect = _CGRectMakeZero();
_unconstrainedFrame = _CGRectMakeZero();
self = [super initWithContentRect:aRect styleMask:CPBorderlessWindowMask];
if (self)
{
[self setLevel:CPPopUpMenuWindowLevel];
[self setHasShadow:YES];
[self setShadowStyle:CPMenuWindowShadowStyle];
[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;
}
+ (float)_standardLeftMargin
{
return LEFT_MARGIN;
}
- (void)setFont:(CPFont)aFont
{
[_menuView setFont:aFont];
}
- (CPFont)font
{
return [_menuView font];
}
+ (CPColor)backgroundColorForBackgroundStyle:(_CPMenuWindowBackgroundStyle)aBackgroundStyle
{
var color = _CPMenuWindowBackgroundColors[aBackgroundStyle];
if (!color)
{
var bundle = [CPBundle bundleForClass:[self class]];
if (aBackgroundStyle == _CPMenuWindowPopUpBackgroundStyle)
color = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
[
[[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;
}
return color;
}
- (void)setBackgroundStyle:(_CPMenuWindowBackgroundStyle)aBackgroundStyle
{
[self setBackgroundColor:[[self class] backgroundColorForBackgroundStyle:aBackgroundStyle]];
}
- (void)setMenu:(CPMenu)aMenu
{
[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)];
}
- (void)setMinWidth:(float)aWidth
{
var size = [self unconstrainedFrame].size;
[self setFrameSize:CGSizeMake(MAX(size.width, aWidth), size.height)];
}
- (CPMenu)menu
{
return [_menuView menu];
}
- (void)orderFront:(id)aSender
{
[self setFrame:_unconstrainedFrame];
[super orderFront:aSender];
}
- (void)setConstraintRect:(CGRect)aRect
{
_constraintRect = aRect;
[self setFrame:_unconstrainedFrame];
}
- (CGRect)unconstrainedFrame
{
return _CGRectMakeCopy(_unconstrainedFrame);
}
// We need this because if not this will call setFrame: with -frame instead of -unconstrainedFrame, turning
// the constrained frame into the unconstrained frame.
- (void)setFrameOrigin:(CGPoint)aPoint
{
[super setFrame:_CGRectMake(aPoint.x, aPoint.y, _CGRectGetWidth(_unconstrainedFrame), _CGRectGetHeight(_unconstrainedFrame))];
}
- (void)setFrameSize:(CGSize)aSize
{
[super setFrame:_CGRectMake(_CGRectGetMinX(_unconstrainedFrame), _CGRectGetMinY(_unconstrainedFrame), aSize.width, aSize.height)];
}
- (void)setFrame:(CGRect)aFrame display:(BOOL)shouldDisplay animate:(BOOL)shouldAnimate
{
// FIXME: There are integral window issues with platform windows.
// FIXME: This gets called far too often.
_unconstrainedFrame = _CGRectMakeCopy(aFrame);
var constrainedFrame = CGRectIntersection(_unconstrainedFrame, _constraintRect);
// We don't want to simply intersect the visible frame and the unconstrained frame.
// We should be allowing as much of the width to fit as possible (pushing back and forward).
constrainedFrame.origin.x = CGRectGetMinX(_unconstrainedFrame);
constrainedFrame.size.width = CGRectGetWidth(_unconstrainedFrame);
if (CGRectGetWidth(constrainedFrame) > CGRectGetWidth(_constraintRect))
constrainedFrame.size.width = CGRectGetWidth(_constraintRect);
if (CGRectGetMaxX(constrainedFrame) > CGRectGetMaxX(_constraintRect))
constrainedFrame.origin.x -= CGRectGetMaxX(constrainedFrame) - CGRectGetMaxX(_constraintRect);
if (CGRectGetMinX(constrainedFrame) < CGRectGetMinX(_constraintRect))
constrainedFrame.origin.x = CGRectGetMinX(_constraintRect);
[super setFrame:constrainedFrame display:shouldDisplay animate:shouldAnimate];
// This needs to happen before changing the frame.
var menuViewOrigin = CGPointMake(CGRectGetMinX(aFrame) + LEFT_MARGIN, CGRectGetMinY(aFrame) + TOP_MARGIN),
moreAbove = menuViewOrigin.y < CGRectGetMinY(constrainedFrame) + TOP_MARGIN,
moreBelow = menuViewOrigin.y + CGRectGetHeight([_menuView frame]) > CGRectGetMaxY(constrainedFrame) - BOTTOM_MARGIN,
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)];
}
[_moreAboveView setHidden:!moreAbove];
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 = 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]))];
[_menuView scrollPoint:CGPointMake(0.0, [self convertBaseToGlobal:clipFrame.origin].y - menuViewOrigin.y)];
}
- (BOOL)hasMinimumNumberOfVisibleItems
{
var visibleRect = [_menuView visibleRect];
// Clearly if the entire view isn't visible the minimum won't be visible.
if (CGRectIsEmpty(visibleRect))
return NO;
var numberOfUnhiddenItems = [_menuView numberOfUnhiddenItems],
minimumNumberOfVisibleItems = MIN(numberOfUnhiddenItems, 3),
count = 0,
index = [_menuView itemIndexAtPoint:[_menuView convertPoint:[_menuClipView frame].origin fromView:nil]];
for (; index < numberOfUnhiddenItems && count < minimumNumberOfVisibleItems; ++index)
{
var itemRect = [_menuView rectForUnhiddenItemAtIndex:index],
visibleItemRect = CGRectIntersection(visibleRect, itemRect);
// As soon as we get to the first unhidden item that is no longer visible, stop.
if (CGRectIsEmpty(visibleItemRect))
break;
// If the item is *completely* visible, count it.
if (CGRectEqualToRect(visibleItemRect, itemRect))
++count;
}
return count >= minimumNumberOfVisibleItems;
}
- (BOOL)canScrollUp
{
return ![_moreAboveView isHidden];
}
- (BOOL)canScrollDown
{
return ![_moreBelowView isHidden];
}
- (BOOL)canScroll
{
return [self canScrollUp] || [self canScrollDown];
}
- (void)scrollUp
{
if (CGRectGetMinY(_unconstrainedFrame) >= CGRectGetMinY(_constraintRect))
return;
_unconstrainedFrame.origin.y += 10;
[self setFrame:_unconstrainedFrame];
}
- (void)scrollDown
{
if (CGRectGetMaxY(_unconstrainedFrame) <= CGRectGetHeight(_constraintRect))
return;
_unconstrainedFrame.origin.y -= 10;
[self setFrame:_unconstrainedFrame];
}
@end
@implementation _CPMenuWindow (CPMenuContainer)
- (CGRect)globalFrame
{
return [self frame];
}
- (BOOL)isMenuBar
{
return NO;
}
- (_CPManagerScrollingState)scrollingStateForPoint:(CGPoint)aGlobalLocation
{
var frame = [self frame];
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)
return _CPMenuManagerScrollingStateUp;
// If we're at or below the bottom scroll indicator...
if (aGlobalLocation.y > CGRectGetMaxY(frame) - BOTTOM_MARGIN - SCROLL_INDICATOR_HEIGHT)
return _CPMenuManagerScrollingStateDown;
return _CPMenuManagerScrollingStateNone;
}
- (float)deltaYForItemAtIndex:(int)anIndex
{
return TOP_MARGIN + CGRectGetMinY([_menuView rectForItemAtIndex:anIndex]);
}
- (CGPoint)rectForItemAtIndex:(int)anIndex
{
return [_menuView convertRect:[_menuView rectForItemAtIndex:anIndex] toView:nil];
}
- (int)itemIndexAtPoint:(CGPoint)aPoint
{
// Don't return indexes of items that aren't visible.
if (!CGRectContainsPoint([_menuClipView bounds], [_menuClipView convertPoint:aPoint fromView:nil]))
return NO;
return [_menuView itemIndexAtPoint:[_menuView convertPoint:aPoint fromView:nil]];
}
@end
/*
@ignore
*/
@implementation _CPMenuView : CPView
{
CPArray _menuItemViews;
CPArray _visibleMenuItemInfos;
CPFont _font @accessors(property=font);
}
- (unsigned)numberOfUnhiddenItems
{
return _visibleMenuItemInfos.length;
}
- (CGRect)rectForUnhiddenItemAtIndex:(int)anIndex
{
return [self rectForItemAtIndex:_visibleMenuItemInfos[anIndex].index];
}
- (CGRect)rectForItemAtIndex:(int)anIndex
{
return [_menuItemViews[anIndex === CPNotFound ? 0 : anIndex] frame];
}
- (int)itemIndexAtPoint:(CGPoint)aPoint
{
var x = aPoint.x,
bounds = [self bounds];
if (x < CGRectGetMinX(bounds) || x > CGRectGetMaxX(bounds))
return CPNotFound;
var y = aPoint.y,
low = 0,
high = _visibleMenuItemInfos.length - 1;
while (low <= high)
{
var middle = FLOOR(low + (high - low) / 2),
info = _visibleMenuItemInfos[middle]
frame = [info.view frame];
if (y < CGRectGetMinY(frame))
high = middle - 1;
else if (y > CGRectGetMaxY(frame))
low = middle + 1;
else
return info.index;
}
return CPNotFound;
}
- (void)tile
{
[_menuItemViews makeObjectsPerformSelector:@selector(removeFromSuperview)];
_menuItemViews = [];
_visibleMenuItemInfos = [];
var menu = [self menu];
if (!menu)
return;
var items = [menu itemArray],
index = 0,
count = [items count],
maxWidth = 0,
y = 0,
showsStateColumn = [menu showsStateColumn];
for (; index < count; ++index)
{
var item = items[index],
view = [item _menuItemView];
_menuItemViews.push(view);
if ([item isHidden])
continue;
_visibleMenuItemInfos.push({ view:view, index:index });
[view setFont:_font];
[view setShowsStateColumn:showsStateColumn];
[view synchronizeWithMenuItem];
[view setFrameOrigin:CGPointMake(0.0, y)];
[self addSubview:view];
var size = [view minSize],
width = size.width;
if (maxWidth < width)
maxWidth = width;
y += size.height;
}
for (index = 0; index < count; ++index)
{
var view = _menuItemViews[index];
[view setFrameSize:CGSizeMake(maxWidth, CGRectGetHeight([view frame]))];
}
[self setAutoresizesSubviews:NO];
[self setFrameSize:CGSizeMake(maxWidth, y)];
[self setAutoresizesSubviews:YES];
}
- (void)setMenu:(CPMenu)aMenu
{
[super setMenu:aMenu];
[self tile];
}
@end
@@ -24,9 +24,10 @@
@import <Foundation/CPObject.j>
@import <Foundation/CPString.j>
@import <AppKit/CPImage.j>
@import <AppKit/CPMenu.j>
@import <AppKit/CPView.j>
@import "CPImage.j"
@import "CPMenu.j"
@import "CPView.j"
@import "_CPMenuItemView.j"
/*!
@ingroup appkit
@@ -108,7 +109,9 @@
_keyEquivalent = aKeyEquivalent || @"";
_keyEquivalentModifierMask = CPPlatformActionKeyMask;
_indentationLevel = 0;
_mnemonicLocation = CPNotFound;
}
@@ -448,20 +451,32 @@ CPOffState
*/
- (void)setSubmenu:(CPMenu)aMenu
{
var supermenu = [_submenu supermenu];
if (supermenu == self)
if (_submenu === aMenu)
return;
var supermenu = [_submenu supermenu];
if (supermenu)
return alert("bad");
[_submenu setSupermenu:_menu];
[CPException raise:CPInvalidArgumentException
reason: @"Can't add submenu \"" + [aMenu title] + "\" to item \"" + [self title] + "\", because it is already submenu of \"" + [[aMenu supermenu] title] + "\""];
_submenu = aMenu;
if (_submenu)
{
[_submenu setSupermenu:_menu];
[self setTarget:_menu];
[self setAction:@selector(submenuAction:)];
}
else
{
[self setTarget:nil];
[self setAction:NULL];
}
[_menuItemView setDirty];
[_menu itemChanged:self];
}
@@ -570,6 +585,43 @@ CPControlKeyMask
return _keyEquivalentModifierMask;
}
- (CPString)keyEquivalentStringRepresentation
{
if (![_keyEquivalent length])
return @"";
var string = _keyEquivalent.toUpperCase(),
needsShift = _keyEquivalentModifierMask & CPShiftKeyMask || string === _keyEquivalent;
if (CPBrowserIsOperatingSystem(CPMacOperatingSystem))
{
if (_keyEquivalentModifierMask & CPCommandKeyMask)
string = "⌘" + string;
if (needsShift)
string = "⇧" + string;
if (_keyEquivalentModifierMask & CPAlternateKeyMask)
string = "⌥" + string;
if (_keyEquivalentModifierMask & CPControlKeyMask)
string = "^" + string;
}
else
{
if (needsShift)
string = "Shift-" + string;
if (_keyEquivalentModifierMask & CPAlternateKeyMask)
string = "Alt-" + string;
if (_keyEquivalentModifierMask & CPControlKeyMask || _keyEquivalentModifierMask & CPCommandKeyMask)
string = "Ctrl-" + string;
}
return string;
}
// Managing Mnemonics
/*!
Sets the index of the mnemonic character in the title. The character
@@ -643,7 +695,7 @@ CPControlKeyMask
- (void)setIndentationLevel:(unsigned)aLevel
{
if (aLevel < 0)
[CPException raise:CPInvalidArgumentException reason:"setIndentationLevel: argument must be greater than 0."];
[CPException raise:CPInvalidArgumentException reason:"setIndentationLevel: argument must be greater than or equal to 0."];
_indentationLevel = MIN(15, aLevel);
}
@@ -742,6 +794,11 @@ CPControlKeyMask
return _menuItemView;
}
- (BOOL)_isSelectable
{
return ![self submenu] || [self action] !== @selector(submenuAction:) || [self target] !== [self menu];
}
@end
var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
@@ -765,6 +822,8 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
CPMenuItemKeyEquivalentKey = @"CPMenuItemKeyEquivalentKey",
CPMenuItemKeyEquivalentModifierMaskKey = @"CPMenuItemKeyEquivalentModifierMaskKey",
CPMenuItemIndentationLevelKey = @"CPMenuItemIndentationLevelKey",
CPMenuItemRepresentedObjectKey = @"CPMenuItemRepresentedObjectKey",
CPMenuItemViewKey = @"CPMenuItemViewKey";
@@ -804,8 +863,9 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
// CPImage _offStateImage;
// CPImage _mixedStateImage;
_submenu = DEFAULT_VALUE(CPMenuItemSubmenuKey, nil);
// This order matters because setSubmenu: needs _menu to be around.
_menu = DEFAULT_VALUE(CPMenuItemMenuKey, nil);
[self setSubmenu:DEFAULT_VALUE(CPMenuItemSubmenuKey, nil)];
_keyEquivalent = [aCoder decodeObjectForKey:CPMenuItemKeyEquivalentKey] || @"";
_keyEquivalentModifierMask = [aCoder decodeObjectForKey:CPMenuItemKeyEquivalentModifierMaskKey] || 0;
@@ -813,7 +873,9 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
// int _mnemonicLocation;
// BOOL _isAlternate;
// int _indentationLevel;
// Default is 0.
[self setIndentationLevel:[aCoder decodeIntForKey:CPMenuItemIndentationLevelKey] || 0];
// CPString _toolTip;
@@ -856,423 +918,11 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
if (_keyEquivalentModifierMask)
[aCoder encodeObject:_keyEquivalentModifierMask forKey:CPMenuItemKeyEquivalentModifierMaskKey];
if (_indentationLevel > 0)
[aCoder encodeInt:_indentationLevel forKey:CPMenuItemIndentationLevelKey];
ENCODE_IFNOT(CPMenuItemRepresentedObjectKey, _representedObject, nil);
ENCODE_IFNOT(CPMenuItemViewKey, _view, nil);
}
@end
var LEFT_MARGIN = 3.0,
RIGHT_MARGIN = 16.0,
STATE_COLUMN_WIDTH = 14.0,
INDENTATION_WIDTH = 17.0,
VERTICAL_MARGIN = 4.0;
var _CPMenuItemSelectionColor = nil,
_CPMenuItemTextShadowColor = nil,
_CPMenuItemDefaultStateImages = [],
_CPMenuItemDefaultStateHighlightedImages = [];
/*
@ignore
*/
@implementation _CPMenuItemView : CPView
{
CPMenuItem _menuItem;
CPFont _font;
CPColor _textColor;
CPColor _textShadowColor;
CPColor _activateColor;
CPColor _activateShadowColor;
CGSize _minSize;
BOOL _isDirty;
BOOL _showsStateColumn;
BOOL _belongsToMenuBar;
CPImageView _stateView;
_CPImageAndTextView _imageAndTextView;
CPView _submenuView;
}
+ (void)initialize
{
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]
var bundle = [CPBundle bundleForClass:self];
_CPMenuItemDefaultStateImages[CPOffState] = nil;
_CPMenuItemDefaultStateHighlightedImages[CPOffState] = nil;
_CPMenuItemDefaultStateImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnState.png"] size:CGSizeMake(14.0, 14.0)];
_CPMenuItemDefaultStateHighlightedImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnStateHighlighted.png"] size:CGSizeMake(14.0, 14.0)];
_CPMenuItemDefaultStateImages[CPMixedState] = nil;
_CPMenuItemDefaultStateHighlightedImages[CPMixedState] = nil;
}
+ (float)leftMargin
{
return LEFT_MARGIN + STATE_COLUMN_WIDTH;
}
- (id)initWithFrame:(CGRect)aFrame forMenuItem:(CPMenuItem)aMenuItem
{
self = [super initWithFrame:aFrame];
if (self)
{
_menuItem = aMenuItem;
_showsStateColumn = YES;
_isDirty = YES;
[self setAutoresizingMask:CPViewWidthSizable];
[self synchronizeWithMenuItem];
}
return self;
}
- (CGSize)minSize
{
return _minSize;
}
- (void)setDirty
{
_isDirty = YES;
}
- (void)synchronizeWithMenuItem
{
if (!_isDirty)
return;
_isDirty = NO;
var view = [_menuItem view];
if ([_menuItem isSeparatorItem])
{
var line = [[CPView alloc] initWithFrame:CGRectMake(0.0, 5.0, 10.0, 1.0)];
view = [[CPView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 10.0)];
[view setAutoresizingMask:CPViewWidthSizable];
[line setAutoresizingMask:CPViewWidthSizable];
[line setBackgroundColor:[CPColor lightGrayColor]];
[view addSubview:line];
}
if (view)
{
[_imageAndTextView removeFromSuperview];
_imageAndTextView = nil;
[_stateView removeFromSuperview];
_stateView = nil;
[_submenuView removeFromSuperview];
_submenuView = nil;
_minSize = [view frame].size;
[self setFrameSize:_minSize];
[self addSubview:view];
return;
}
// State Column
var x = _belongsToMenuBar ? 0.0 : (LEFT_MARGIN + [_menuItem indentationLevel] * INDENTATION_WIDTH);
if (_showsStateColumn)
{
if (!_stateView)
{
_stateView = [[CPImageView alloc] initWithFrame:CGRectMake(x, (CGRectGetHeight([self frame]) - STATE_COLUMN_WIDTH) / 2.0, STATE_COLUMN_WIDTH, STATE_COLUMN_WIDTH)];
[_stateView setAutoresizingMask:CPViewMinYMargin | CPViewMaxYMargin];
[self addSubview:_stateView];
}
var state = [_menuItem state];
switch (state)
{
case CPOffState:
case CPOnState:
case CPMixedState: [_stateView setImage:_CPMenuItemDefaultStateImages[state]];
break;
default: [_stateView setImage:nil];
}
x += STATE_COLUMN_WIDTH;
}
else
{
[_stateView removeFromSuperview];
_stateView = nil;
}
// Image and Title
if (!_imageAndTextView)
{
_imageAndTextView = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 0.0)];
[_imageAndTextView setImagePosition:CPImageLeft];
[_imageAndTextView setTextShadowOffset:CGSizeMake(0.0, 1.0)];
[self addSubview:_imageAndTextView];
}
var font = [_menuItem font];
if (!font)
font = _font;
[_imageAndTextView setFont:font];
[_imageAndTextView setVerticalAlignment:CPCenterVerticalTextAlignment];
[_imageAndTextView setImage:[_menuItem image]];
[_imageAndTextView setText:[_menuItem title]];
[_imageAndTextView setTextColor:[self textColor]];
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
[_imageAndTextView setTextShadowOffset:CGSizeMake(0, 1)];
[_imageAndTextView setFrameOrigin:CGPointMake(x, VERTICAL_MARGIN)];
[_imageAndTextView sizeToFit];
var frame = [_imageAndTextView frame];
// frame.size.height += 1.0;
// [_imageAndTextView setFrame:frame];
frame.size.height += 2 * VERTICAL_MARGIN;
x += CGRectGetWidth(frame);
// Submenu Arrow
if ([_menuItem hasSubmenu])
{
x += 3.0;
if (!_submenuView)
{
_submenuView = [[_CPMenuItemArrowView alloc] initWithFrame:CGRectMake(0.0, 0.0, 10.0, 10.0)];
[self addSubview:_submenuView];
}
[_submenuView setHidden:NO];
[_submenuView setColor:_belongsToMenuBar ? [self textColor] : nil];
[_submenuView setFrameOrigin:CGPointMake(x, (CGRectGetHeight(frame) - 10.0) / 2.0)];
x += 10.0;
}
else
[_submenuView setHidden:YES];
_minSize = CGSizeMake(x + (_belongsToMenuBar ? 0.0 : RIGHT_MARGIN) + 3.0, CGRectGetHeight(frame));
[self setFrameSize:_minSize];
}
- (CGFloat)overlapOffsetWidth
{
return LEFT_MARGIN + ([[_menuItem menu] showsStateColumn] ? STATE_COLUMN_WIDTH : 0.0);
}
- (void)setShowsStateColumn:(BOOL)shouldShowStateColumn
{
_showsStateColumn = shouldShowStateColumn;
}
- (void)setBelongsToMenuBar:(BOOL)shouldBelongToMenuBar
{
_belongsToMenuBar = shouldBelongToMenuBar;
}
- (void)highlight:(BOOL)shouldHighlight
{
// ASSERT(![_menuItem view]);
if (_belongsToMenuBar)
[_imageAndTextView setImage:shouldHighlight ? [_menuItem alternateImage] : [_menuItem image]];
else if ([_menuItem isEnabled])
{
if (shouldHighlight)
{
[self setBackgroundColor:_CPMenuItemSelectionColor];
[_imageAndTextView setTextColor:[CPColor whiteColor]];
[_imageAndTextView setTextShadowColor:_CPMenuItemTextShadowColor];
}
else
{
[self setBackgroundColor:nil];
[_imageAndTextView setTextColor:[self textColor]];
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
}
var state = [_menuItem state];
switch (state)
{
case CPOffState:
case CPOnState:
case CPMixedState: [_stateView setImage:shouldHighlight ? _CPMenuItemDefaultStateHighlightedImages[state] : _CPMenuItemDefaultStateImages[state]];
break;
default: [_stateView setImage:nil];
}
}
}
- (void)activate:(BOOL)shouldActivate
{
[_imageAndTextView setImage:[_menuItem image]];
if (shouldActivate)
{
[_imageAndTextView setTextColor:[self activateColor] || [CPColor whiteColor]];
[_imageAndTextView setTextShadowColor:[self activateShadowColor] || [CPColor blackColor]];
[_submenuView setColor:[self activateColor] || [CPColor whiteColor]];
}
else
{
[_imageAndTextView setTextColor:[self textColor]];
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
[_submenuView setColor:[self textColor]];
}
}
- (BOOL)eventOnSubmenu:(CPEvent)anEvent
{
if (![_menuItem hasSubmenu])
return NO;
return CGRectContainsPoint([_submenuView frame], [self convertPoint:[anEvent locationInWindow] fromView:nil]);
}
- (BOOL)isHidden
{
return [_menuItem isHidden];
}
- (CPMenuItem)menuItem
{
return _menuItem;
}
- (void)setFont:(CPFont)aFont
{
if (_font == aFont)
return;
_font = aFont;
[self setDirty];
}
- (void)setTextColor:(CPColor)aColor
{
if (_textColor == aColor)
return;
_textColor = aColor;
[_imageAndTextView setTextColor:[self textColor]];
[_submenuView setColor:[self textColor]];
}
- (CPColor)textColor
{
return [_menuItem isEnabled] ? (_textColor ? _textColor : [CPColor colorWithCalibratedRed:70.0 / 255.0 green:69.0 / 255.0 blue:69.0 / 255.0 alpha:1.0]) : [CPColor lightGrayColor];
}
- (void)setTextShadowColor:(CPColor)aColor
{
if (_textShadowColor == aColor)
return;
_textShadowColor = aColor;
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
//[_submenuView setColor:[self textColor]];
}
- (CPColor)textShadowColor
{
return [_menuItem isEnabled] ? (_textShadowColor ? _textShadowColor : [CPColor colorWithWhite:1.0 alpha:0.8]) : [CPColor colorWithWhite:0.8 alpha:0.8];
}
- (void)setActivateColor:(CPColor)aColor
{
_activateColor = aColor;
}
- (CPColor)activateColor
{
return _activateColor;
}
- (void)setActivateShadowColor:(CPColor)aColor
{
_activateShadowColor = aColor;
}
- (CPColor)activateShadowColor
{
return _activateShadowColor;
}
@end
@implementation _CPMenuItemArrowView : CPView
{
CPColor _color;
}
- (void)setColor:(CPColor)aColor
{
if (_color == aColor)
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
+232
View File
@@ -0,0 +1,232 @@
var HORIZONTAL_MARGIN = 8.0,
SUBMENU_INDICATOR_MARGIN = 3.0,
VERTICAL_MARGIN = 4.0;
var SelectionColor = nil,
SUBMENU_INDICATOR_COLOR = nil,
_CPMenuItemSelectionColor = nil,
_CPMenuItemTextShadowColor = nil,
_CPMenuItemDefaultStateImages = [],
_CPMenuItemDefaultStateHighlightedImages = [];
@implementation _CPMenuItemMenuBarView : CPView
{
CPMenuItem _menuItem @accessors(property=menuItem);
CPFont _font;
CPColor _textColor;
CPColor _textShadowColor;
BOOL _isDirty;
_CPImageAndTextView _imageAndTextView;
CPView _submenuIndicatorView;
}
+ (void)initialize
{
if (self !== [_CPMenuItemMenuBarView class])
return;
var bundle = [CPBundle bundleForClass:self];
SelectionColor = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuBarWindow/_CPMenuBarWindowBackgroundSelected.png"] size:CGSizeMake(1.0, 28.0)]];
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];
_CPMenuItemDefaultStateImages[CPOffState] = nil;
_CPMenuItemDefaultStateHighlightedImages[CPOffState] = nil;
_CPMenuItemDefaultStateImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnState.png"] size:CGSizeMake(14.0, 14.0)];
_CPMenuItemDefaultStateHighlightedImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnStateHighlighted.png"] size:CGSizeMake(14.0, 14.0)];
_CPMenuItemDefaultStateImages[CPMixedState] = nil;
_CPMenuItemDefaultStateHighlightedImages[CPMixedState] = nil;
}
+ (id)view
{
return [[self alloc] init];
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
_imageAndTextView = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(HORIZONTAL_MARGIN, 0.0, 0.0, 0.0)];
[_imageAndTextView setImagePosition:CPImageLeft];
[_imageAndTextView setTextShadowOffset:CGSizeMake(0.0, 1.0)];
[_imageAndTextView setAutoresizingMask:CPViewMinYMargin | CPViewMaxYMargin];
[self addSubview:_imageAndTextView];
_submenuIndicatorView = [[_CPMenuItemMenuBarSubmenuIndicatorView alloc] initWithFrame:CGRectMake(0.0, 0.0, 9.0, 6.0)];
[_submenuIndicatorView setAutoresizingMask:CPViewMinYMargin | CPViewMaxYMargin];
[self addSubview:_submenuIndicatorView];
[self setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
}
return self;
}
- (CPColor)textColor
{
if (![_menuItem isEnabled])
return [CPColor lightGrayColor];
return _textColor || [CPColor colorWithCalibratedRed:70.0 / 255.0 green:69.0 / 255.0 blue:69.0 / 255.0 alpha:1.0];
}
- (CPColor)textShadowColor
{
if (![_menuItem isEnabled])
return [CPColor colorWithWhite:0.8 alpha:0.8];
return _textShadowColor || [CPColor colorWithWhite:1.0 alpha:0.8];
}
- (void)update
{
var x = HORIZONTAL_MARGIN,
height = 0.0;
[_imageAndTextView setFont:[_menuItem font] || [_CPMenuBarWindow font]];
[_imageAndTextView setVerticalAlignment:CPCenterVerticalTextAlignment];
[_imageAndTextView setImage:[_menuItem image]];
[_imageAndTextView setText:[_menuItem title]];
[_imageAndTextView setTextColor:[self textColor]];
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
[_imageAndTextView setTextShadowOffset:CGSizeMake(0.0, 1.0)];
[_imageAndTextView sizeToFit];
var imageAndTextViewFrame = [_imageAndTextView frame];
imageAndTextViewFrame.origin.x = x;
x += CGRectGetWidth(imageAndTextViewFrame);
height = MAX(height, CGRectGetHeight(imageAndTextViewFrame));
var hasSubmenuIndicator = [_menuItem hasSubmenu] && [_menuItem action];
if (hasSubmenuIndicator)
{
[_submenuIndicatorView setHidden:NO];
[_submenuIndicatorView setColor:[self textColor]];
[_submenuIndicatorView setShadowColor:[self textShadowColor]];
var submenuViewFrame = [_submenuIndicatorView frame];
submenuViewFrame.origin.x = x + SUBMENU_INDICATOR_MARGIN;
x = CGRectGetMaxX(submenuViewFrame);
height = MAX(height, CGRectGetHeight(submenuViewFrame));
}
else
[_submenuIndicatorView setHidden:YES];
height += 2.0 * VERTICAL_MARGIN;
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;
[_submenuIndicatorView setFrame:submenuViewFrame];
}
_minSize = CGSizeMake(x + HORIZONTAL_MARGIN, height);
[self setAutoresizesSubviews:NO];
[self setFrameSize:_minSize];
[self setAutoresizesSubviews:YES];
}
- (void)highlight:(BOOL)shouldHighlight
{
// FIXME: This should probably be even throw.
if (![_menuItem isEnabled])
return;
if (shouldHighlight)
{
[self setBackgroundColor:SelectionColor];
[_imageAndTextView setTextColor:[CPColor whiteColor]];
[_imageAndTextView setTextShadowColor:_CPMenuItemTextShadowColor];
[_submenuIndicatorView setColor:[CPColor whiteColor]];
[_submenuIndicatorView setShadowColor:[CPColor colorWithWhite:0.1 alpha:0.7]];
}
else
{
[self setBackgroundColor:nil];
[_imageAndTextView setTextColor:[self textColor]];
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
[_submenuIndicatorView setColor:[self textColor]];
[_submenuIndicatorView setShadowColor:[self textShadowColor]];
}
}
@end
@implementation _CPMenuItemMenuBarSubmenuIndicatorView : CPView
{
CPColor _color;
CPColor _shadowColor;
}
- (void)setColor:(CPColor)aColor
{
if (_color === aColor)
return;
_color = aColor;
[self setNeedsDisplay:YES];
}
- (void)setShadowColor:(CPColor)aColor
{
if (_shadowColor === aColor)
return;
_shadowColor = aColor;
[self setNeedsDisplay:YES];
}
- (void)drawRect:(CGRect)aRect
{
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);
CGContextSetFillColor(context, _color);
CGContextFillPath(context);
}
@end
@@ -0,0 +1,38 @@
@import <AppKit/CPView.j>
@implementation _CPMenuItemSeparatorView : CPView
{
}
+ (id)view
{
return [[self alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 10.0)];
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
[self setAutoresizingMask:CPViewWidthSizable];
return self;
}
- (void)drawRect:(CGRect)aRect
{
var context = [[CPGraphicsContext currentContext] graphicsPort],
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);
}
@end
+298
View File
@@ -0,0 +1,298 @@
var LEFT_MARGIN = 3.0,
RIGHT_MARGIN = 14.0 + 3.0,
STATE_COLUMN_WIDTH = 14.0,
INDENTATION_WIDTH = 17.0,
VERTICAL_MARGIN = 4.0,
RIGHT_COLUMNS_MARGIN = 30.0,
KEY_EQUIVALENT_MARGIN = 10.0;
var SUBMENU_INDICATOR_COLOR = nil,
_CPMenuItemSelectionColor = nil,
_CPMenuItemTextShadowColor = nil,
_CPMenuItemDefaultStateImages = [],
_CPMenuItemDefaultStateHighlightedImages = [];
@implementation _CPMenuItemStandardView : CPView
{
CPMenuItem _menuItem @accessors(property=menuItem);
CPFont _font;
CPColor _textColor;
CPColor _textShadowColor;
CGSize _minSize @accessors(readonly, property=minSize);
BOOL _isDirty;
CPImageView _stateView;
_CPImageAndTextView _imageAndTextView;
_CPImageAndTextView _keyEquivalentView;
CPView _submenuIndicatorView;
}
+ (void)initialize
{
if (self !== [_CPMenuItemStandardView class])
return;
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]
var bundle = [CPBundle bundleForClass:self];
_CPMenuItemDefaultStateImages[CPOffState] = nil;
_CPMenuItemDefaultStateHighlightedImages[CPOffState] = nil;
_CPMenuItemDefaultStateImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnState.png"] size:CGSizeMake(14.0, 14.0)];
_CPMenuItemDefaultStateHighlightedImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnStateHighlighted.png"] size:CGSizeMake(14.0, 14.0)];
_CPMenuItemDefaultStateImages[CPMixedState] = nil;
_CPMenuItemDefaultStateHighlightedImages[CPMixedState] = nil;
}
+ (id)view
{
return [[self alloc] init];
}
+ (float)_standardLeftMargin
{
return LEFT_MARGIN + STATE_COLUMN_WIDTH;
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
_stateView = [[CPImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 0.0)];
[_stateView setImageScaling:CPScaleNone];
[self addSubview:_stateView];
_imageAndTextView = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 0.0)];
[_imageAndTextView setImagePosition:CPImageLeft];
[_imageAndTextView setTextShadowOffset:CGSizeMake(0.0, 1.0)];
[self addSubview:_imageAndTextView];
_keyEquivalentView = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 0.0)];
[_keyEquivalentView setImagePosition:CPNoImage];
[_keyEquivalentView setTextShadowOffset:CGSizeMake(0.0, 1.0)];
[_keyEquivalentView setAutoresizingMask:CPViewMinXMargin];
[self addSubview:_keyEquivalentView];
_submenuIndicatorView = [[_CPMenuItemSubmenuIndicatorView alloc] initWithFrame:CGRectMake(0.0, 0.0, 8.0, 10.0)];
[_submenuIndicatorView setColor:SUBMENU_INDICATOR_COLOR];
[_submenuIndicatorView setAutoresizingMask:CPViewMinXMargin];
[self addSubview:_submenuIndicatorView];
[self setAutoresizingMask:CPViewWidthSizable];
}
return self;
}
- (CPColor)textColor
{
if (![_menuItem isEnabled])
return [CPColor lightGrayColor];
return _textColor || [CPColor colorWithCalibratedRed:70.0 / 255.0 green:69.0 / 255.0 blue:69.0 / 255.0 alpha:1.0];
}
- (CPColor)textShadowColor
{
if (![_menuItem isEnabled])
return nil;
return _textShadowColor || [CPColor colorWithWhite:1.0 alpha:0.8];
}
- (void)setFont:(CPFont)aFont
{
_font = aFont;
}
- (void)update
{
var x = LEFT_MARGIN + [_menuItem indentationLevel] * INDENTATION_WIDTH,
height = 0.0,
hasStateColumn = [[_menuItem menu] showsStateColumn];
if (hasStateColumn)
{
[_stateView setHidden:NO];
[_stateView setImage:_CPMenuItemDefaultStateImages[[_menuItem state]] || nil];
x += STATE_COLUMN_WIDTH;
}
else
[_stateView setHidden:YES];
[_imageAndTextView setFont:[_menuItem font] || _font];
[_imageAndTextView setVerticalAlignment:CPCenterVerticalTextAlignment];
[_imageAndTextView setImage:[_menuItem image]];
[_imageAndTextView setText:[_menuItem title]];
[_imageAndTextView setTextColor:[self textColor]];
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
[_imageAndTextView setTextShadowOffset:CGSizeMake(0.0, 1.0)];
[_imageAndTextView sizeToFit];
var imageAndTextViewFrame = [_imageAndTextView frame];
imageAndTextViewFrame.origin.x = x;
x += CGRectGetWidth(imageAndTextViewFrame);
height = MAX(height, CGRectGetHeight(imageAndTextViewFrame));
var hasKeyEquivalent = !![_menuItem keyEquivalent],
hasSubmenu = [_menuItem hasSubmenu];
if (hasKeyEquivalent || hasSubmenu)
x += RIGHT_COLUMNS_MARGIN;
if (hasKeyEquivalent)
{
[_keyEquivalentView setFont:[_menuItem font] || _font];
[_keyEquivalentView setVerticalAlignment:CPCenterVerticalTextAlignment];
[_keyEquivalentView setImage:[_menuItem image]];
[_keyEquivalentView setText:[_menuItem keyEquivalentStringRepresentation]];
[_keyEquivalentView setTextColor:[self textColor]];
[_keyEquivalentView setTextShadowColor:[self textShadowColor]];
[_keyEquivalentView setTextShadowOffset:CGSizeMake(0, 1)];
[_keyEquivalentView setFrameOrigin:CGPointMake(x, VERTICAL_MARGIN)];
[_keyEquivalentView sizeToFit];
var keyEquivalentViewFrame = [_keyEquivalentView frame];
keyEquivalentViewFrame.origin.x = x;
x += CGRectGetWidth(keyEquivalentViewFrame);
height = MAX(height, CGRectGetHeight(keyEquivalentViewFrame));
if (hasSubmenu)
x += RIGHT_COLUMNS_MARGIN;
}
else
[_keyEquivalentView setHidden:YES];
if (hasSubmenu)
{
[_submenuIndicatorView setHidden:NO];
var submenuViewFrame = [_submenuIndicatorView frame];
submenuViewFrame.origin.x = x;
x += CGRectGetWidth(submenuViewFrame);
height = MAX(height, CGRectGetHeight(submenuViewFrame));
}
else
[_submenuIndicatorView setHidden:YES];
height += 2.0 * VERTICAL_MARGIN;
imageAndTextViewFrame.origin.y = FLOOR((height - CGRectGetHeight(imageAndTextViewFrame)) / 2.0);
[_imageAndTextView setFrame:imageAndTextViewFrame];
if (hasStateColumn)
[_stateView setFrameSize:CGSizeMake(STATE_COLUMN_WIDTH, height)];
if (hasKeyEquivalent)
{
keyEquivalentViewFrame.origin.y = FLOOR((height - CGRectGetHeight(keyEquivalentViewFrame)) / 2.0);
[_keyEquivalentView setFrame:keyEquivalentViewFrame];
}
if (hasSubmenu)
{
submenuViewFrame.origin.y = FLOOR((height - CGRectGetHeight(submenuViewFrame)) / 2.0);
[_submenuIndicatorView setFrame:submenuViewFrame];
}
_minSize = CGSizeMake(x + RIGHT_MARGIN, height);
[self setAutoresizesSubviews:NO];
[self setFrameSize:_minSize];
[self setAutoresizesSubviews:YES];
}
- (void)highlight:(BOOL)shouldHighlight
{
// FIXME: This should probably be even throw.
if (![_menuItem isEnabled])
return;
if (shouldHighlight)
{
[self setBackgroundColor:_CPMenuItemSelectionColor];
[_imageAndTextView setTextColor:[CPColor whiteColor]];
[_keyEquivalentView setTextColor:[CPColor whiteColor]];
[_submenuIndicatorView setColor:[CPColor whiteColor]];
[_imageAndTextView setTextShadowColor:_CPMenuItemTextShadowColor];
[_keyEquivalentView setTextShadowColor:_CPMenuItemTextShadowColor];
}
else
{
[self setBackgroundColor:nil];
[_imageAndTextView setTextColor:[self textColor]];
[_keyEquivalentView setTextColor:[self textColor]];
[_submenuIndicatorView setColor:SUBMENU_INDICATOR_COLOR];
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
[_keyEquivalentView setTextShadowColor:[self textShadowColor]];
}
if (shouldHighlight)
[_stateView setImage:_CPMenuItemDefaultStateHighlightedImages[[_menuItem state]] || nil];
else
[_stateView setImage:_CPMenuItemDefaultStateImages[[_menuItem state]] || nil];
}
@end
@implementation _CPMenuItemSubmenuIndicatorView : CPView
{
CPColor _color;
}
- (void)setColor:(CPColor)aColor
{
if (_color === aColor)
return;
_color = aColor;
[self setNeedsDisplay:YES];
}
- (void)drawRect:(CGRect)aRect
{
var context = [[CPGraphicsContext currentContext] graphicsPort],
bounds = [self bounds];
CGContextBeginPath(context);
CGContextMoveToPoint(context, CGRectGetMinX(bounds), CGRectGetMinY(bounds));
CGContextAddLineToPoint(context, CGRectGetMaxX(bounds), CGRectGetMidY(bounds));
CGContextAddLineToPoint(context, CGRectGetMinX(bounds), CGRectGetMaxY(bounds));
CGContextClosePath(context);
CGContextSetFillColor(context, _color);
CGContextFillPath(context);
}
@end
+273
View File
@@ -0,0 +1,273 @@
@import "_CPMenuItemSeparatorView.j"
@import "_CPMenuItemStandardView.j"
@import "_CPMenuItemMenuBarView.j"
var LEFT_MARGIN = 3.0,
RIGHT_MARGIN = 16.0,
STATE_COLUMN_WIDTH = 14.0,
INDENTATION_WIDTH = 17.0,
VERTICAL_MARGIN = 4.0;
var _CPMenuItemSelectionColor = nil,
_CPMenuItemTextShadowColor = nil,
_CPMenuItemDefaultStateImages = [],
_CPMenuItemDefaultStateHighlightedImages = [];
/*
@ignore
*/
@implementation _CPMenuItemView : CPView
{
CPMenuItem _menuItem;
CPView _view;
CPFont _font;
CPColor _textColor;
CPColor _textShadowColor;
CGSize _minSize;
BOOL _isDirty;
BOOL _showsStateColumn;
CPImageView _stateView;
_CPImageAndTextView _imageAndTextView;
CPView _submenuView;
}
+ (void)initialize
{
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]
var bundle = [CPBundle bundleForClass:self];
_CPMenuItemDefaultStateImages[CPOffState] = nil;
_CPMenuItemDefaultStateHighlightedImages[CPOffState] = nil;
_CPMenuItemDefaultStateImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnState.png"] size:CGSizeMake(14.0, 14.0)];
_CPMenuItemDefaultStateHighlightedImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnStateHighlighted.png"] size:CGSizeMake(14.0, 14.0)];
_CPMenuItemDefaultStateImages[CPMixedState] = nil;
_CPMenuItemDefaultStateHighlightedImages[CPMixedState] = nil;
}
+ (float)leftMargin
{
return LEFT_MARGIN + STATE_COLUMN_WIDTH;
}
- (id)initWithFrame:(CGRect)aFrame forMenuItem:(CPMenuItem)aMenuItem
{
self = [super initWithFrame:aFrame];
if (self)
{
_menuItem = aMenuItem;
_showsStateColumn = YES;
_isDirty = YES;
[self setAutoresizingMask:CPViewWidthSizable];
[self synchronizeWithMenuItem];
}
return self;
}
- (CGSize)minSize
{
return _minSize;
}
- (void)setDirty
{
_isDirty = YES;
}
- (void)synchronizeWithMenuItem
{
var menuItemView = [_menuItem view];
if ([_menuItem isSeparatorItem])
{
if (![_view isKindOfClass:[_CPMenuItemSeparatorView class]])
{
[_view removeFromSuperview];
_view = [_CPMenuItemSeparatorView view];
}
}
else if (menuItemView)
{
if (_view !== menuItemView)
{
[_view removeFromSuperview];
_view = menuItemView;
}
}
else if ([_menuItem menu] == [CPApp mainMenu])
{
if (![_view isKindOfClass:[_CPMenuItemMenuBarView class]])
{
[_view removeFromSuperview];
_view = [_CPMenuItemMenuBarView view];
}
[_view setMenuItem:_menuItem];
}
else
{
if (![_view isKindOfClass:[_CPMenuItemStandardView class]])
{
[_view removeFromSuperview];
_view = [_CPMenuItemStandardView view];
}
[_view setMenuItem:_menuItem];
}
if ([_view superview] !== self)
[self addSubview:_view];
if ([_view respondsToSelector:@selector(update)])
[_view update];
_minSize = [_view frame].size;
[self setAutoresizesSubviews:NO];
[self setFrameSize:_minSize];
[self setAutoresizesSubviews:YES];
}
- (void)setShowsStateColumn:(BOOL)shouldShowStateColumn
{
_showsStateColumn = shouldShowStateColumn;
}
- (void)highlight:(BOOL)shouldHighlight
{
if ([_view respondsToSelector:@selector(highlight:)])
[_view highlight:shouldHighlight];
}
- (void)activate:(BOOL)shouldActivate
{
[_imageAndTextView setImage:[_menuItem image]];
if (shouldActivate)
{
[_imageAndTextView setTextColor:[self activateColor] || [CPColor whiteColor]];
[_imageAndTextView setTextShadowColor:[self activateShadowColor] || [CPColor blackColor]];
[_submenuView setColor:[self activateColor] || [CPColor whiteColor]];
}
else
{
[_imageAndTextView setTextColor:[self textColor]];
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
[_submenuView setColor:[self textColor]];
}
}
- (BOOL)eventOnSubmenu:(CPEvent)anEvent
{
if (![_menuItem hasSubmenu])
return NO;
return CGRectContainsPoint([_submenuView frame], [self convertPoint:[anEvent locationInWindow] fromView:nil]);
}
- (BOOL)isHidden
{
return [_menuItem isHidden];
}
- (CPMenuItem)menuItem
{
return _menuItem;
}
- (void)setFont:(CPFont)aFont
{
if (_font === aFont)
return;
_font = aFont;
if ([_view respondsToSelector:@selector(setFont:)])
[_view setFont:aFont];
[self setDirty];
}
- (void)setTextColor:(CPColor)aColor
{
if (_textColor == aColor)
return;
_textColor = aColor;
[_imageAndTextView setTextColor:[self textColor]];
[_submenuView setColor:[self textColor]];
}
- (CPColor)textColor
{
return nil;
}
- (void)setTextShadowColor:(CPColor)aColor
{
if (_textShadowColor == aColor)
return;
_textShadowColor = aColor;
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
//[_submenuView setColor:[self textColor]];
}
- (CPColor)textShadowColor
{
return [_menuItem isEnabled] ? (_textShadowColor ? _textShadowColor : [CPColor colorWithWhite:1.0 alpha:0.8]) : [CPColor colorWithWhite:0.8 alpha:0.8];
}
@end
@implementation _CPMenuItemArrowView : CPView
{
CPColor _color;
}
- (void)setColor:(CPColor)aColor
{
if (_color == aColor)
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
+122 -116
View File
@@ -235,7 +235,7 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_
return _itemsForRows[aRow] || nil;
}
- (CPInteger)rowForItem:(id)aItem
- (CPInteger)rowForItem:(id)anItem
{
if (!anItem)
return _rootItemInfo.row;
@@ -618,140 +618,146 @@ var CPOutlineViewDataSource_outlineView_setObjectValue_forTableColumn_byItem_
@end
// FIX ME: We're using with() here because Safari fails if we use anOutlineView._itemInfosForItems or whatever...
var _reloadItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anItem)
{
if (!anItem)
return;
// Get the existing info if it exists.
var itemInfosForItems = anOutlineView._itemInfosForItems,
dataSource = anOutlineView._outlineViewDataSource,
itemUID = [anItem UID],
itemInfo = itemInfosForItems[itemUID];
// If we're not in the tree, then just bail.
if (!itemInfo)
return [];
// See if the item itself can be swapped out.
var parent = itemInfo.parent,
parentItemInfo = parent ? itemInfosForItems[[parent UID]] : anOutlineView._rootItemInfo,
parentChildren = parentItemInfo.children,
index = [parentChildren indexOfObjectIdenticalTo:anItem],
newItem = [dataSource outlineView:anOutlineView child:index ofItem:parent];
if (anItem !== newItem)
{
itemInfosForItems[[anItem UID]] = nil;
itemInfosForItems[[newItem UID]] = itemInfo;
parentChildren[index] = newItem;
anOutlineView._itemsForRows[itemInfo.row] = newItem;
}
itemInfo.isExpandable = [dataSource outlineView:anOutlineView isItemExpandable:newItem];
itemInfo.isExpanded = itemInfo.isExpandable && itemInfo.isExpanded;
}
var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anItem, /*BOOL*/ isIntermediate)
{
var itemInfosForItems = anOutlineView._itemInfosForItems,
dataSource = anOutlineView._outlineViewDataSource;
if (!anItem)
var itemInfo = anOutlineView._rootItemInfo;
else
with(anOutlineView)
{
// Get the existing info if it exists.
var itemUID = [anItem UID],
var itemInfosForItems = _itemInfosForItems,
dataSource = _outlineViewDataSource,
itemUID = [anItem UID],
itemInfo = itemInfosForItems[itemUID];
// If we're not in the tree, then just bail.
if (!itemInfo)
return [];
itemInfo.isExpandable = [dataSource outlineView:anOutlineView isItemExpandable:anItem];
// If we were previously expanded, but now no longer expandable, "de-expand".
// NOTE: we are *not* collapsing, thus no notification is posted.
if (!itemInfo.isExpandable && itemInfo.isExpanded)
// See if the item itself can be swapped out.
var parent = itemInfo.parent,
parentItemInfo = parent ? itemInfosForItems[[parent UID]] : _rootItemInfo,
parentChildren = parentItemInfo.children,
index = [parentChildren indexOfObjectIdenticalTo:anItem],
newItem = [dataSource outlineView:anOutlineView child:index ofItem:parent];
if (anItem !== newItem)
{
itemInfo.isExpanded = NO;
itemInfosForItems[[anItem UID]] = nil;
itemInfosForItems[[newItem UID]] = itemInfo;
parentChildren[index] = newItem;
_itemsForRows[itemInfo.row] = newItem;
}
itemInfo.isExpandable = [dataSource outlineView:anOutlineView isItemExpandable:newItem];
itemInfo.isExpanded = itemInfo.isExpandable && itemInfo.isExpanded;
}
}
// FIX ME: We're using with() here because Safari fails if we use anOutlineView._itemInfosForItems or whatever...
var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anItem, /*BOOL*/ isIntermediate)
{
with(anOutlineView)
{
var itemInfosForItems = _itemInfosForItems,
dataSource = _outlineViewDataSource;
if (!anItem)
var itemInfo = _rootItemInfo;
else
{
// Get the existing info if it exists.
var itemUID = [anItem UID],
itemInfo = itemInfosForItems[itemUID];
// If we're not in the tree, then just bail.
if (!itemInfo)
return [];
itemInfo.isExpandable = [dataSource outlineView:anOutlineView isItemExpandable:anItem];
// If we were previously expanded, but now no longer expandable, "de-expand".
// NOTE: we are *not* collapsing, thus no notification is posted.
if (!itemInfo.isExpandable && itemInfo.isExpanded)
{
itemInfo.isExpanded = NO;
itemInfo.children = [];
}
}
// The root item does not count as a descendant.
var weight = itemInfo.weight,
descendants = anItem ? [anItem] : [];
if (itemInfo.isExpanded && (!(_implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_shouldDeferDisplayingChildrenOfItem_) ||
![dataSource outlineView:anOutlineView shouldDeferDisplayingChildrenOfItem:anItem]))
{
var index = 0,
count = [dataSource outlineView:anOutlineView numberOfChildrenOfItem:anItem],
level = itemInfo.level + 1;
itemInfo.children = [];
}
}
// The root item does not count as a descendant.
var weight = itemInfo.weight,
descendants = anItem ? [anItem] : [];
if (itemInfo.isExpanded && (!(anOutlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_shouldDeferDisplayingChildrenOfItem_) ||
![dataSource outlineView:anOutlineView shouldDeferDisplayingChildrenOfItem:anItem]))
{
var index = 0,
count = [dataSource outlineView:anOutlineView numberOfChildrenOfItem:anItem],
level = itemInfo.level + 1;
itemInfo.children = [];
for (; index < count; ++index)
{
var childItem = [dataSource outlineView:anOutlineView child:index ofItem:anItem],
childItemInfo = itemInfosForItems[[childItem UID]];
if (!childItemInfo)
for (; index < count; ++index)
{
childItemInfo = { isExpanded:NO, isExpandable:NO, children:[], weight:1 };
itemInfosForItems[[childItem UID]] = childItemInfo;
var childItem = [dataSource outlineView:anOutlineView child:index ofItem:anItem],
childItemInfo = itemInfosForItems[[childItem UID]];
if (!childItemInfo)
{
childItemInfo = { isExpanded:NO, isExpandable:NO, children:[], weight:1 };
itemInfosForItems[[childItem UID]] = childItemInfo;
}
itemInfo.children[index] = childItem;
var childDescendants = _loadItemInfoForItem(anOutlineView, childItem, YES);
childItemInfo.parent = anItem;
childItemInfo.level = level;
descendants = descendants.concat(childDescendants);
}
itemInfo.children[index] = childItem;
var childDescendants = _loadItemInfoForItem(anOutlineView, childItem, YES);
childItemInfo.parent = anItem;
childItemInfo.level = level;
descendants = descendants.concat(childDescendants);
}
}
itemInfo.weight = descendants.length;
if (!isIntermediate)
{
// row = -1 is the root item, so just go to row 0 since it is ignored.
var index = MAX(itemInfo.row, 0),
itemsForRows = anOutlineView._itemsForRows;
descendants.unshift(index, weight);
itemsForRows.splice.apply(itemsForRows, descendants);
var count = itemsForRows.length;
for (; index < count; ++index)
itemInfosForItems[[itemsForRows[index] UID]].row = index;
var deltaWeight = itemInfo.weight - weight;
if (deltaWeight !== 0)
itemInfo.weight = descendants.length;
if (!isIntermediate)
{
var parent = itemInfo.parent;
while (parent)
// row = -1 is the root item, so just go to row 0 since it is ignored.
var index = MAX(itemInfo.row, 0),
itemsForRows = _itemsForRows;
descendants.unshift(index, weight);
itemsForRows.splice.apply(itemsForRows, descendants);
var count = itemsForRows.length;
for (; index < count; ++index)
itemInfosForItems[[itemsForRows[index] UID]].row = index;
var deltaWeight = itemInfo.weight - weight;
if (deltaWeight !== 0)
{
var parentItemInfo = itemInfosForItems[[parent UID]];
parentItemInfo.weight += deltaWeight;
parent = parentItemInfo.parent;
var parent = itemInfo.parent;
while (parent)
{
var parentItemInfo = itemInfosForItems[[parent UID]];
parentItemInfo.weight += deltaWeight;
parent = parentItemInfo.parent;
}
if (anItem)
_rootItemInfo.weight += deltaWeight;
}
if (anItem)
anOutlineView._rootItemInfo.weight += deltaWeight;
}
}
}//end of with
return descendants;
}
+88 -16
View File
@@ -43,11 +43,14 @@ CPURLPboardType = @"CPURLPboardType";
CPImagesPboardType = @"CPImagesPboardType";
CPVideosPboardType = @"CPVideosPboardType";
UTF8PboardType = @"public.utf8-plain-text";
// Deprecated
CPImagePboardType = @"CPImagePboardType";
var CPPasteboards = nil;
var CPPasteboards = nil,
supportsNativePasteboard = NO;
/*!
@ingroup appkit
@@ -63,6 +66,8 @@ var CPPasteboards = nil;
unsigned _changeCount;
CPString _stateUID;
WebScriptObject _nativePasteboard;
}
/*
@@ -76,6 +81,9 @@ var CPPasteboards = nil;
[self setVersion:1.0];
CPPasteboards = [CPDictionary dictionary];
if (typeof window.cpPasteboardWithName !== "undefined")
supportsNativePasteboard = YES;
}
/*!
@@ -94,7 +102,7 @@ var CPPasteboards = nil;
+ (id)pasteboardWithName:(CPString)aName
{
var pasteboard = [CPPasteboards objectForKey:aName];
if (pasteboard)
return pasteboard;
@@ -118,6 +126,12 @@ var CPPasteboards = nil;
_provided = [CPDictionary dictionary];
_changeCount = 0;
if (supportsNativePasteboard)
{
_nativePasteboard = window.cpPasteboardWithName(aName);
[self _synchronizePasteboard];
}
}
return self;
@@ -146,7 +160,16 @@ var CPPasteboards = nil;
[_owners setObject:anOwner forKey:type];
}
if (_nativePasteboard)
{
var nativeTypes = [types copy];
if ([types containsObject:CPStringPboardType])
nativeTypes.push(UTF8PboardType);
_nativePasteboard.addTypes_(nativeTypes);
}
return ++_changeCount;
}
@@ -157,6 +180,12 @@ var CPPasteboards = nil;
@return the pasteboard's change count
*/
- (unsigned)declareTypes:(CPArray)types owner:(id)anOwner
{
[self _declareTypes:types owner:anOwner updateNativePasteboard:YES];
}
/*! @ignore */
- (unsigned)_declareTypes:(CPArray)types owner:(id)anOwner updateNativePasteboard:(BOOL)shouldUpdate
{
[_types setArray:types];
@@ -167,7 +196,16 @@ var CPPasteboards = nil;
while (count--)
[_owners setObject:anOwner forKey:_types[count]];
if (_nativePasteboard && shouldUpdate)
{
var nativeTypes = [types copy];
if ([types containsObject:CPStringPboardType])
nativeTypes.push(UTF8PboardType);
_nativePasteboard.declareTypes_(nativeTypes);
_changeCount = _nativePasteboard.changeCount();
}
return ++_changeCount;
}
@@ -180,7 +218,10 @@ var CPPasteboards = nil;
- (BOOL)setData:(CPData)aData forType:(CPString)aType
{
[_provided setObject:aData forKey:aType];
if (aType === CPStringPboardType)
[self setData:aData forType:UTF8PboardType];
return YES;
}
@@ -192,7 +233,7 @@ var CPPasteboards = nil;
*/
- (BOOL)setPropertyList:(id)aPropertyList forType:(CPString)aType
{
return [self setData:[CPPropertyListSerialization dataFromPropertyList:aPropertyList format:CPPropertyListXMLFormat_v1_0 errorDescription:nil] forType:aType];
return [self setData:[CPPropertyListSerialization dataFromPropertyList:aPropertyList format:CPPropertyList280NorthFormat_v1_0] forType:aType];
}
/*!
@@ -203,7 +244,7 @@ var CPPasteboards = nil;
*/
- (void)setString:(CPString)aString forType:(CPString)aType
{
return [self setPropertyList:aString forType:aType];
[self setPropertyList:aString forType:aType];
}
// Determining Types
@@ -223,6 +264,7 @@ var CPPasteboards = nil;
*/
- (CPArray)types
{
[self _synchronizePasteboard];
return _types;
}
@@ -251,16 +293,46 @@ var CPPasteboards = nil;
if (owner)
{
[owner pasteboard:self provideDataForType:aType];
++_changeCount;
[owner pasteboard:self provideDataForType:aType];
return [_provided objectForKey:aType];
}
if (aType === CPStringPboardType)
return [self dataForType:UTF8PboardType];
return nil;
}
- (void)_synchronizePasteboard
{
if (_nativePasteboard && _nativePasteboard.changeCount() > _changeCount)
{
var nativeTypes = [_nativePasteboard.types() copy];
if ([nativeTypes containsObject:UTF8PboardType])
nativeTypes.push(CPStringPboardType);
[self _declareTypes:nativeTypes owner:self updateNativePasteboard:NO];
_changeCount = _nativePasteboard.changeCount();
}
}
/*! @ignore
method provided for integration with native pasteboard
*/
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
{
if (aType === CPStringPboardType)
{
var string = _nativePasteboard.stringForType_(UTF8PboardType);
[self setString:string forType:CPStringPboardType];
[self setString:string forType:UTF8PboardType];
}
else
[self setString:_nativePasteboard.stringForType_(aType) forType:aType];
}
/*!
Returns the property list for the specified data type
@param aType the requested data type
@@ -271,7 +343,7 @@ var CPPasteboards = nil;
var data = [self dataForType:aType];
if (data)
return [CPPropertyListSerialization propertyListFromData:data format:CPPropertyListXMLFormat_v1_0 errorDescription:nil];
return [CPPropertyListSerialization propertyListFromData:data format:CPPropertyList280NorthFormat_v1_0];
return nil;
}
@@ -343,7 +415,7 @@ var DOMDataTransferPasteboard = nil;
if (type === CPStringPboardType)
_dataTransfer.setData(type, [aPasteboard stringForType:type]);
else
_dataTransfer.setData(type, [[aPasteboard dataForType:type] string]);
_dataTransfer.setData(type, [[aPasteboard dataForType:type] encodedString]);
}
}
@@ -357,9 +429,9 @@ var DOMDataTransferPasteboard = nil;
var dataString = _dataTransfer.getData(aType);
if (aType === CPStringPboardType)
return [CPData dataFromPropertyList:dataString format:kCFPropertyList280NorthFormat_v1_0 errorDescription:0];
return [CPData dataFromPropertyList:dataString format:kCFPropertyList280NorthFormat_v1_0];
return [CPData dataWithString:dataString];
return [CPData dataWithEncodedString:dataString];
}
- (id)propertyListForType:(CPString)aType
@@ -367,7 +439,7 @@ var DOMDataTransferPasteboard = nil;
if (aType === CPStringPboardType)
return _dataTransfer.getData(aType);
return [CPPropertyListSerialization propertyListFromData:[self dataForType:aType] format:CPPropertyListUnknownFormat errorDescription:nil];
return [CPPropertyListSerialization propertyListFromData:[self dataForType:aType] format:CPPropertyListUnknownFormat];
}
@end
+41 -42
View File
@@ -638,21 +638,49 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
{
if (![self isEnabled] || ![self numberOfItems])
return;
[self highlight:YES];
var menu = [self menu],
theWindow = [self window],
menuWindow = [_CPMenuWindow menuWindowWithMenu:menu font:[self font]];
[menuWindow setDelegate:self];
[menuWindow setBackgroundStyle:_CPMenuWindowPopUpBackgroundStyle];
// Pull Down Menus show up directly below their buttons.
bounds = [self bounds],
minimumWidth = CGRectGetWidth(bounds);
// FIXME: setFont: should set the font on the menu.
[menu setFont:[self font]];
if ([self pullsDown])
var menuOrigin = [theWindow convertBaseToGlobal:[self convertPoint:CGPointMake(0.0, CGRectGetMaxY([self bounds])) toView:nil]];
// Pop Up Menus attempt to show up "on top" of the selected item.
{
var positionedItem = nil,
location = CGPointMake(0.0, CGRectGetMaxY(bounds));
}
else
{
var contentRect = [self contentRectForBounds:bounds],
positionedItem = [self selectedItem],
standardLeftMargin = [_CPMenuWindow _standardLeftMargin] + [_CPMenuItemStandardView _standardLeftMargin],
location = CGPointMake(CGRectGetMinX(contentRect) - standardLeftMargin, 0.0);
minimumWidth += standardLeftMargin;
}
[menu setMinimumWidth:minimumWidth];
[menu
_popUpMenuPositioningItem:positionedItem
atLocation:location
topY:CGRectGetMinY(bounds)
bottomY:CGRectGetMaxY(bounds)
inView:self
callback:function(aMenu)
{
[self highlight:NO];
var highlightedItem = [aMenu highlightedItem];
if ([highlightedItem _isSelectable])
[self selectItem:highlightedItem];
}];
/*
else
{
// This is confusing, I KNOW, so let me explain it to you.
@@ -660,43 +688,14 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
// 1. So calculate where our content is, then calculate where the menu item is.
// 2. Move LEFT by whatever indentation we have (offsetWidths, aka, window margin, item margin, etc).
// 3. MOVE UP by the difference in sizes of the content and menu item, this will only work if the content is vertically centered.
var contentRect = [self convertRect:[self contentRectForBounds:[self bounds]] toView:nil],
var contentRect = [self convertRect:[self contentRectForBounds:bounds] toView:nil],
menuOrigin = [theWindow convertBaseToGlobal:contentRect.origin],
menuItemRect = [menuWindow rectForItemAtIndex:_selectedIndex];
menuOrigin.x -= CGRectGetMinX(menuItemRect) + [menuWindow overlapOffsetWidth] + [[[menu itemAtIndex:_selectedIndex] _menuItemView] overlapOffsetWidth];
menuOrigin.y -= CGRectGetMinY(menuItemRect) + (CGRectGetHeight(menuItemRect) - CGRectGetHeight(contentRect)) / 2.0;
}
[menuWindow setFrameOrigin:menuOrigin];
var menuMaxX = CGRectGetMaxX([menuWindow frame]),
buttonMaxX = [theWindow convertBaseToGlobal:CGPointMake(CGRectGetMaxX([self convertRect:[self bounds] toView:nil]), 0.0)].x;
if (menuMaxX < buttonMaxX)
[menuWindow setMinWidth:CGRectGetWidth([menuWindow frame]) + buttonMaxX - menuMaxX - ([self pullsDown] ? 0.0 : VISIBLE_MARGIN)];
[menuWindow orderFront:self];
[menuWindow beginTrackingWithEvent:anEvent sessionDelegate:self didEndSelector:@selector(menuWindowDidFinishTracking:highlightedItem:)];
}
/*
@ignore
*/
- (void)menuWindowDidFinishTracking:(_CPMenuWindow)aMenuWindow highlightedItem:(CPMenuItem)aMenuItem
{
[_CPMenuWindow poolMenuWindow:aMenuWindow];
[self highlight:NO];
var index = [_menu indexOfItem:aMenuItem];
if (index == CPNotFound)
return;
[self selectItemAtIndex:index];
[CPApp sendAction:[aMenuItem action] to:[aMenuItem target] from:aMenuItem];
}
- (void)_popUpItemAction:(id)aSender
+25 -34
View File
@@ -104,17 +104,14 @@ var CPProgressIndicatorSpinningStyleColors = nil,
for (; start <= end; ++start)
{
CPProgressIndicatorBezelBorderViewPool[start] = [];
CPProgressIndicatorBezelBorderViewPool[start][CPMiniControlSize] = [];
CPProgressIndicatorBezelBorderViewPool[start][CPSmallControlSize] = [];
CPProgressIndicatorBezelBorderViewPool[start][CPRegularControlSize] = [];
}
CPProgressIndicatorClassName = [self className];
CPProgressIndicatorStyleIdentifiers = [];
CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle] = @"Bar";
CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorSpinningStyle] = @"Spinny";
CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorHUDBarStyle] = @"HUDBar";
@@ -126,30 +123,20 @@ var CPProgressIndicatorSpinningStyleColors = nil,
CPProgressIndicatorStyleSizes = [];
// Bar Sttyle
var prefix = CPProgressIndicatorClassName + @"BezelBorder" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle];
var prefixes = [
CPProgressIndicatorClassName + @"BezelBorder" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle],
CPProgressIndicatorClassName + @"Bar" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle],
CPProgressIndicatorClassName + @"BezelBorder" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorHUDBarStyle],
CPProgressIndicatorClassName + @"Bar" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorHUDBarStyle]
];
CPProgressIndicatorStyleSizes[prefix + regularIdentifier] = [_CGSizeMake(3.0, 15.0), _CGSizeMake(1.0, 15.0), _CGSizeMake(3.0, 15.0)];
CPProgressIndicatorStyleSizes[prefix + smallIdentifier] = [_CGSizeMake(3.0, 15.0), _CGSizeMake(1.0, 15.0), _CGSizeMake(3.0, 15.0)];
CPProgressIndicatorStyleSizes[prefix + miniIdentifier] = [_CGSizeMake(3.0, 15.0), _CGSizeMake(1.0, 15.0), _CGSizeMake(3.0, 15.0)];
prefix = CPProgressIndicatorClassName + @"Bar" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle];
CPProgressIndicatorStyleSizes[prefix + regularIdentifier] = _CGSizeMake(1.0, 9.0);
CPProgressIndicatorStyleSizes[prefix + smallIdentifier] = _CGSizeMake(1.0, 9.0);
CPProgressIndicatorStyleSizes[prefix + miniIdentifier] = _CGSizeMake(1.0, 9.0);
// HUD Bar Style
prefix = CPProgressIndicatorClassName + @"BezelBorder" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorHUDBarStyle];
CPProgressIndicatorStyleSizes[prefix + regularIdentifier] = [_CGSizeMake(3.0, 15.0), _CGSizeMake(1.0, 15.0), _CGSizeMake(3.0, 15.0)];
CPProgressIndicatorStyleSizes[prefix + smallIdentifier] = [_CGSizeMake(3.0, 15.0), _CGSizeMake(1.0, 15.0), _CGSizeMake(3.0, 15.0)];
CPProgressIndicatorStyleSizes[prefix + miniIdentifier] = [_CGSizeMake(3.0, 15.0), _CGSizeMake(1.0, 15.0), _CGSizeMake(3.0, 15.0)];
prefix = CPProgressIndicatorClassName + @"Bar" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorHUDBarStyle];
CPProgressIndicatorStyleSizes[prefix + regularIdentifier] = _CGSizeMake(1.0, 9.0);
CPProgressIndicatorStyleSizes[prefix + smallIdentifier] = _CGSizeMake(1.0, 9.0);
CPProgressIndicatorStyleSizes[prefix + miniIdentifier] = _CGSizeMake(1.0, 9.0);
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)];
CPProgressIndicatorStyleSizes[prefix + smallIdentifier] = [_CGSizeMake(3.0, 16.0), _CGSizeMake(1.0, 16.0), _CGSizeMake(3.0, 16.0)];
CPProgressIndicatorStyleSizes[prefix + miniIdentifier] = [_CGSizeMake(3.0, 16.0), _CGSizeMake(1.0, 16.0), _CGSizeMake(3.0, 16.0)];
}
}
- (id)initWithFrame:(CGRect)aFrame
@@ -428,21 +415,25 @@ var CPProgressIndicatorSpinningStyleColors = nil,
if (!_barView)
{
_barView = [[CPView alloc] initWithFrame:CGRectMake(2.0, 2.0, 0.0, 9.0)];
[_barView setBackgroundColor:[CPColor redColor]];
_barView = [[CPView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 16.0)];
[self addSubview:_barView];
}
[_barView setBackgroundColor:_CPControlColorWithPatternImage(
[_barView setBackgroundColor:_CPControlThreePartImagePattern(
NO,
CPProgressIndicatorStyleSizes,
CPProgressIndicatorClassName,
@"Bar",
CPProgressIndicatorStyleIdentifiers[_style],
_CPControlIdentifierForControlSize(_controlSize))];
[_barView setFrameSize:CGSizeMake(CGRectGetWidth([self bounds]) * (_doubleValue - _minValue) / (_maxValue - _minValue) - 4.0, 9.0)];
var width = CGRectGetWidth([self bounds]),
barWidth = width * ((_doubleValue - _minValue) / (_maxValue - _minValue));
if (barWidth > 0.0 && barWidth < 4.0)
barWidth = 4.0;
[_barView setFrameSize:CGSizeMake(barWidth, 16.0)];
}
/* @ignore */
+7 -2
View File
@@ -98,7 +98,7 @@
if (self)
{
[self setRadioGroup:aRadioGroup || [CPRadioGroup new]];
[self setRadioGroup:aRadioGroup];
[self setHighlightsBy:CPContentsCellMask];
[self setShowsStateBy:CPContentsCellMask];
@@ -115,7 +115,7 @@
- (id)initWithFrame:(CGRect)aFrame
{
return [self initWithFrame:aFrame radioGroup:nil];
return [self initWithFrame:aFrame radioGroup:[CPRadioGroup new]];
}
- (CPInteger)nextState
@@ -175,6 +175,9 @@ var CPRadioRadioGroupKey = @"CPRadioRadioGroupKey";
{
CPSet _radios;
CPRadio _selectedRadio;
id _target @accessors(property=target);
SEL _action @accessors(property=action);
}
- (id)init
@@ -213,6 +216,8 @@ var CPRadioRadioGroupKey = @"CPRadioRadioGroupKey";
[_selectedRadio setState:CPOffState];
_selectedRadio = aRadio;
[CPApp sendAction:_action to:_target from:self];
}
- (CPRadio)selectedRadio
+2 -1
View File
@@ -27,6 +27,7 @@ CPDeleteKeyCode = 8;
CPTabKeyCode = 9;
CPReturnKeyCode = 13;
CPEscapeKeyCode = 27;
CPSpaceKeyCode = 32;
CPLeftArrowKeyCode = 37;
CPUpArrowKeyCode = 38;
CPRightArrowKeyCode = 39;
@@ -241,7 +242,7 @@ CPDownArrowKeyCode = 40;
*/
- (void)insertNewline:(id)aSender
{
[self insertNewline:aSender];
[[self nextResponder] insertNewline:aSender];
}
- (void)cancel:(id)sender
+24 -1
View File
@@ -5,6 +5,13 @@
@implementation CPSavePanel : CPPanel
{
CPURL _URL;
BOOL _isExtensionHidden @accessors(getter=isExtensionHidden, setter=setExtensionHidden:);
BOOL _canSelectHiddenExtension @accessors(property=canSelectHiddenExtension);
BOOL _allowsOtherFileTypes @accessors(property=allowsOtherFileTypes);
BOOL _canCreateDirectories @accessors(property=canCreateDirectories);
CPArray _allowedFileTypes @accessors(property=allowedFileTypes);
}
+ (id)savePanel
@@ -12,6 +19,16 @@
return [[CPSavePanel alloc] init];
}
- (id)init
{
if (self = [super init])
{
_canCreateDirectories = YES;
}
return self;
}
- (CPInteger)runModal
{
// FIXME: Is this correct???
@@ -19,7 +36,13 @@
if (typeof window["cpSavePanel"] === "function")
{
var resultObject = window.cpSavePanel(),
var resultObject = window.cpSavePanel({
isExtensionHidden: _isExtensionHidden,
canSelectHiddenExtension: _canSelectHiddenExtension,
allowsOtherFileTypes: _allowsOtherFileTypes,
canCreateDirectories: _canCreateDirectories,
allowedFileTypes: _allowedFileTypes
}),
result = resultObject.button;
_URL = result ? [CPURL URLWithString:resultObject.URL] : nil;
+29 -25
View File
@@ -313,16 +313,14 @@
return;
_hasHorizontalScroller = shouldHaveHorizontalScroller;
if (_hasHorizontalScroller && !_horizontalScroller)
[self setHorizontalScroller:[[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, _CGRectGetWidth([self bounds]), [CPScroller scrollerWidth])]];
else if (!_hasHorizontalScroller && _horizontalScroller)
{
[_horizontalScroller setHidden:YES];
[self reflectScrolledClipView:_contentView];
[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];
}
/*!
@@ -378,14 +376,12 @@
_hasVerticalScroller = shouldHaveVerticalScroller;
if (_hasVerticalScroller && !_verticalScroller)
[self setVerticalScroller:[[CPScroller alloc] initWithFrame:_CGRectMake(0.0, 0.0, [CPScroller scrollerWidth], _CGRectGetHeight([self bounds]))]];
else if (!_hasVerticalScroller && _verticalScroller)
{
[_verticalScroller setHidden:YES];
[self reflectScrolledClipView:_contentView];
[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];
}
/*!
@@ -726,16 +722,18 @@
@end
var CPScrollViewContentViewKey = "CPScrollViewContentView",
CPScrollViewVLineScrollKey = "CPScrollViewVLineScroll",
CPScrollViewHLineScrollKey = "CPScrollViewHLineScroll",
CPScrollViewVPageScrollKey = "CPScrollViewVPageScroll",
CPScrollViewHPageScrollKey = "CPScrollViewHPageScroll",
CPScrollViewHasVScrollerKey = "CPScrollViewHasVScroller",
CPScrollViewHasHScrollerKey = "CPScrollViewHasHScroller",
CPScrollViewVScrollerKey = "CPScrollViewVScroller",
CPScrollViewHScrollerKey = "CPScrollViewHScroller",
CPScrollViewAutohidesScrollerKey = "CPScrollViewAutohidesScroller";
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)
@@ -750,6 +748,7 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView",
_horizontalPageScroll = [aCoder decodeFloatForKey:CPScrollViewHPageScrollKey];
_contentView = [aCoder decodeObjectForKey:CPScrollViewContentViewKey];
_headerClipView = [aCoder decodeObjectForKey:CPScrollViewHeaderClipViewKey];
_verticalScroller = [aCoder decodeObjectForKey:CPScrollViewVScrollerKey];
_horizontalScroller = [aCoder decodeObjectForKey:CPScrollViewHScrollerKey];
@@ -757,7 +756,9 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView",
_hasVerticalScroller = [aCoder decodeBoolForKey:CPScrollViewHasVScrollerKey];
_hasHorizontalScroller = [aCoder decodeBoolForKey:CPScrollViewHasHScrollerKey];
_autohidesScrollers = [aCoder decodeBoolForKey:CPScrollViewAutohidesScrollerKey];
_cornerView = [aCoder decodeObjectForKey:CPScrollViewCornerViewKey];
// Do to the anything goes nature of decoding, our subviews may not exist yet, so layout at the end of the run loop when we're sure everything is in a correct state.
[[CPRunLoop currentRunLoop] performSelector:@selector(reflectScrolledClipView:) target:self argument:_contentView order:0 modes:[CPDefaultRunLoopMode]];
}
@@ -770,7 +771,8 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView",
[super encodeWithCoder:aCoder];
[aCoder encodeObject:_contentView forKey:CPScrollViewContentViewKey];
[aCoder encodeObject:_headerClipView forKey:CPScrollViewHeaderClipViewKey];
[aCoder encodeObject:_verticalScroller forKey:CPScrollViewVScrollerKey];
[aCoder encodeObject:_horizontalScroller forKey:CPScrollViewHScrollerKey];
@@ -782,6 +784,8 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView",
[aCoder encodeBool:_hasVerticalScroller forKey:CPScrollViewHasVScrollerKey];
[aCoder encodeBool:_hasHorizontalScroller forKey:CPScrollViewHasHScrollerKey];
[aCoder encodeBool:_autohidesScrollers forKey:CPScrollViewAutohidesScrollerKey];
[aCoder encodeObject:_cornerView forKey:CPScrollViewCornerViewKey];
}
@end
+30 -10
View File
@@ -79,7 +79,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[ nil, nil, nil, nil,
return [CPDictionary dictionaryWithObjects:[ [CPNull null], [CPNull null], [CPNull null], [CPNull null],
_CGSizeMakeZero(), _CGSizeMakeZero(), _CGInsetMakeZero(), _CGInsetMakeZero(), _CGSizeMakeZero()]
forKeys:[ @"knob-slot-color",
@"decrement-line-color",
@@ -235,21 +235,21 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
*/
- (void)checkSpaceForParts
{
var bounds = [self bounds];
var bounds = [self bounds];
// Assume we won't be needing the arrows.
if (_knobProportion === 1.0)
{
_usableParts = CPNoScrollerParts;
_partRects[CPScrollerDecrementPage] = _CGRectMakeZero();
_partRects[CPScrollerKnob] = _CGRectMakeZero();
_partRects[CPScrollerIncrementPage] = _CGRectMakeZero();
_partRects[CPScrollerDecrementLine] = _CGRectMakeZero();
_partRects[CPScrollerIncrementLine] = _CGRectMakeZero();
_partRects[CPScrollerDecrementPage] = CGRectMakeZero();
_partRects[CPScrollerKnob] = CGRectMakeZero();
_partRects[CPScrollerIncrementPage] = CGRectMakeZero();
_partRects[CPScrollerDecrementLine] = CGRectMakeZero();
_partRects[CPScrollerIncrementLine] = CGRectMakeZero();
// In this case, the slot is the entirety of the scroller.
_partRects[CPScrollerKnobSlot] = _CGRectMakeCopy(bounds);
_partRects[CPScrollerKnobSlot] = CGRectMakeCopy(bounds);
return;
}
@@ -279,8 +279,18 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
_partRects[CPScrollerIncrementPage] = _CGRectMake(0.0, knobLocation + knobHeight, width, height - (knobLocation + knobHeight) - effectiveIncrementLineHeight);
_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);
}
_partRects[CPScrollerIncrementLine] = _CGRectMake(0.0, height - incrementLineSize.height, incrementLineSize.width, incrementLineSize.height);
if(height < knobHeight + decrementLineSize.height + incrementLineSize.height + trackInset.top + trackInset.bottom)
_partRects[CPScrollerKnob] = _CGRectMakeZero();
if(height < decrementLineSize.height + incrementLineSize.height - 2)
{
_partRects[CPScrollerIncrementLine] = _CGRectMakeZero();
_partRects[CPScrollerDecrementLine] = _CGRectMakeZero();
_partRects[CPScrollerKnobSlot] = _CGRectMake(trackInset.left, 0, width - trackInset.left - trackInset.right, height);
}
}
else
{
@@ -300,6 +310,16 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
_partRects[CPScrollerKnobSlot] = _CGRectMake(effectiveDecrementLineWidth, trackInset.top, slotWidth, height - trackInset.top - trackInset.bottom);
_partRects[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
_partRects[CPScrollerIncrementLine] = _CGRectMake(width - incrementLineSize.width, 0.0, incrementLineSize.width, incrementLineSize.height);
if(width < knobWidth + decrementLineSize.width + incrementLineSize.width + trackInset.left + trackInset.right)
_partRects[CPScrollerKnob] = _CGRectMakeZero();
if(width < decrementLineSize.width + incrementLineSize.width - 2)
{
_partRects[CPScrollerIncrementLine] = _CGRectMakeZero();
_partRects[CPScrollerDecrementLine] = _CGRectMakeZero();
_partRects[CPScrollerKnobSlot] = _CGRectMake(0.0, 0.0, width, slotHeight);
}
}
}
+171 -135
View File
@@ -89,40 +89,35 @@ var CPSearchFieldSearchImage = nil,
{
self = [super initWithFrame:frame];
if (self != nil)
{
_recentSearches = [CPArray array];
_maximumRecents = 10;
_sendsWholeSearchString = NO;
_sendsSearchStringImmediately = NO;
[self setBezeled:YES];
[self setBezelStyle:CPTextFieldRoundedBezel];
[self setBordered:YES];
[self setEditable:YES];
[self setDelegate:self];
_cancelButton = [[CPButton alloc] initWithFrame:CPMakeRect(frame.size.width - 27,(frame.size.height-22)/2,22,22)];
[self resetCancelButton];
[_cancelButton setHidden:YES];
[_cancelButton setAutoresizingMask:CPViewMinXMargin];
[self addSubview:_cancelButton];
_searchButton = [[CPButton alloc] initWithFrame:CPMakeRect(5,(frame.size.height-25)/2,25,25)];
[_searchButton setBezelStyle:CPRegularSquareBezelStyle];
[_searchButton setAutoresizingMask:CPViewMaxXMargin]
[_searchButton setBordered:NO];
[_searchButton setImageScaling:CPScaleToFit];
{
_recentSearches = [CPArray array];
_maximumRecents = 10;
_sendsWholeSearchString = NO;
_sendsSearchStringImmediately = NO;
_recentsAutosaveName = nil;
[self setBezeled:YES];
[self setBezelStyle:CPTextFieldRoundedBezel];
[self setBordered:YES];
[self setEditable:YES];
[self setDelegate:self];
_cancelButton = [[CPButton alloc] initWithFrame:CPMakeRect(frame.size.width - 27,(frame.size.height-22)/2,22,22)];
[self resetCancelButton];
[_cancelButton setHidden:YES];
[_cancelButton setAutoresizingMask:CPViewMinXMargin];
[self addSubview:_cancelButton];
_searchButton = [[CPButton alloc] initWithFrame:CPMakeRect(5,(frame.size.height-25)/2,25,25)];
[self resetSearchButton];
[self addSubview:_searchButton];
#if PLATFORM(DOM)
_cancelButton._DOMElement.style.cursor = "default";
_searchButton._DOMElement.style.cursor = "default";
#endif
[self setSearchMenuTemplate:[self _searchMenuTemplate]];
[self addSubview:_searchButton];
}
}
return self;
}
@@ -133,11 +128,13 @@ var CPSearchFieldSearchImage = nil,
[copy setCancelButton:[_cancelButton copy]];
[copy setSearchButton:[_searchButton copy]];
[copy setrecentsAutosaveName:[_recentsAutosaveName copy]];
[copy setSendsWholeSearchString:[_sendsWholeSearchString copy]];
[copy setSendsSearchStringImmediately:[_sendsSearchStringImmediately copy]];
[copy setMaximumRecents:_maximumRecents];
[copy setSearchMenutemplate:[_searchMenuTemplate copy]];
if (_recentsAutosaveName)
[copy setrecentsAutosaveName:[_recentsAutosaveName copy]];
if (_searchMenuTemplate)
[copy setSearchMenutemplate:[_searchMenuTemplate copy]];
return copy;
}
@@ -172,11 +169,11 @@ var CPSearchFieldSearchImage = nil,
target,
button = [self searchButton];
if (_searchMenuTemplate == nil)
if (_searchMenuTemplate === nil)
{
searchButtonImage = CPSearchFieldSearchImage;
action = [self action];
target = [self target];
action = @selector(_sendAction:);
target = self;
}
else
{
@@ -185,7 +182,10 @@ var CPSearchFieldSearchImage = nil,
target = self;
}
[button setBordered:NO];
[button setImageScaling:CPScaleToFit];
[button setImage:searchButtonImage];
[button setAutoresizingMask:CPViewMaxXMargin];
[button setTarget:target];
[button setAction:action];
}
@@ -215,11 +215,11 @@ var CPSearchFieldSearchImage = nil,
- (void)resetCancelButton
{
var button = [self cancelButton];
[button setBezelStyle:CPRegularSquareBezelStyle];
[button setBordered:NO];
[button setImageScaling:CPScaleToFit];
[button setImage:CPSearchFieldCancelImage];
[button setAlternateImage:CPSearchFieldCancelPressedImage];
[button setAutoresizingMask:CPViewMinXMargin];
[button setTarget:self];
[button setAction:@selector(_searchFieldCancel:)];
}
@@ -255,7 +255,7 @@ var CPSearchFieldSearchImage = nil,
@param rect The current bounding rectangle for the search button.
Subclasses can override this method to return a new bounding rectangle for the search button. You might use this method to provide a custom layout for the search field control.
*/
- (CPRect)searchButtonRectForBounds:(CPRect)rect // fix
- (CPRect)searchButtonRectForBounds:(CPRect)rect
{
return [_searchButton frame];
}
@@ -290,6 +290,7 @@ var CPSearchFieldSearchImage = nil,
_searchMenuTemplate = menu;
[self resetSearchButton];
[self _loadRecentSearchList];
[self _updateSearchMenu];
}
@@ -370,10 +371,10 @@ var CPSearchFieldSearchImage = nil,
*/
- (void)setRecentSearches:(CPArray)searches
{
var max = MIN([self maximumRecents],[searches count]);
var searches = [searches subarrayWithRange:CPMakeRange(0,max)];
_recentSearches = searches;
var max = MIN([self maximumRecents], [searches count]),
searches = [searches subarrayWithRange:CPMakeRange(0, max)];
_recentSearches = searches;
[self _autosaveRecentSearchList];
}
@@ -392,12 +393,13 @@ var CPSearchFieldSearchImage = nil,
*/
- (void)setRecentsAutosaveName:(CPString)name
{
if (_recentsAutosaveName != nil)
[self _deregisterForAutosaveNotification];
_recentsAutosaveName = name;
if(name != nil)
if (_recentsAutosaveName != nil)
[self _registerForAutosaveNotification];
else
[self _deregisterForAutosaveNotification];
}
// Private methods and subclassing
@@ -425,95 +427,110 @@ var CPSearchFieldSearchImage = nil,
- (void)_updateCancelButtonVisibility
{
[_cancelButton setHidden:([[self stringValue] length] == 0)];
[_cancelButton setHidden:([[self stringValue] length] === 0)];
}
- (void)controlTextDidChange:(CPNotification)aNotification
{
if(!_sendsWholeSearchString)
if (![self sendsWholeSearchString])
{
if(_sendsSearchStringImmediately)
if ([self sendsSearchStringImmediately])
[self _sendPartialString];
else
{
[_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];
}
- (void)_sendAction:(id)sender
{
[self sendAction:[self action] to:[self target]];
}
- (void)sendAction:(SEL)anAction to:(id)anObject
{
[super sendAction:anAction to:anObject];
[_partialStringTimer invalidate];
var current_value = [self objectValue];
if(current_value != nil && current_value != "" && ![_recentSearches containsObject:current_value])
{
[self _addStringToRecentSearches:current_value];
[self _updateSearchMenu];
}
[self _addStringToRecentSearches:[self stringValue]];
[self _updateCancelButtonVisibility];
}
- (void)_addStringToRecentSearches:(CPString)string
{
var newSearches = [CPMutableArray arrayWithArray:_recentSearches];
[newSearches addObject:string];
[self setRecentSearches:newSearches];
if (string === nil || string === @"" || [_recentSearches containsObject:string])
return;
var searches = [CPMutableArray arrayWithArray:_recentSearches];
[searches addObject:string];
[self setRecentSearches:searches];
[self _updateSearchMenu];
}
- (BOOL)trackMouse:(CPEvent)event
{
var rect;
var point;
var location = [event locationInWindow];
var rect,
point,
location = [event locationInWindow];
point = [self convertPoint:location fromView:nil];
rect = [self searchButtonRectForBounds:[self frame]];
if (CPRectContainsPoint(rect,point))
{
return [[self searchButton] trackMouse:event];
}
{
return [[self searchButton] trackMouse:event];
}
rect = [self cancelButtonRectForBounds:[self frame]];
if (CPRectContainsPoint(rect,point))
{
return [[self cancelButton] trackMouse:event];
}
{
return [[self cancelButton] trackMouse:event];
}
return [super trackMouse:event];
}
- (CPMenu)_searchMenuTemplate
- (CPMenu)_defaultSearchMenuTemplate
{
var template, item;
template = [[CPMenu alloc] init];
item = [[CPMenuItem alloc] initWithTitle:@"Recent searches" action:NULL keyEquivalent:@""];
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:) keyEquivalent:@""];
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:) keyEquivalent:@""];
item = [[CPMenuItem alloc] initWithTitle:@"Clear recent searches"
action:@selector(_searchFieldClearRecents:)
keyEquivalent:@""];
[item setTag:CPSearchFieldClearRecentsMenuItemTag];
[item setTarget:self];
[template addItem:item];
item = [[CPMenuItem alloc] initWithTitle:@"No recent searches" action:NULL keyEquivalent:@""];
item = [[CPMenuItem alloc] initWithTitle:@"No recent searches"
action:NULL
keyEquivalent:@""];
[item setTag:CPSearchFieldNoRecentsMenuItemTag];
[item setEnabled:NO];
[template addItem:item];
@@ -523,41 +540,56 @@ var CPSearchFieldSearchImage = nil,
- (void)_updateSearchMenu
{
if(_searchMenuTemplate == nil)
if (_searchMenuTemplate === nil)
return;
var i, menu = [[CPMenu alloc] init];
var countOfRecents = [_recentSearches count];
var i, menu = [[CPMenu alloc] init],
countOfRecents = [_recentSearches count],
numberOfItems = [_searchMenuTemplate numberOfItems];
for (i = 0; i < [_searchMenuTemplate numberOfItems]; i++)
for (i = 0; i < numberOfItems; i++)
{
var item = [_searchMenuTemplate itemAtIndex:i];
var tag = [item tag];
var item = [_searchMenuTemplate itemAtIndex:i],
tag = [item tag];
if(tag == CPSearchFieldClearRecentsMenuItemTag && countOfRecents != 0)
if (!(tag === CPSearchFieldRecentsTitleMenuItemTag && countOfRecents === 0) &&
!(tag === CPSearchFieldClearRecentsMenuItemTag && countOfRecents === 0) &&
!(tag === CPSearchFieldNoRecentsMenuItemTag && countOfRecents != 0) &&
!(tag === CPSearchFieldRecentsMenuItemTag))
{
var separator = [CPMenuItem separatorItem];
[menu addItem:separator];
}
var itemAction, itemTarget;
switch (tag)
{
case CPSearchFieldRecentsTitleMenuItemTag : itemAction = NULL; itemTarget = NULL; break;
case CPSearchFieldClearRecentsMenuItemTag : itemAction = @selector(_searchFieldClearRecents:); itemTarget = self; break;
case CPSearchFieldNoRecentsMenuItemTag : itemAction = NULL; itemTarget = NULL; break;
default: itemAction = [item action]; itemTarget = [item target]; break;
}
if (tag === CPSearchFieldClearRecentsMenuItemTag || tag === CPSearchFieldRecentsTitleMenuItemTag)
{
var separator = [CPMenuItem separatorItem];
[separator setEnabled:NO];
[menu addItem:separator];
}
if (!(tag == CPSearchFieldRecentsTitleMenuItemTag && countOfRecents == 0) &&
!(tag == CPSearchFieldClearRecentsMenuItemTag && countOfRecents == 0) &&
!(tag == CPSearchFieldNoRecentsMenuItemTag && countOfRecents != 0) &&
!(tag == CPSearchFieldRecentsMenuItemTag))
{
var templateItem = [[CPMenuItem alloc] initWithTitle:[item title] action:[item action] keyEquivalent:[item keyEquivalent]];
[templateItem setTarget:[item target]];
[templateItem setEnabled:[item isEnabled]];
[templateItem setTag:[item tag]];
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)
else if (tag === CPSearchFieldRecentsMenuItemTag)
{
var j;
for (j = 0; j < countOfRecents; j++)
{
var rencentItem = [[CPMenuItem alloc] initWithTitle:[_recentSearches objectAtIndex:j] action:[item action] keyEquivalent:[item keyEquivalent]];
[rencentItem setTarget:[item target]];
var rencentItem = [[CPMenuItem alloc] initWithTitle:[_recentSearches objectAtIndex:j]
action:@selector(_searchFieldSearch:)
keyEquivalent:[item keyEquivalent]];
[rencentItem setTarget:self];
[menu addItem:rencentItem];
}
}
@@ -565,16 +597,15 @@ var CPSearchFieldSearchImage = nil,
_searchMenu = menu;
}
- (void)_showMenu:(id)sender
{
if(_searchMenu == nil || ![self isEnabled])
if (_searchMenu === nil || [_searchMenu numberOfItems] === 0 || ![self isEnabled])
return;
[super selectText:nil];
var aFrame = [[self superview] convertRect:[self frame] toView:nil],
location = CPMakePoint(aFrame.origin.x + 10, aFrame.origin.y + aFrame.size.height - 4);
var origin = CPMakePoint([self frame].origin.x, [self frame].origin.y + [self frame].size.height);
var anEvent = [CPEvent keyEventWithType:CPRightMouseDown location:origin modifierFlags:0 timestamp:[CPDate date] windowNumber:1 context:[[CPGraphicsContext currentContext] graphicsPort] characters:"" charactersIgnoringModifiers:"" isARepeat:NO keyCode:0];
var anEvent = [CPEvent mouseEventWithType:CPRightMouseDown location:location modifierFlags:0 timestamp:[[CPApp currentEvent] timestamp] windowNumber:[[self window] windowNumber] context:nil eventNumber:1 clickCount:1 pressure:0];
[CPMenu popUpContextMenu:_searchMenu withEvent:anEvent forView:sender];
}
@@ -586,16 +617,21 @@ var CPSearchFieldSearchImage = nil,
- (void)_searchFieldCancel:(id)sender
{
[self setObjectValue:nil];
[self setObjectValue:@""];
[self _sendPartialString];
[self _updateCancelButtonVisibility];
[sender setHidden:YES];
}
- (void)_searchFieldSearch:(id)sender
{
[self setObjectValue:[sender title]];
var searchString = [sender title];
if ([sender tag] != CPSearchFieldRecentsMenuItemTag)
[self _addStringToRecentSearches:searchString];
[self setObjectValue:searchString];
[self _sendPartialString];
[self _updateCancelButtonVisibility];
}
@@ -615,52 +651,48 @@ var CPSearchFieldSearchImage = nil,
[[CPNotificationCenter defaultCenter] removeObserver:self name:@"CPAutosavedRecentsChangedNotification" object:nil];
}
- (void)_updateAutosavedRecents:(id)notification
{
var name = [notification object];
var list = [self recentSearches];
[[CPUserDefaults standardUserDefaults] setObject:list forKey:name];
}
- (void)_autosaveRecentSearchList
{
if(_recentsAutosaveName != nil)
if (_recentsAutosaveName != nil)
[[CPNotificationCenter defaultCenter] postNotificationName:@"CPAutosavedRecentsChangedNotification" object:_recentsAutosaveName];
}
- (void)_updateAutosavedRecents:(id)notification
{
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 list,
name = [self recentsAutosaveName];
list = [[CPUserDefaults standardUserDefaults] objectForKey:name];
_recentSearches = list;
}
if (name === nil)
return;
/*
- (BOOL)trackMouse:(CPEvent)theEvent inRect:(CPRect)cellFrame ofView:(CPView)aTextView untilMouseUp:(BOOL)flag
{
}
var bundle_name = [[[CPBundle mainBundle] infoDictionary] objectForKey:"CPBundleName"],
cookie_name = [bundle_name lowercaseString] + "." + name,
- (BOOL)_trimRecentSearchList
{
}
cookie = [[CPCookie alloc] initWithName:cookie_name];
- (void)_trackButton:(CPButton)button forEvent:(CPEvent)event inRect:(CPRect)rect ofView:(id)view
{
if (cookie != nil)
{
var cookie_value = [cookie value];
list = (cookie_value != @"") ? [cookie_value componentsSeparatedByString:@","] : [CPArray array];
_recentSearches = list;
}
}
- (id)_selectOrEdit:(CPRect)rect inView:(id)view target:(id)target editor:(id)editor event:(id)event start:(int)start end:(int)end
{
}
- (void)resetCursorRect:(CPRect)rect inView:(id)view
{
}
*/
@end
var CPSearchButtonKey = @"CPSearchButtonKey",
@@ -679,11 +711,13 @@ var CPSearchButtonKey = @"CPSearchButtonKey",
[coder encodeObject:_searchButton forKey:CPSearchButtonKey];
[coder encodeObject:_cancelButton forKey:CPCancelButtonKey];
[coder encodeObject:_recentsAutosaveName forKey:CPRecentsAutosaveNameKey];
[coder encodeBool:_sendsWholeSearchString forKey:CPSendsWholeSearchStringKey];
[coder encodeBool:_sendsSearchStringImmediately forKey:CPSendsSearchStringImmediatelyKey];
[coder encodeInt:_maximumRecents forKey:CPMaximumRecentsKey];
[coder encodeObject:_searchMenuTemplate forKey:CPSearchMenuTemplateKey];
if (_recentsAutosaveName)
[coder encodeObject:_recentsAutosaveName forKey:CPRecentsAutosaveNameKey];
if (_searchMenuTemplate)
[coder encodeObject:_searchMenuTemplate forKey:CPSearchMenuTemplateKey];
}
- (id)initWithCoder:(CPCoder)coder
@@ -696,8 +730,10 @@ var CPSearchButtonKey = @"CPSearchButtonKey",
_sendsWholeSearchString = [coder decodeBoolForKey:CPSendsWholeSearchStringKey];
_sendsSearchStringImmediately = [coder decodeBoolForKey:CPSendsSearchStringImmediatelyKey];
_maximumRecents = [coder decodeIntForKey:CPMaximumRecentsKey];
[self setSearchMenuTemplate:[coder decodeObjectForKey:CPSearchMenuTemplateKey]];
[self resetCancelButton];
var template = [coder decodeObjectForKey:CPSearchMenuTemplateKey];
if (template)
[self setSearchMenuTemplate:template];
[self setDelegate:self];
return self;
+43 -35
View File
@@ -26,20 +26,8 @@
#include "CoreGraphics/CGGeometry.h"
/*
@global
@group CPSegmentSwitchTracking
*/
CPSegmentSwitchTrackingSelectOne = 0;
/*
@global
@group CPSegmentSwitchTracking
*/
CPSegmentSwitchTrackingSelectAny = 1;
/*
@global
@group CPSegmentSwitchTracking
*/
CPSegmentSwitchTrackingMomentary = 2;
/*!
@@ -68,7 +56,7 @@ CPSegmentSwitchTrackingMomentary = 2;
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[CPCenterTextAlignment, CPCenterVerticalTextAlignment, CPImageLeft, CPScaleNone, _CGInsetMakeZero(), _CGInsetMakeZero(), nil, nil, nil, nil, 1.0, 24.0]
return [CPDictionary dictionaryWithObjects:[CPCenterTextAlignment, CPCenterVerticalTextAlignment, CPImageLeft, CPScaleNone, _CGInsetMakeZero(), _CGInsetMakeZero(), [CPNull null], [CPNull null], [CPNull null], [CPNull null], 1.0, 24.0]
forKeys:[@"alignment", @"vertical-alignment", @"image-position", @"image-scaling", @"bezel-inset", @"content-inset", @"left-segment-bezel-color", @"right-segment-bezel-color", @"center-segment-bezel-color", @"divider-bezel-color", @"divider-thickness", @"default-height"]];
}
@@ -375,7 +363,10 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (void)setEnabled:(BOOL)isEnabled forSegment:(unsigned)aSegment
{
_segments[aSegment].enabled = isEnabled;
if (isEnabled)
_themeStates[aSegment] &= ~CPThemeStateDisabled;
else
_themeStates[aSegment] |= CPThemeStateDisabled;
[self setNeedsLayout];
[self setNeedsDisplay:YES];
@@ -388,7 +379,7 @@ CPSegmentSwitchTrackingMomentary = 2;
*/
- (BOOL)isEnabledForSegment:(unsigned)aSegment
{
return _segments[aSegment].enabled;
return !(_themeStates[aSegment] & CPThemeStateDisabled)
}
/*!
@@ -462,30 +453,28 @@ CPSegmentSwitchTrackingMomentary = 2;
}
else if (aName === "right-segment-bezel")
{
var lastSegmentLeftOffset = [self _leftOffsetForSegment:[self _indexOfLastSegment]];
return CPRectMake(lastSegmentLeftOffset + [self widthForSegment:[self _indexOfLastSegment]] - contentInset.right,
return CPRectMake(CGRectGetWidth([self bounds]) - contentInset.right,
bezelInset.top,
contentInset.right,
height);
}
else if (aName.substring(0, "segment-bezel".length) == "segment-bezel")
else if (aName.indexOf("segment-bezel") === 0)
{
var segment = parseInt(aName.substring("segment-bezel-".length), 10),
frame = CGRectCreateCopy(_segments[segment].frame);
if (segment == 0)
if (segment === 0)
{
frame.origin.x += contentInset.left;
frame.size.width -= contentInset.left;
}
if (segment == _segments.length - 1)
frame.size.width -= contentInset.right;
if (segment === _segments.length - 1)
frame.size.width = CGRectGetWidth([self bounds]) - contentInset.right - frame.origin.x;
return frame;
}
else if (aName.substring(0, "divider-bezel".length) == "divider-bezel")
else if (aName.indexOf("divider-bezel") === 0)
{
var segment = parseInt(aName.substring("divider-bezel-".length), 10),
width = [self widthForSegment:segment],
@@ -494,7 +483,7 @@ CPSegmentSwitchTrackingMomentary = 2;
return CGRectMake(left + width, bezelInset.top, thickness, height);
}
else if (aName.substring(0, "segment-content".length) == "segment-content")
else if (aName.indexOf("segment-content") === 0)
{
var segment = parseInt(aName.substring("segment-content-".length), 10);
@@ -517,8 +506,12 @@ CPSegmentSwitchTrackingMomentary = 2;
if (_segments.length <= 0)
return;
var themeState = _themeStates[0];
themeState |= _themeState & CPThemeStateDisabled;
var leftCapColor = [self valueForThemeAttribute:@"left-segment-bezel-color"
inState:_themeStates[0]];
inState:themeState];
var leftBezelView = [self layoutEphemeralSubviewNamed:@"left-segment-bezel"
positioned:CPWindowBelow
@@ -526,8 +519,12 @@ CPSegmentSwitchTrackingMomentary = 2;
[leftBezelView setBackgroundColor:leftCapColor];
var themeState = _themeStates[_themeStates.length - 1];
themeState |= _themeState & CPThemeStateDisabled;
var rightCapColor = [self valueForThemeAttribute:@"right-segment-bezel-color"
inState:_themeStates[_themeStates.length - 1]];
inState:themeState];
var rightBezelView = [self layoutEphemeralSubviewNamed:@"right-segment-bezel"
positioned:CPWindowBelow
@@ -703,7 +700,16 @@ CPSegmentSwitchTrackingMomentary = 2;
while (count--)
if (CGRectContainsPoint(_segments[count].frame, aPoint))
return count;
if (_segments.length)
{
var adjustedLastFrame = CGRectCreateCopy(_segments[_segments.length - 1].frame);
adjustedLastFrame.size.width = CGRectGetWidth([self bounds]) - adjustedLastFrame.origin.x;
if (CGRectContainsPoint(adjustedLastFrame, aPoint))
return _segments.length - 1;
}
return -1;
}
@@ -734,7 +740,7 @@ CPSegmentSwitchTrackingMomentary = 2;
if (_trackingSegment == -1)
return;
if (CGRectContainsPoint(_segments[_trackingSegment].frame, location))
if (_trackingSegment === [self testSegment:location])
{
if (_trackingMode == CPSegmentSwitchTrackingSelectAny)
{
@@ -765,10 +771,13 @@ CPSegmentSwitchTrackingMomentary = 2;
if (type == CPLeftMouseDown)
{
_trackingHighlighted = YES;
_trackingSegment = [self testSegment:location];
[self drawSegmentBezel:_trackingSegment highlight:YES];
var trackingSegment = [self testSegment:location];
if (trackingSegment > -1 && [self isEnabledForSegment:trackingSegment])
{
_trackingHighlighted = YES;
_trackingSegment = trackingSegment;
[self drawSegmentBezel:_trackingSegment highlight:YES];
}
}
else if (type == CPLeftMouseDragged)
@@ -776,12 +785,11 @@ CPSegmentSwitchTrackingMomentary = 2;
if (_trackingSegment == -1)
return;
var highlighted = CGRectContainsPoint(_segments[_trackingSegment].frame, location);
var highlighted = [self testSegment:location] === _trackingSegment;
if (highlighted != _trackingHighlighted)
{
_trackingHighlighted = highlighted;
[self drawSegmentBezel:_trackingSegment highlight:_trackingHighlighted];
}
}
+1 -1
View File
@@ -49,7 +49,7 @@ CPCircularSlider = 1;
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[nil, _CGSizeMakeZero(), 0.0, nil]
return [CPDictionary dictionaryWithObjects:[[CPNull null], _CGSizeMakeZero(), 0.0, [CPNull null]]
forKeys:[@"knob-color", @"knob-size", @"track-width", @"track-color"]];
}
+21 -17
View File
@@ -144,20 +144,21 @@ var CPSplitViewHorizontalImage = nil,
{
if (_isPaneSplitter == shouldBePaneSplitter)
return;
_isPaneSplitter = shouldBePaneSplitter;
#if PLATFORM(DOM)
_DOMDividerElements = [];
#endif
if(_DOMDividerElements[_drawingDivider])
[self _setupDOMDivider]
// The divider changes size when pane splitter mode is toggled, so the
// subviews need to change size too.
_needsResizeSubviews = YES;
[self setNeedsDisplay:YES];
}
- (void)didAddSubview:(CPView)aSubview
{
_needsResizeSubviews = YES;
// [self adjustSubviews];
}
- (BOOL)isSubviewCollapsed:(CPView)subview
@@ -213,16 +214,7 @@ var CPSplitViewHorizontalImage = nil,
CPDOMDisplayServerAppendChild(_DOMElement, _DOMDividerElements[_drawingDivider]);
if (_isPaneSplitter)
{
_DOMDividerElements[_drawingDivider].style.backgroundColor = "#A5A5A5";
_DOMDividerElements[_drawingDivider].style.backgroundImage = "";
}
else
{
_DOMDividerElements[_drawingDivider].style.backgroundColor = "";
_DOMDividerElements[_drawingDivider].style.backgroundImage = "url('"+_dividerImagePath+"')";
}
[self _setupDOMDivider];
}
CPDOMDisplayServerSetStyleLeftTop(_DOMDividerElements[_drawingDivider], NULL, _CGRectGetMinX(aRect), _CGRectGetMinY(aRect));
@@ -230,6 +222,20 @@ var CPSplitViewHorizontalImage = nil,
#endif
}
- (void)_setupDOMDivider
{
if (_isPaneSplitter)
{
_DOMDividerElements[_drawingDivider].style.backgroundColor = "#A5A5A5";
_DOMDividerElements[_drawingDivider].style.backgroundImage = "";
}
else
{
_DOMDividerElements[_drawingDivider].style.backgroundColor = "";
_DOMDividerElements[_drawingDivider].style.backgroundImage = "url('"+_dividerImagePath+"')";
}
}
- (void)viewWillDraw
{
[self _adjustSubviewsWithCalculatedSize];
@@ -512,8 +518,6 @@ var CPSplitViewHorizontalImage = nil,
}
else if (totalSizableSpace && !isSizable)
viewFrame.size[_sizeComponent] = [view frame].size[_sizeComponent];
else
alert("SHOULD NEVER GET HERE");
bounds.origin[_originComponent] += viewFrame.size[_sizeComponent] + dividerThickness;
+5 -1
View File
@@ -247,6 +247,8 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
[_labelsView tabView:self didAddTabViewItem:aTabViewItem];
[aTabViewItem _setTabView:self];
if ([_tabViewItems count] == 1)
[self selectFirstTabViewItem:self];
@@ -263,9 +265,11 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
var index = [self indexOfTabViewItem:aTabViewItem];
[_tabViewItems removeObjectIdenticalTo:aTabViewItem];
[_labelsView tabView:self didRemoveTabViewItemAtIndex:index];
[aTabViewItem _setTabView:nil];
if (_delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
[_delegate tabViewDidChangeNumberOfTabViewItems:self];
}
+10
View File
@@ -58,6 +58,8 @@ CPPressedTab = 2;
CPView _view;
CPView _auxiliaryView;
CPTabView _tabView;
}
- (id)init
@@ -168,6 +170,14 @@ CPPressedTab = 2;
return _tabView;
}
/*!
@ignore
*/
- (void)_setTabView:(CPTabView)aView
{
_tabView = aView;
}
@end
var CPTabViewItemIdentifierKey = "CPTabViewItemIdentifierKey",
+75 -44
View File
@@ -27,22 +27,11 @@
@import "CPTableHeaderView.j"
#include "CoreGraphics/CGGeometry.h"
/*
@global
@class CPTableColumn
*/
CPTableColumnNoResizing = 0;
/*
@global
@class CPTableColumn
*/
CPTableColumnAutoresizingMask = 1;
/*
@global
@class CPTableColumn
*/
CPTableColumnUserResizingMask = 2;
CPTableColumnAutoresizingMask = 1 << 0;
CPTableColumnUserResizingMask = 1 << 1;
@implementation CPTableColumn : CPObject
{
@@ -54,12 +43,15 @@ CPTableColumnUserResizingMask = 2;
float _width;
float _minWidth;
float _maxWidth;
unsigned _resizingMask;
id _identifier;
BOOL _isEditable;
CPSortDescriptor _sortDescriptorPrototype;
BOOL _isHidden;
CPString _headerToolTip;
BOOL _disableResizingPosting @accessors(property=disableResizingPosting);
}
- (id)init
@@ -78,15 +70,27 @@ CPTableColumnUserResizingMask = 2;
_width = 100.0;
_minWidth = 10.0;
_maxWidth = 1000000.0;
_resizingMask = CPTableColumnAutoresizingMask | CPTableColumnUserResizingMask;
_disableResizingPosting = NO;
[self setIdentifier:anIdentifier];
[self setHeaderView:[CPTextField new]];
[self setDataView:[CPTextField new]];
var header = [[_CPTableColumnHeaderView alloc] initWithFrame:CGRectMakeZero()];
[self setHeaderView:header];
var textDataView = [CPTextField new];
[textDataView setLineBreakMode:CPLineBreakByTruncatingTail];
[textDataView setValue:[CPColor colorWithHexString:@"333333"] forThemeAttribute:@"text-color"];
[textDataView setValue:[CPColor whiteColor] forThemeAttribute:@"text-color" inState:CPThemeStateHighlighted];
[textDataView setValue:[CPFont boldSystemFontOfSize:12] forThemeAttribute:@"font" inState:CPThemeStateHighlighted];
[textDataView setValue:CGInsetMake(4.0, 8.0, 0.0, 8.0) forThemeAttribute:@"content-inset"];
[self setDataView:textDataView];
}
return self;
}
- (void)setTableView:(CPTableView)aTableView
{
_tableView = aTableView;
@@ -117,18 +121,23 @@ CPTableColumnUserResizingMask = 2;
if (tableView)
{
var index = [[tableView tableColumns] indexOfObjectIdenticalTo:self];
// FIXME: THIS IS HORRIBLE. Don't just reload everything when a table column changes, just relayout the changed widths.
tableView._reloadAllRows = YES;
tableView._dirtyTableColumnRangeIndex = tableView._dirtyTableColumnRangeIndex < 0 ? index : MIN(index, tableView._dirtyTableColumnRangeIndex);
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)];
// 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];
[[CPNotificationCenter defaultCenter]
postNotificationName:CPTableViewColumnDidResizeNotification
object:tableView
userInfo:[CPDictionary dictionaryWithObjects:[self, oldWidth] forKeys:[@"CPTableColumn", "CPOldWidth"]]];
if (!_disableResizingPosting)
[self _postDidResizeNotificationWithOldWidth:oldWidth];
}
}
@@ -168,7 +177,7 @@ CPTableColumnUserResizingMask = 2;
_maxWidth = aMaxWidth;
var width = [self width],
newWidth = MAX(width, [self maxWidth]);
newWidth = MIN(width, [self maxWidth]);
if (width !== newWidth)
[self setWidth:newWidth];
@@ -184,7 +193,7 @@ CPTableColumnUserResizingMask = 2;
_resizingMask = aResizingMask;
}
- (float)resizingMask
- (unsigned)resizingMask
{
return _resizingMask;
}
@@ -221,6 +230,22 @@ CPTableColumnUserResizingMask = 2;
return _headerView;
}
/*!
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:
[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:
[someView setSomething:x];
[tableColumn setDataView:someView];
*/
- (void)setDataView:(CPView)aView
{
if (_dataView === aView)
@@ -256,9 +281,9 @@ CPTableColumnUserResizingMask = 2;
var dataView = [self dataViewForRow:aRowIndex],
dataViewUID = [dataView UID];
var x = [self tableView]._cachedDataViews[dataViewUID];
if (x && x.length)
return x.pop();
var x = [self tableView]._cachedDataViews[dataViewUID];
if (x && x.length)
return x.pop();
// if we haven't cached an archive of the data view, do it now
if (!_dataViewData[dataViewUID])
@@ -266,7 +291,8 @@ return x.pop();
// unarchive the data view cache
var newDataView = [CPKeyedUnarchiver unarchiveObjectWithData:_dataViewData[dataViewUID]];
newDataView.identifier = dataViewUID;
newDataView.identifier = dataViewUID;
return newDataView;
}
@@ -346,6 +372,14 @@ newDataView.identifier = dataViewUID;
return _headerToolTip;
}
- (void)_postDidResizeNotificationWithOldWidth:(float)oldWidth
{
[[CPNotificationCenter defaultCenter]
postNotificationName:CPTableViewColumnDidResizeNotification
object:[self tableView]
userInfo:[CPDictionary dictionaryWithObjects:[self, oldWidth] forKeys:[@"CPTableColumn", "CPOldWidth"]]];
}
@end
var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
@@ -371,14 +405,11 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
_maxWidth = [aCoder decodeFloatForKey:CPTableColumnMaxWidthKey];
[self setIdentifier:[aCoder decodeObjectForKey:CPTableColumnIdentifierKey]];
// [self setHeaderView:[aCoder decodeObjectForKey:CPTableColumnHeaderViewKey]];
// [self setDataView:[aCoder decodeObjectForKey:CPTableColumnDataViewKey]];
[self setHeaderView:[aCoder decodeObjectForKey:CPTableColumnHeaderViewKey]];
[self setDataView:[aCoder decodeObjectForKey:CPTableColumnDataViewKey]];
[self setHeaderView:[aCoder decodeObjectForKey:CPTableColumnHeaderViewKey]];
[self setHeaderView:[CPTextField new]];
[self setDataView:[CPTextField new]];
// _resizingMask = [aCoder decodeBoolForKey:CPTableColumnResizingMaskKey];
_resizingMask = [aCoder decodeBoolForKey:CPTableColumnResizingMaskKey];
}
return self;
@@ -392,10 +423,10 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
[aCoder encodeObject:_minWidth forKey:CPTableColumnMinWidthKey];
[aCoder encodeObject:_maxWidth forKey:CPTableColumnMaxWidthKey];
// [aCoder encodeObject:_headerView forKey:CPTableColumnHeaderViewKey];
// [aCoder encodeObject:_dataView forKey:CPTableColumnDataViewKey];
[aCoder encodeObject:_headerView forKey:CPTableColumnHeaderViewKey];
[aCoder encodeObject:_dataView forKey:CPTableColumnDataViewKey];
// [aCoder encodeObject:_resizingMask forKey:CPTableColumnResizingMaskKey];
[aCoder encodeObject:_resizingMask forKey:CPTableColumnResizingMaskKey];
}
@end
+417 -63
View File
@@ -23,14 +23,139 @@
@import "CPTableColumn.j"
@import "CPTableView.j"
@import "CPView.j"
var CPThemeStatePressed = CPThemeState("pressed");
@implementation _CPTableColumnHeaderView : CPView
{
_CPImageAndTextView _textField;
}
- (void)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
[self _init];
}
return self;
}
- (void)_init
{
_textField = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(5, 1, CGRectGetWidth([self bounds]) - 10, CGRectGetHeight([self bounds]) - 1)];
[_textField setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
[_textField setLineBreakMode:CPLineBreakByTruncatingTail];
[_textField setTextColor: [CPColor colorWithHexString: @"333333"]];
[_textField setFont:[CPFont boldSystemFontOfSize:12.0]];
[_textField setAlignment:CPLeftTextAlignment];
[_textField setVerticalAlignment:CPCenterVerticalTextAlignment];
[_textField setTextShadowColor:[CPColor whiteColor]];
[_textField setTextShadowOffset:CGSizeMake(0,1)];
[self addSubview:_textField];
}
- (void)layoutSubviews
{
var themeState = [self themeState];
if(themeState & CPThemeStateHighlighted && themeState & CPThemeStatePressed)
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-highlighted-pressed.png", CGSizeMake(1.0, 22.0))]];
else if (themeState & CPThemeStateHighlighted)
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview-highlighted.png", CGSizeMake(1.0, 22.0))]];
else if (themeState & CPThemeStatePressed)
[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
{
[_textField setText:string];
}
- (CPString)stringValue
{
return [_textField text];
}
- (void)textField
{
return _textField;
}
- (void)sizeToFit
{
[_textField sizeToFit];
}
- (void)setFont:(CPFont)aFont
{
[_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];
}
}
@end
var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringValueKey",
_CPTableColumnHeaderViewFontKey = @"_CPTableColumnHeaderViewFontKey",
_CPTableColumnHeaderViewImageKey = @"_CPTableColumnHeaderViewImageKey";
@implementation _CPTableColumnHeaderView (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
if (self = [super initWithCoder:aCoder])
{
[self _init];
[self _setIndicatorImage:[aCoder decodeObjectForKey:_CPTableColumnHeaderViewImageKey]];
[self setStringValue:[aCoder decodeObjectForKey:_CPTableColumnHeaderViewStringValueKey]];
[self setFont:[aCoder decodeObjectForKey:_CPTableColumnHeaderViewFontKey]];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:[_textField text] forKey:_CPTableColumnHeaderViewStringValueKey];
[aCoder encodeObject:[_textField image] forKey:_CPTableColumnHeaderViewImageKey];
[aCoder encodeObject:[_textField font] forKey:_CPTableColumnHeaderViewFontKey];
}
@end
@implementation CPTableHeaderView : CPView
{
int _resizedColumn @accessors(readonly, property=resizedColumn);
int _draggedColumn @accessors(readonly, property=draggedColumn);
int _pressedColumn @accessors(readonly, property=pressedColumn);
float _draggedDistance @accessors(readonly, property=draggedDistance);
float _lastLocation;
float _columnOldWidth;
CPTableView _tableView @accessors(property=tableView);
}
@@ -41,9 +166,14 @@
if (self)
{
_resizedColumn = CPNotFound;
_draggedColumn = CPNotFound;
_resizedColumn = -1;
_draggedColumn = -1;
_pressedColumn = -1;
_draggedDistance = 0.0;
_lastLocation = nil;
_columnOldWidth = nil;
[self setBackgroundColor:[CPColor colorWithPatternImage:CPAppKitImage("tableview-headerview.png", CGSizeMake(1.0, 22.0))]];
}
return self;
@@ -51,95 +181,319 @@
- (int)columnAtPoint:(CGPoint)aPoint
{
if (!CGRectContainsPoint([self bounds], aPoint))
return CPNotFound;
// at this point, we can essentially ignore height, because all columns have equal heights
// and that height is equal to the height of our own bounds, which we know we are inside of
var index = 0,
count = [[_tableView tableColumns] count],
tableSpacing = [_tableView intercellSpacing],
tableColumns = [_tableView tableColumns],
leftOffset = 0,
pointX = aPoint.x;
for (; index < count; index++)
{
var width = [tableColumns[index] width] + tableSpacing.width;
if (pointX >= leftOffset && pointX < leftOffset + width)
return index;
leftOffset += width;
}
return CPNotFound;
return [_tableView columnAtPoint:CGPointMake(aPoint.x, 0)];
}
- (CGRect)headerRectOfColumn:(int)aColumnIndex
{
var tableColumns = [_tableView tableColumns],
tableSpacing = [_tableView intercellSpacing],
bounds = [self bounds];
var tableColumns = [_tableView tableColumns];
if (aColumnIndex < 0 || aColumnIndex > [tableColumns count])
[CPException raise:"invalid" reason:"tried to get headerRectOfColumn: on invalid column"];
bounds.size.width = [tableColumns[aColumnIndex] width] + tableSpacing.width;
while (--aColumnIndex >= 0)
bounds.origin.x += [tableColumns[aColumnIndex] width] + tableSpacing.width;
// UPDATE COLUMN RANGES ?
var tableRange = _tableView._tableColumnRanges[aColumnIndex],
bounds = [self bounds];
bounds.origin.x = tableRange.location;
bounds.size.width = tableRange.length;
return bounds;
}
- (CGRect)_cursorRectForColumn:(int)column
{
if (column == -1 || !([_tableView._tableColumns[column] resizingMask] & CPTableColumnUserResizingMask))
return CGRectMakeZero();
var rect = [self headerRectOfColumn:column];
rect.origin.x = CGRectGetMaxX(rect) - 5;
rect.size.width = 20;
return rect;
}
- (void)_setPressedColumn:(CPInteger)column
{
if (_pressedColumn != -1)
{
var headerView = [_tableView._tableColumns[_pressedColumn] headerView];
[headerView unsetThemeState:CPThemeStatePressed];
}
if (column != -1)
{
var headerView = [_tableView._tableColumns[column] headerView];
[headerView setThemeState:CPThemeStatePressed];
}
_pressedColumn = column;
}
- (void)mouseDown:(CPEvent)theEvent
{
var mouseLocation = [self convertPoint:[theEvent locationInWindow] fromView:nil],
clickedColumn = [self columnAtPoint:mouseLocation];
// should we send column -1 ?
[_tableView _sendDelegateDidMouseDownInHeader:clickedColumn];
var resizeLocation = CGPointMake(mouseLocation.x - 5, mouseLocation.y),
resizedColumn = [self columnAtPoint:resizeLocation];
if (resizedColumn == -1)
return;
// 2 different tracking methods: one for resizing/stop-resizing, another one for selection/reordering
if ([_tableView allowsColumnResizing] && [_tableView columnAutoresizingStyle] & CPTableViewUniformColumnAutoresizingStyle
&& CGRectContainsPoint([self _cursorRectForColumn:resizedColumn], mouseLocation))
{
_resizedColumn = resizedColumn;
[_tableView._tableColumns[_resizedColumn] setDisableResizingPosting:YES];
[_tableView setDisableAutomaticResizing:YES];
[self trackResizeWithEvent:theEvent];
}
else
{
[self _setPressedColumn:clickedColumn];
[self trackMouseWithEvent:theEvent];
}
}
- (void)trackMouseWithEvent:(CPEvent)theEvent
{
var type = [theEvent type];
if (type == CPLeftMouseUp)
{
var location = [self convertPoint:[theEvent locationInWindow] fromView:nil],
clickedColumn = [self columnAtPoint:location];
[self _setPressedColumn:-1];
if (clickedColumn != -1)
[_tableView _didClickTableColumn:clickedColumn modifierFlags:[theEvent modifierFlags]];
return;
}
/*
else if (type & CPLeftMouseDragged && [_tableView allowsColumnREordering])
{
// Start dragging here
[[CPCursor closedHandCursor] set];
return;
}
*/
[CPApp setTarget:self selector:@selector(trackMouseWithEvent:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPLeftMouseDownMask untilDate:nil inMode:nil dequeue:YES];
}
- (void)trackResizeWithEvent:(CPEvent)anEvent
{
var location = [self convertPoint:[anEvent locationInWindow] fromView:nil],
tableColumn = [[_tableView tableColumns] objectAtIndex:_resizedColumn],
type = [anEvent type];
if (_lastLocation == nil)
_lastLocation = location;
if (_columnOldWidth == nil)
_columnOldWidth = [tableColumn width];
if (type === CPLeftMouseUp)
{
[self _updateResizeCursor:anEvent];
[tableColumn _postDidResizeNotificationWithOldWidth:_columnOldWidth];
[tableColumn setDisableResizingPosting:NO];
[_tableView setDisableAutomaticResizing:NO];
_resizedColumn = -1;
_lastLocation = nil;
_columnOldWidth = nil;
return;
}
else if (type === CPLeftMouseDragged)
{
var newWidth = [tableColumn width] + location.x - _lastLocation.x;
if (newWidth < [tableColumn minWidth])
[[CPCursor resizeRightCursor] set];
else if (newWidth > [tableColumn maxWidth])
[[CPCursor resizeLeftCursor] set];
else
{
[tableColumn setWidth:newWidth];
// FIXME: there has to be a better way to do this...
// We should refactor the auto resizing crap.
// We need to figure out the exact cocoa behavior here though.
[_tableView resizeWithOldSuperviewSize:[_tableView bounds]];
_lastLocation = location;
[[CPCursor resizeLeftRightCursor] set];
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
}
[CPApp setTarget:self selector:@selector(trackResizeWithEvent:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
}
- (void)_updateResizeCursor:(CPEvent)theEvent
{
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))
{
var tableColumn = [[_tableView tableColumns] objectAtIndex:overColumn],
width = [tableColumn width];
if (width == [tableColumn minWidth])
[[CPCursor resizeRightCursor] set];
else if (width == [tableColumn maxWidth])
[[CPCursor resizeLeftCursor] set];
else
[[CPCursor resizeLeftRightCursor] set];
}
else
[[CPCursor arrowCursor] set];
}
- (void)viewDidMoveToWindow
{
if ([_tableView allowsColumnResizing])
[[self window] setAcceptsMouseMovedEvents:YES];
}
- (void)mouseEntered:(CPEvent)theEvent
{
[self _updateResizeCursor:theEvent];
}
- (void)mouseMoved:(CPEvent)theEvent
{
[self _updateResizeCursor:theEvent];
}
- (void)mouseExited:(CPEvent)theEvent
{
// FIXME: we should use CPCursor push/pop (if previous currentCursor != arrow).
[[CPCursor arrowCursor] set];
}
- (void)layoutSubviews
{
var tableColumns = [_tableView tableColumns],
count = [tableColumns count],
columnRect = [self bounds],
spacing = [_tableView intercellSpacing];
for (i = 0; i < count; ++i)
var tableColumns = [_tableView tableColumns],
count = [tableColumns count];
for (var i = 0; i < count; i++)
{
var column = [tableColumns objectAtIndex:i],
headerView = [column headerView];
columnRect.size.width = [column width] + spacing.width;
[headerView setFrame:columnRect];
columnRect.origin.x += [column width] + spacing.width;
[self addSubview:headerView];
var frame = [self headerRectOfColumn:i];
frame.size.height -= 0.5;
if (i > 0)
{
frame.origin.x += 0.5;
frame.size.width -= 1;
}
[headerView setFrame:frame];
if([headerView superview] != self)
[self addSubview:headerView];
}
}
- (void)drawRect:(CGRect)aRect
{
[[_tableView gridColor] setStroke];
var context = [[CPGraphicsContext currentContext] graphicsPort],
exposedColumnIndexes = exposedColumnIndexes = [_tableView columnIndexesInRect:aRect],
columnsArray = [];
exposedColumnIndexes = [_tableView columnIndexesInRect:aRect],
columnsArray = [],
tableColumns = [_tableView tableColumns],
exposedTableColumns = _tableView._exposedColumns,
firstIndex = [exposedTableColumns firstIndex],
exposedRange = CPMakeRange(firstIndex, [exposedTableColumns lastIndex] - firstIndex + 1);
[exposedColumnIndexes getIndexes:columnsArray maxCount:-1 inIndexRange:nil];
CGContextSetLineWidth(context, 1);
CGContextSetStrokeColor(context, [_tableView gridColor]);
[exposedColumnIndexes getIndexes:columnsArray maxCount:-1 inIndexRange:exposedRange];
var columnArrayIndex = 0,
columnArrayCount = columnsArray.length;
for(; columnArrayIndex < columnArrayCount; ++columnArrayIndex)
columnArrayCount = columnsArray.length,
columnMaxX;
CGContextBeginPath(context);
for(; columnArrayIndex < columnArrayCount; columnArrayIndex++)
{
// grab each column rect and add horizontal lines
var columnToStroke = [self headerRectOfColumn:columnArrayIndex];
CGContextBeginPath(context);
CGContextMoveToPoint(context, ROUND(columnToStroke.origin.x + columnToStroke.size.width) - 0.5, ROUND(columnToStroke.origin.y) - 0.5);
CGContextAddLineToPoint(context, ROUND(columnToStroke.origin.x + columnToStroke.size.width) - 0.5, ROUND(columnToStroke.origin.y + columnToStroke.size.height) - 0.5);
CGContextSetLineWidth(context, 1);
CGContextStrokePath(context);
// grab each column rect and add vertical lines
var columnIndex = columnsArray[columnArrayIndex],
columnToStroke = [self headerRectOfColumn:columnIndex];
columnMaxX = CGRectGetMaxX(columnToStroke);
CGContextMoveToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(CGRectGetMinY(columnToStroke)));
CGContextAddLineToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(CGRectGetMaxY(columnToStroke)));
}
CGContextClosePath(context);
CGContextStrokePath(context);
/*
var maxY = CGRectGetMaxY([self bounds]);
// draw normal gradient for remaining space
if (supportsCanvasGradient)
{
aRect.origin.x = columnMaxX - 0.5;
aRect.size.width -= columnMaxX;
CGContextBeginPath(context);
CGContextAddRect(context, CGRectMake(columnMaxX + 1, 0, CGRectGetMaxX([self bounds]) - columnMaxX, CGRectGetHeight([self bounds])));
CGContextClosePath(context);
CGContextDrawLinearGradient(context, [_CPTableColumnHeaderView headerGradient], CGPointMake(0,0), CGPointMake(0, maxY - 1),0);
}
// Draw bottom line
CGContextBeginPath(context);
CGContextMoveToPoint(context, 0, maxY - 0.5);
CGContextAddLineToPoint(context, CGRectGetMaxX([self bounds]), maxY - 0.5);
CGContextClosePath(context);
CGContextStrokePath(context);
*/
}
@end
var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey";
@implementation CPTableHeaderView (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
if (self = [super initWithCoder:aCoder])
{
_resizedColumn = -1;
_draggedColumn = -1;
_pressedColumn = -1;
_draggedDistance = 0.0;
_lastLocation = nil;
_columnOldWidth = nil;
_tableView = [aCoder decodeObjectForKey:CPTableHeaderViewTableViewKey];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:_tableView forKey:CPTableHeaderViewTableViewKey];
}
@end
+1576 -97
View File
File diff suppressed because it is too large. Load diff
+234 -119
View File
@@ -29,14 +29,6 @@
#include "Platform/Platform.h"
#include "Platform/DOM/CPDOMDisplayServer.h"
CPLineBreakByWordWrapping = 0;
CPLineBreakByCharWrapping = 1;
CPLineBreakByClipping = 2;
CPLineBreakByTruncatingHead = 3;
CPLineBreakByTruncatingTail = 4;
CPLineBreakByTruncatingMiddle = 5;
CPTextFieldSquareBezel = 0; /*! A textfield bezel with a squared corners. */
CPTextFieldRoundedBezel = 1; /*! A textfield bezel with rounded corners. */
@@ -55,11 +47,7 @@ var CPTextFieldDOMInputElement = nil,
CPTextFieldInputIsActive = NO,
CPTextFieldCachedSelectStartFunction = nil,
CPTextFieldCachedDragFunction = nil,
CPTextFieldBlurFunction = nil,
CPTextFieldKeyUpFunction = nil,
CPTextFieldKeyPressFunction = nil,
CPTextFieldKeyDownFunction = nil;
CPTextFieldBlurFunction = nil;
#endif
@@ -173,7 +161,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[_CGInsetMakeZero(), _CGInsetMake(2.0, 2.0, 2.0, 2.0), nil]
return [CPDictionary dictionaryWithObjects:[_CGInsetMakeZero(), _CGInsetMake(2.0, 2.0, 2.0, 2.0), [CPNull null]]
forKeys:[@"bezel-inset", @"content-inset", @"bezel-color"]];
}
@@ -209,97 +197,13 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
return true;
}
CPTextFieldKeyDownFunction = function(aDOMEvent)
{
CPTextFieldTextDidChangeValue = [CPTextFieldInputOwner stringValue];
aDOMEvent = aDOMEvent || window.event;
if (aDOMEvent.keyCode == CPReturnKeyCode || aDOMEvent.keyCode == CPTabKeyCode)
CPTextFieldKeyPressFunction(aDOMEvent);
return true;
}
CPTextFieldKeyPressFunction = function(aDOMEvent)
{
aDOMEvent = aDOMEvent || window.event;
CPTextFieldKeyUpFunction();
if (aDOMEvent.keyCode == CPReturnKeyCode || aDOMEvent.keyCode == CPTabKeyCode)
{
if (aDOMEvent.preventDefault)
aDOMEvent.preventDefault();
if (aDOMEvent.stopPropagation)
aDOMEvent.stopPropagation();
aDOMEvent.cancelBubble = true;
var owner = CPTextFieldInputOwner;
if (aDOMEvent && aDOMEvent.keyCode == CPReturnKeyCode)
{
if (owner._isEditing)
{
owner._isEditing = NO;
[owner textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:owner userInfo:nil]];
}
[owner sendAction:[owner action] to:[owner target]];
[owner selectText:nil];
}
else if (aDOMEvent && aDOMEvent.keyCode == CPTabKeyCode)
{
if (!aDOMEvent.shiftKey)
[[owner window] selectNextKeyView:owner];
else
[[owner window] selectPreviousKeyView:owner];
}
}
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
}
CPTextFieldKeyUpFunction = function()
{
[CPTextFieldInputOwner _setStringValue:CPTextFieldDOMInputElement.value];
if ([CPTextFieldInputOwner stringValue] !== CPTextFieldTextDidChangeValue)
{
if (!CPTextFieldInputOwner._isEditing)
{
CPTextFieldInputOwner._isEditing = YES;
[CPTextFieldInputOwner textDidBeginEditing:[CPNotification notificationWithName:CPControlTextDidBeginEditingNotification object:CPTextFieldInputOwner userInfo:nil]];
}
[CPTextFieldInputOwner textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:CPTextFieldInputOwner userInfo:nil]];
CPTextFieldTextDidChangeValue = [CPTextFieldInputOwner stringValue];
}
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
}
CPTextFieldHandleBlur = function(anEvent)
{
var owner = CPTextFieldInputOwner;
CPTextFieldInputOwner = nil;
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
}
if (document.attachEvent)
{
CPTextFieldDOMInputElement.attachEvent("on" + CPDOMEventKeyUp, CPTextFieldKeyUpFunction);
CPTextFieldDOMInputElement.attachEvent("on" + CPDOMEventKeyDown, CPTextFieldKeyDownFunction);
CPTextFieldDOMInputElement.attachEvent("on" + CPDOMEventKeyPress, CPTextFieldKeyPressFunction);
}
else
{
CPTextFieldDOMInputElement.addEventListener(CPDOMEventKeyUp, CPTextFieldKeyUpFunction, NO);
CPTextFieldDOMInputElement.addEventListener(CPDOMEventKeyDown, CPTextFieldKeyDownFunction, NO);
CPTextFieldDOMInputElement.addEventListener(CPDOMEventKeyPress, CPTextFieldKeyPressFunction, NO);
}
//FIXME make this not onblur
CPTextFieldDOMInputElement.onblur = CPTextFieldBlurFunction;
@@ -330,10 +234,6 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
CPTextFieldDOMPasswordInputElement.style.outline = "none";
CPTextFieldDOMPasswordInputElement.type = "password";
CPTextFieldDOMPasswordInputElement.attachEvent("on" + CPDOMEventKeyUp, CPTextFieldKeyUpFunction);
CPTextFieldDOMPasswordInputElement.attachEvent("on" + CPDOMEventKeyDown, CPTextFieldKeyDownFunction);
CPTextFieldDOMPasswordInputElement.attachEvent("on" + CPDOMEventKeyPress, CPTextFieldKeyPressFunction);
CPTextFieldDOMPasswordInputElement.onblur = CPTextFieldBlurFunction;
}
@@ -593,11 +493,11 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
if (document.attachEvent)
{
CPTextFieldCachedSelectStartFunction = document.body.onselectstart;
CPTextFieldCachedDragFunction = document.body.ondrag;
CPTextFieldCachedSelectStartFunction = [[self window] platformWindow]._DOMBodyElement.onselectstart;
CPTextFieldCachedDragFunction = [[self window] platformWindow]._DOMBodyElement.ondrag;
document.body.ondrag = function () {};
document.body.onselectstart = function () {};
[[self window] platformWindow]._DOMBodyElement.ondrag = function () {};
[[self window] platformWindow]._DOMBodyElement.onselectstart = function () {};
}
[self textDidFocus:[CPNotification notificationWithName:CPTextFieldDidFocusNotification object:self userInfo:nil]];
@@ -640,8 +540,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
CPTextFieldCachedSelectStartFunction = nil;
CPTextFieldCachedDragFunction = nil;
document.body.ondrag = CPTextFieldCachedDragFunction
document.body.onselectstart = CPTextFieldCachedSelectStartFunction
[[self window] platformWindow]._DOMBodyElement.ondrag = CPTextFieldCachedDragFunction;
[[self window] platformWindow]._DOMBodyElement.onselectstart = CPTextFieldCachedSelectStartFunction;
}
#endif
@@ -661,6 +561,88 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
return YES;
}
/*!
Text fields require panels to become key window, so this returns \c YES.
*/
- (BOOL)needsPanelToBecomeKey
{
return YES;
}
- (void)mouseDown:(CPEvent)anEvent
{
// Don't track! (ever?)
if ([self isEditable] && [self isEnabled])
return [[self window] makeFirstResponder:self];
else
return [[self nextResponder] mouseDown:anEvent];
}
- (void)mouseUp:(CPEvent)anEvent
{
if (![self isEditable] || ![self isEnabled])
[[self nextResponder] mouseUp:anEvent];
}
- (void)mouseDragged:(CPEvent)anEvent
{
if (![self isEditable] || ![self isEnabled])
[[self nextResponder] mouseDragged:anEvent];
}
- (void)keyUp:(CPEvent)anEvent
{
var oldValue = [self stringValue];
[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]];
}
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
}
- (void)keyDown:(CPEvent)anEvent
{
if ([anEvent keyCode] === CPReturnKeyCode)
{
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];
}
else if ([anEvent keyCode] === CPTabKeyCode)
{
if ([anEvent modifierFlags] & CPShiftKeyMask)
[[self window] selectPreviousKeyView:self];
else
[[self window] selectNextKeyView:self];
if ([[[self window] firstResponder] respondsToSelector:@selector(selectText:)])
[[[self window] firstResponder] selectText:self];
[[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
}
else
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
}
- (void)textDidBlur:(CPNotification)note
{
//this looks to prevent false propagation of notifications for other objects
@@ -679,15 +661,6 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
[[CPNotificationCenter defaultCenter] postNotification:note];
}
- (void)mouseDown:(CPEvent)anEvent
{
// Don't track! (ever?)
if ([self isEditable] && [self isEnabled])
return [[self window] makeFirstResponder:self];
else
return [[self nextResponder] mouseDown:anEvent];
}
/*!
Returns the string the text field.
*/
@@ -803,11 +776,151 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
#if PLATFORM(DOM)
var element = [self _inputElement];
if (element.parentNode === _DOMElement && ([self isEditable] || [self isSelectable]))
window.setTimeout(function() { element.select(); }, 0);
if (([self isEditable] || [self isSelectable]))
{
if ([[self window] firstResponder] === self)
window.setTimeout(function() { element.select(); }, 0);
else
{
[[self window] makeFirstResponder:self];
window.setTimeout(function() {[self selectText:sender];}, 0);
}
}
#endif
}
- (void)copy:(id)sender
{
if (![CPPlatform isBrowser])
{
var selectedRange = [self selectedRange];
if (selectedRange.length < 1)
return;
var pasteboard = [CPPasteboard generalPasteboard],
stringValue = [self stringValue],
stringForPasting = [stringValue substringWithRange:selectedRange];
[pasteboard declareTypes:[CPStringPboardType] owner:nil];
[pasteboard setString:stringForPasting forType:CPStringPboardType];
}
}
- (void)cut:(id)sender
{
if (![CPPlatform isBrowser])
{
[self copy:sender];
[self deleteBackwards:sender];
}
}
- (void)paste:(id)sender
{
if (![CPPlatform isBrowser])
{
var pasteboard = [CPPasteboard generalPasteboard];
if (![[pasteboard types] containsObject:CPStringPboardType])
return;
[self deleteBackwards:sender];
var selectedRange = [self selectedRange],
stringValue = [self stringValue],
pasteString = [pasteboard stringForType:CPStringPboardType],
newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:pasteString];
[self setStringValue:newValue];
[self setSelectedRange:CPMakeRange(selectedRange.location+pasteString.length, 0)];
}
}
- (CPRange)selectedRange
{
if ([[self window] firstResponder] !== self)
return CPMakeRange(0, 0);
// we wrap this in try catch because firefox will throw an exception in certain instances
try
{
var inputElement = [self _inputElement],
selectionStart = inputElement.selectionStart,
selectionEnd = inputElement.selectionEnd;
if ([selectionStart isKindOfClass:CPNumber])
return CPMakeRange(selectionStart, selectionEnd - selectionStart);
// browsers which don't support selectionStart/selectionEnd (aka IE).
var theDocument = inputElement.ownerDocument || inputElement.document,
selectionRange = theDocument.selection.createRange(),
range = inputElement.createTextRange();
if (range.inRange(selectionRange))
{
range.setEndPoint('EndToStart', selectionRange);
return CPMakeRange(range.text.length, selectionRange.text.length);
}
}
catch (e)
{
// fall through to the return
}
return CGMakeRange(0, 0);
}
- (void)setSelectedRange:(CPRange)aRange
{
if (![[self window] firstResponder] === self)
return;
var inputElement = [self _inputElement];
try
{
if ([inputElement.selectionStart isKindOfClass:CPNumber])
{
inputElement.selectionStart = aRange.location;
inputElement.selectionEnd = CPMaxRange(aRange);
}
else
{
// browsers which don't support selectionStart/selectionEnd (aka IE).
var theDocument = inputElement.ownerDocument || inputElement.document,
existingRange = theDocument.selection.createRange(),
range = inputElement.createTextRange();
if (range.inRange(existingRange))
{
range.collapse(true);
range.move('character', aRange.location);
range.moveEnd('character', aRange.length);
range.select();
}
}
}
catch (e)
{
}
}
- (void)selectAll:(id)sender
{
[self selectText:sender];
}
- (void)deleteBackwards:(id)sender
{
var selectedRange = [self selectedRange],
stringValue = [self stringValue],
newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:""];
[self setStringValue:newValue];
[self setSelectedRange:CPMakeRange(selectedRange.location, 0)];
}
#pragma mark Setting the Delegate
- (void)setDelegate:(id)aDelegate
@@ -924,6 +1037,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
var view = [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
//[view setImagePosition:CPNoImage];
[view setHitTests:NO];
return view;
}
+11 -17
View File
@@ -43,7 +43,7 @@
if (self)
{
_bundle = [[CPBundle alloc] initWithPath:aURL + "/Info.plist"];
_bundle = [[CPBundle alloc] initWithPath:aURL];
}
return self;
@@ -58,27 +58,21 @@
- (void)bundleDidFinishLoading:(CPBundle)aBundle
{
var paths = [_bundle objectForInfoDictionaryKey:@"CPBundleReplacedFiles"],
index = 0,
count = paths.length,
bundlePath = [_bundle bundlePath];
var themes = [_bundle objectForInfoDictionaryKey:@"CPKeyedThemes"],
count = themes.length;
while (count--)
{
var path = paths[count];
if ([path pathExtension] === "keyedtheme")
{
var unarchiver = [[_CPThemeKeyedUnarchiver alloc]
initForReadingWithData:[CPData dataWithString:objj_files[bundlePath + '/' + path].contents]
bundle:_bundle];
var path = [aBundle pathForResource:themes[count]],
unarchiver = [[_CPThemeKeyedUnarchiver alloc]
initForReadingWithData:[[CPURL URLWithString:path] staticResourceData]
bundle:_bundle];
[unarchiver decodeObjectForKey:@"root"];
[unarchiver decodeObjectForKey:@"root"];
[unarchiver finishDecoding];
}
[unarchiver finishDecoding];
}
[_loadDelegate blendDidFinishLoading:self];
}
+579 -312
View File
File diff suppressed because it is too large. Load diff
+166 -82
View File
@@ -26,35 +26,18 @@
@import <AppKit/CPImage.j>
@import <AppKit/CPView.j>
/*
@global
@class CPToolbarItem
*/
CPToolbarItemVisibilityPriorityStandard = 0;
/*
@global
@class CPToolbarItem
*/
CPToolbarItemVisibilityPriorityLow = -1000;
/*
@global
@class CPToolbarItem
*/
CPToolbarItemVisibilityPriorityHigh = 1000;
/*
@global
@class CPToolbarItem
*/
CPToolbarItemVisibilityPriorityUser = 2000;
CPToolbarSeparatorItemIdentifier = @"CPToolbarSeparatorItemIdentifier";
CPToolbarSpaceItemIdentifier = @"CPToolbarSpaceItemIdentifier";
CPToolbarFlexibleSpaceItemIdentifier = @"CPToolbarFlexibleSpaceItemIdentifier";
CPToolbarShowColorsItemIdentifier = @"CPToolbarShowColorsItemIdentifier";
CPToolbarShowFontsItemIdentifier = @"CPToolbarShowFontsItemIdentifier";
CPToolbarCustomizeToolbarItemIdentifier = @"CPToolbarCustomizeToolbarItemIdentifier";
CPToolbarPrintItemIdentifier = @"CPToolbarPrintItemIdentifier";
CPToolbarSeparatorItemIdentifier = @"CPToolbarSeparatorItem";
CPToolbarSpaceItemIdentifier = @"CPToolbarSpaceItem";
CPToolbarFlexibleSpaceItemIdentifier = @"CPToolbarFlexibleSpaceItem";
CPToolbarShowColorsItemIdentifier = @"CPToolbarShowColorsItem";
CPToolbarShowFontsItemIdentifier = @"CPToolbarShowFontsItem";
CPToolbarCustomizeToolbarItemIdentifier = @"CPToolbarCustomizeToolbarItem";
CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
/*!
@ingroup appkit
@@ -84,6 +67,8 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItemIdentifier";
CGSize _maxSize;
int _visibilityPriority;
BOOL _autovalidates;
}
- (id)init
@@ -112,6 +97,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItemIdentifier";
_maxSize = CGSizeMakeZero();
_visibilityPriority = CPToolbarItemVisibilityPriorityStandard;
_autovalidates = YES;
}
return self;
@@ -134,6 +120,12 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItemIdentifier";
return _toolbar;
}
/* @ignore */
- (void)_setToolbar:(CPToolbar)aToolbar
{
_toolbar = aToolbar;
}
/*!
Returns the item's label
*/
@@ -188,7 +180,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItemIdentifier";
- (void)setToolTip:(CPString)aToolTip
{
if ([_view respondsToSelector:@selector(setToolTip:)])
[view setToolTip:aToolTip];
[_view setToolTip:aToolTip];
_toolTip = aToolTip;
}
@@ -313,8 +305,8 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItemIdentifier";
if (!_image)
return;
if (_minSize.width == 0 && _minSize.height == 0 &&
_maxSize.width == 0 && _maxSize.height == 0)
if (_minSize.width === 0 && _minSize.height === 0 &&
_maxSize.width === 0 && _maxSize.height === 0)
{
var imageSize = [_image size];
@@ -393,6 +385,9 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItemIdentifier";
*/
- (void)setMinSize:(CGSize)aMinSize
{
if(!aMinSize.height || !aMinSize.width)
return;
_minSize = CGSizeMakeCopy(aMinSize);
// Try to provide some sanity: Make maxSize >= minSize
@@ -413,6 +408,9 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItemIdentifier";
*/
- (void)setMaxSize:(CGSize)aMaxSize
{
if(!aMaxSize.height || !aMaxSize.width)
return;
_maxSize = CGSizeMakeCopy(aMaxSize);
// Try to provide some sanity: Make minSize <= maxSize
@@ -449,6 +447,128 @@ CPToolbarItemVisibilityPriorityUser
_visibilityPriority = aVisibilityPriority;
}
- (void)validate
{
// View items do not do any target-action analysis.
if (_view)
{
if ([target respondsToSelector:@selector(validateToolbarItem:)])
[self setEnabled:[target validateToolbarItem:self]];
return;
}
var action = [self action];
if (!action)
return [self setEnabled:NO];
var target = [self target];
if (target && ![target respondsToSelector:action])
return [self setEnabled:NO];
target = [CPApp targetForAction:action to:target from:self];
if (!target)
return [self setEnabled:NO];
if ([target respondsToSelector:@selector(validateToolbarItem:)])
[self setEnabled:[target validateToolbarItem:self]];
else
[self setEnabled:YES];
}
- (BOOL)autovalidates
{
return _autovalidates;
}
- (void)setAutovalidates:(BOOL)shouldAutovalidate
{
_autovalidates = !!shouldAutovalidate;
}
@end
var CPToolbarItemItemIdentifierKey = @"CPToolbarItemItemIdentifierKey",
CPToolbarItemLabelKey = @"CPToolbarItemLabelKey",
CPToolbarItemPaletteLabelKey = @"CPToolbarItemPaletteLabelKey",
CPToolbarItemToolTipKey = @"CPToolbarItemToolTipKey",
CPToolbarItemTagKey = @"CPToolbarItemTagKey",
CPToolbarItemTargetKey = @"CPToolbarItemTargetKey",
CPToolbarItemActionKey = @"CPToolbarItemActionKey",
CPToolbarItemEnabledKey = @"CPToolbarItemEnabledKey",
CPToolbarItemImageKey = @"CPToolbarItemImageKey",
CPToolbarItemAlternateImageKey = @"CPToolbarItemAlternateImageKey",
CPToolbarItemViewKey = @"CPToolbarItemViewKey",
CPToolbarItemMinSizeKey = @"CPToolbarItemMinSizeKey",
CPToolbarItemMaxSizeKey = @"CPToolbarItemMaxSizeKey",
CPToolbarItemVisibilityPriorityKey = @"CPToolbarItemVisibilityPriorityKey",
CPToolbarItemAutovalidatesKey = @"CPToolbarItemAutovalidatesKey";
@implementation CPToolbarItem (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
if (self)
{
_itemIdentifier = [aCoder decodeObjectForKey:CPToolbarItemItemIdentifierKey];
_minSize = [aCoder decodeSizeForKey:CPToolbarItemMinSizeKey];
_maxSize = [aCoder decodeSizeForKey:CPToolbarItemMaxSizeKey];
[self setLabel:[aCoder decodeObjectForKey:CPToolbarItemLabelKey]];
[self setPaletteLabel:[aCoder decodeObjectForKey:CPToolbarItemPaletteLabelKey]];
[self setToolTip:[aCoder decodeObjectForKey:CPToolbarItemToolTipKey]];
[self setTag:[aCoder decodeObjectForKey:CPToolbarItemTagKey]];
[self setTarget:[aCoder decodeObjectForKey:CPToolbarItemTargetKey]];
[self setAction:CPSelectorFromString([aCoder decodeObjectForKey:CPToolbarItemActionKey])];
[self setEnabled:[aCoder decodeBoolForKey:CPToolbarItemEnabledKey]];
[self setImage:[aCoder decodeObjectForKey:CPToolbarItemImageKey]];
[self setAlternateImage:[aCoder decodeObjectForKey:CPToolbarItemAlternateImageKey]];
[self setView:[aCoder decodeObjectForKey:CPToolbarItemViewKey]];
[self setVisibilityPriority:[aCoder decodeIntForKey:CPToolbarItemVisibilityPriorityKey]];
[self setAutovalidates:[aCoder decodeBoolForKey:CPToolbarItemAutovalidatesKey]];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[aCoder encodeObject:_itemIdentifier forKey:CPToolbarItemItemIdentifierKey];
[aCoder encodeObject:[self label] forKey:CPToolbarItemLabelKey];
[aCoder encodeObject:[self paletteLabel] forKey:CPToolbarItemPaletteLabelKey];
[aCoder encodeObject:[self toolTip] forKey:CPToolbarItemToolTipKey];
[aCoder encodeObject:[self tag] forKey:CPToolbarItemTagKey];
[aCoder encodeObject:[self target] forKey:CPToolbarItemTargetKey];
[aCoder encodeObject:[self action] forKey:CPToolbarItemActionKey];
[aCoder encodeObject:[self isEnabled] forKey:CPToolbarItemEnabledKey];
[aCoder encodeObject:[self image] forKey:CPToolbarItemImageKey];
[aCoder encodeObject:[self alternateImage] forKey:CPToolbarItemAlternateImageKey];
[aCoder encodeObject:[self view] forKey:CPToolbarItemViewKey];
[aCoder encodeSize:[self minSize] forKey:CPToolbarItemMinSizeKey];
[aCoder encodeSize:[self maxSize] forKey:CPToolbarItemMaxSizeKey];
[aCoder encodeObject:[self visibilityPriority] forKey:CPToolbarItemVisibilityPriorityKey];
[aCoder encodeBool:[self autovalidates] forKey:CPToolbarItemAutovalidatesKey];
}
@end
@implementation CPToolbarItem (CPCopying)
@@ -456,10 +576,12 @@ CPToolbarItemVisibilityPriorityUser
- (id)copy
{
var copy = [[[self class] alloc] initWithItemIdentifier:_itemIdentifier];
if (_view)
[copy setView:[CPKeyedUnarchiver unarchiveObjectWithData:[CPKeyedArchiver archivedDataWithRootObject:_view]]];
[copy _setToolbar:_toolbar];
[copy setLabel:_label];
[copy setPaletteLabel:_paletteLabel];
[copy setToolTip:[self toolTip]];
@@ -467,7 +589,7 @@ CPToolbarItemVisibilityPriorityUser
[copy setTag:[self tag]];
[copy setTarget:[self target]];
[copy setAction:[self action]];
[copy setEnabled:[self isEnabled]];
[copy setImage:[self image]];
@@ -475,9 +597,10 @@ CPToolbarItemVisibilityPriorityUser
[copy setMinSize:_minSize];
[copy setMaxSize:_maxSize];
[copy setVisibilityPriority:_visibilityPriority];
[copy setVisibilityPriority:[self visibilityPriority]];
[copy setAutovalidates:[self autovalidates]];
return copy;
}
@@ -485,62 +608,17 @@ CPToolbarItemVisibilityPriorityUser
// Standard toolbar identifiers
var _CPToolbarSeparatorItemView = nil,
_CPToolbarSpaceItemView = nil;
@implementation CPToolbarItem (Standard)
+ (CPView)_separatorItemView
{
if (!_CPToolbarSeparatorItemView)
{
_CPToolbarSeparatorItemView = [[CPView alloc] initWithFrame:CGRectMake(0.0, 0.0, 2.0, 32.0)];
sizes = {};
sizes[@"CPToolbarItemSeparator"] = [CGSizeMake(2.0, 26.0), CGSizeMake(2.0, 1.0), CGSizeMake(2.0, 26.0)];
[_CPToolbarSeparatorItemView setBackgroundColor:_CPControlThreePartImagePattern(YES, sizes, @"CPToolbarItem", @"Separator")];
}
return _CPToolbarSeparatorItemView;
}
+ (CPView)_spaceItemView
{
if (!_CPToolbarSpaceItemView)
_CPToolbarSpaceItemView = [[CPView alloc] initWithFrame:CGRectMakeZero()];
return _CPToolbarSpaceItemView;
}
/* @ignore */
+ (CPToolbarItem)_standardItemWithItemIdentifier:(CPString)anItemIdentifier
{
var item = [[CPToolbarItem alloc] initWithItemIdentifier:anItemIdentifier];
switch (anItemIdentifier)
{
case CPToolbarSeparatorItemIdentifier: [item setView:[self _separatorItemView]];
[item setMinSize:CGSizeMake(2.0, 0.0)];
[item setMaxSize:CGSizeMake(2.0, 100000.0)];
return item;
case CPToolbarSpaceItemIdentifier: [item setView:[self _spaceItemView]];
[item setMinSize:CGSizeMake(32.0, 32.0)];
[item setMaxSize:CGSizeMake(32.0, 32.0)];
return item;
case CPToolbarFlexibleSpaceItemIdentifier: [item setView:[self _spaceItemView]];
[item setMinSize:CGSizeMake(32.0, 32.0)];
[item setMaxSize:CGSizeMake(10000.0, 32.0)];
return item;
case CPToolbarShowColorsItemIdentifier: return nil;
case CPToolbarSeparatorItemIdentifier: return [_CPToolbarSeparatorItem new];
case CPToolbarSpaceItemIdentifier: return [_CPToolbarSpaceItem new];
case CPToolbarFlexibleSpaceItemIdentifier: return [_CPToolbarFlexibleSpaceItem new];
case CPToolbarShowColorsItemIdentifier: return [_CPToolbarShowColorsItem new];
case CPToolbarShowFontsItemIdentifier: return nil;
case CPToolbarCustomizeToolbarItemIdentifier: return nil;
case CPToolbarPrintItemIdentifier: return nil;
@@ -550,3 +628,9 @@ var _CPToolbarSeparatorItemView = nil,
}
@end
@import "_CPToolbarFlexibleSpaceItem.j"
@import "_CPToolbarShowColorsItem.j"
@import "_CPToolbarSeparatorItem.j"
@import "_CPToolbarSpaceItem.j"
+243 -9
View File
@@ -7,7 +7,7 @@
id _representedObject @accessors(readonly, property=representedObject);
CPTreeNode _parentNode @accessors(readonly, property=parentNode);
CPMutableArray _childNodes @accessors(readonly, property=childNodes);
CPMutableArray _childNodes;
}
+ (id)treeNodeWithRepresentedObject:(id)anObject
@@ -33,32 +33,40 @@
return [_childNodes count] <= 0;
}
- (CPArray)childNodes
{
return [_childNodes copy];
}
- (CPMutableArray)mutableChildNodes
{
return [self mutableArrayValueForKey:@"childNodes"];
}
- (void)insertObject:(id)anObject inChildNodesAtIndex:(CPInteger)anIndex
- (void)insertObject:(id)aTreeNode inChildNodesAtIndex:(CPInteger)anIndex
{
anObject._parentNode = self;
[[aTreeNode._parentNode mutableChildNodes] removeObjectIdenticalTo:aTreeNode];
[_childNodes addObject:anObject];
aTreeNode._parentNode = self;
[_childNodes insertObject:aTreeNode atIndex:anIndex];
}
- (void)removeObjectFromChildNodesAtIndex:(CPInteger)anIndex
{
anObject._parentNode = nil;
[_childNodes objectAtIndex:anIndex]._parentNode = nil;
[_childNodes removeObjectAtIndex:anIndex];
}
- (void)replaceObjectFromChildNodesAtIndex:(CPInteger)anIndex withObject:(id)anObject
- (void)replaceObjectFromChildNodesAtIndex:(CPInteger)anIndex withObject:(id)aTreeNode
{
var oldObject = [_childNodes objectAtIndex:anIndex];
var oldTreeNode = [_childNodes objectAtIndex:anIndex];
oldObject._parentNode = nil;
oldTreeNode._parentNode = nil;
aTreeNode._parentNode = self;
[_childNodes replaceObjectAtIndex:anIndex withObject:anObject];
[_childNodes replaceObjectAtIndex:anIndex withObject:aTreeNode];
}
- (id)objectInChildNodesAtIndex:(CPInteger)anIndex
@@ -79,4 +87,230 @@
[_childNodes[count] sortWithSortDescriptors:sortDescriptors recursively:YES];
}
- (CPEnumerator)preOrder
{
return [_CPTreeNodeEnumerator enumeratorWithTreeNode:self order:_CPTreeNodeEnumeratorPreOrder];
}
- (CPEnumerator)inOrder
{
return [_CPTreeNodeEnumerator enumeratorWithTreeNode:self order:_CPTreeNodeEnumeratorInOrder];
}
- (CPEnumerator)postOrder
{
return [_CPTreeNodeEnumerator enumeratorWithTreeNode:self order:_CPTreeNodeEnumeratorPostOrder];
}
- (CPEnumerator)levelOrder
{
return [_CPTreeNodeEnumerator enumeratorWithTreeNode:self order:_CPTreeNodeEnumeratorLevelOrder];
}
- (int)countByEnumeratingWithState:(id)aState objects:(id)objects count:(id)aCount
{
if (aState.state !== 0)
return 0;
// FIXME: Change this to inorder when implemented?
var count = [[self preOrder] countByEnumeratingWithState:aState objects:objects count:aCount];
// Dangerous?
aState.state = YES;
return count;
}
@end
var CPTreeNodeRepresentedObjectKey = @"CPTreeNodeRepresentedObjectKey",
CPTreeNodeParentNodeKey = @"CPTreeNodeParentNodeKey",
CPTreeNodeChildNodesKey = @"CPTreeNodeChildNodesKey";
@implementation CPTreeNode (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
if (self)
{
_representedObject = [aCoder decodeObjectForKey:CPTreeNodeRepresentedObjectKey];
_parentNode = [aCoder decodeObjectForKey:CPTreeNodeParentNodeKey];
_childNodes = [aCoder decodeObjectForKey:CPTreeNodeChildNodesKey];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[aCoder encodeObject:_representedObject forKey:CPTreeNodeRepresentedObjectKey];
[aCoder encodeConditionalObject:_parentNode forKey:CPTreeNodeParentNodeKey];
[aCoder encodeObject:_childNodes forKey:CPTreeNodeChildNodesKey];
}
@end
var _CPTreeNodeEnumeratorPreOrder = 0,
_CPTreeNodeEnumeratorInOrder = 1,
_CPTreeNodeEnumeratorPostOrder = 2,
_CPTreeNodeEnumeratorLevelOrder = 3;
@implementation _CPTreeNodeEnumerator : CPEnumerator
{
int _order;
Object _state;
CPTreeNode _treeNode;
}
+ (_CPTreeNodeEnumerator)enumeratorWithTreeNode:(CPTreeNode)aTreeNode order:(int)anOrder
{
return [[self alloc] initWithTreeNode:aTreeNode order:anOrder];
}
- (id)initWithTreeNode:(CPTreeNode)aTreeNode order:(int)anOrder
{
self = [super init];
if (self)
{
_order = anOrder
_state = [self _newState];
_treeNode = aTreeNode;
}
return self;
}
- (id)_newState
{
return { stack:[_treeNode], visited:[CPSet set] };
}
- (id)_preOrderFromState:(Object)state allObjects:(BOOL)shouldReturnAllObjects
{
var stack = state.stack;
if (stack.length <= 0)
return nil;
if (shouldReturnAllObjects)
var allObjects = [];
while (stack.length)
{
var currentNode = stack.pop(),
childNodes = currentNode._childNodes,
count = childNodes.length;
while (count--)
stack.push(childNodes[count]);
if (shouldReturnAllObjects)
allObjects.push(currentNode);
else
return currentNode;
}
return allObjects;
}
- (id)_inOrderFromState:(Object)state allObjects:(BOOL)shouldReturnAllObjects
{
// Implement.
}
- (id)_postOrderFromState:(Object)state allObjects:(BOOL)shouldReturnAllObjects
{
var stack = state.stack;
if (stack.length <= 0)
return nil;
var visited = state.visited;
if (shouldReturnAllObjects)
var allObjects = [];
while (stack.length)
{
var currentNode = [stack lastObject],
childNodes = currentNode._childNodes,
originalCount = stack.length,
count = childNodes.length;
while (count--)
{
var treeNode = childNodes[count];
if ([visited containsObject:treeNode])
continue;
else
stack.push(treeNode);
}
if (originalCount === stack.length)
{
[visited addObject:currentNode];
if (shouldReturnAllObjects)
allObjects.push(stack.pop());
else
return stack.pop();
}
}
return allObjects;
}
- (id)_levelOrderFromState:(Object)state allObjects:(BOOL)shouldReturnAllObjects
{
// Implement.
}
- (id)nextObject
{
if (_order === _CPTreeNodeEnumeratorPreOrder)
return [self _preOrderFromState:[self _newState] allObjects:NO];
else if (_order === _CPTreeNodeEnumeratorInOrder)
return [self _inOrderFromState:[self _newState] allObjects:NO];
else if (_order === _CPTreeNodeEnumeratorPostOrder)
return [self _postOrderFromState:[self _newState] allObjects:NO];
//else if (_order === _CPTreeNodeEnumeratorLevelOrder)
return [self _levelOrderFromState:[self _newState] allObjects:NO];
}
- (CPArray)allObjects
{
if (_order === _CPTreeNodeEnumeratorPreOrder)
return [self _preOrderFromState:[self _newState] allObjects:YES];
else if (_order === _CPTreeNodeEnumeratorInOrder)
return [self _inOrderFromState:[self _newState] allObjects:YES];
else if (_order === _CPTreeNodeEnumeratorPostOrder)
return [self _postOrderFromState:[self _newState] allObjects:YES];
//else if (_order === _CPTreeNodeEnumeratorLevelOrder)
return [self _levelOrderFromState:[self _newState] allObjects:NO];
}
- (int)countByEnumeratingWithState:(id)aState objects:(id)objects count:(id)aCount
{
if (aState.state !== 0)
return 0;
var count = [[self allObjects] countByEnumeratingWithState:aState objects:objects count:aCount];
// Dangerous?
aState.state = YES;
return count;
}
@end
+100 -9
View File
@@ -238,6 +238,11 @@ var CPViewFlags = { },
return [CPSet setWithObjects:@"frameOrigin", @"frameSize"];
}
+ (CPSet)keyPathsForValuesAffectingBounds
{
return [CPSet setWithObjects:@"boundsOrigin", @"boundsSize"];
}
- (id)init
{
return [self initWithFrame:CGRectMakeZero()];
@@ -308,7 +313,7 @@ var CPViewFlags = { },
*/
- (CPArray)subviews
{
return _subviews;
return [_subviews copy];
}
/*!
@@ -441,7 +446,7 @@ var CPViewFlags = { },
[_superview willRemoveSubview:self];
[[_superview subviews] removeObject:self];
[_superview._subviews removeObject:self];
#if PLATFORM(DOM)
CPDOMDisplayServerRemoveChild(_superview._DOMElement, _DOMElement);
@@ -468,6 +473,73 @@ var CPViewFlags = { },
[self _insertSubview:aView atIndex:index];
}
- (void)setSubviews:(CPArray)newSubviews
{
if (!newSubviews)
[CPException raise:CPInvalidArgumentException reason:"newSubviews cannot be nil in -[CPView setSubviews:]"];
// Trivial Case 0: Same array somehow
if ([_subviews isEqual:newSubviews])
return;
// Trivial Case 1: No current subviews, simply add all new subviews.
if ([_subviews count] === 0)
{
var index = 0,
count = [newSubviews count];
for (; index < count; ++index)
[self addSubview:newSubviews[index]];
return;
}
// Trivial Case 2: No new subviews, simply remove all current subviews.
if ([newSubviews count] === 0)
{
var count = [_subviews count];
while (count--)
[_subviews[count] removeFromSuperview];
return;
}
// Find out the views that were removed.
var removedSubviews = [CPMutableSet setWithArray:_subviews];
[removedSubviews removeObjectsInArray:newSubviews];
[removedSubviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
// Find out which views need to be added.
var addedSubviews = [CPMutableSet setWithArray:newSubviews];
[addedSubviews removeObjectsInArray:_subviews];
var addedSubview = nil,
addedSubviewEnumerator = [addedSubviews objectEnumerator];
while (addedSubview = [addedSubviewEnumerator nextObject])
[self addSubview:addedSubview];
// If the order is fine, no need to reorder.
if ([_subviews isEqual:newSubviews])
return;
_subviews = [newSubviews copy];
var index = 0,
count = [_subviews count];
for (; index < count; ++index)
{
var subview = _subviews[index];
CPDOMDisplayServerRemoveChild(_DOMElement, subview._DOMElement);
CPDOMDisplayServerAppendChild(_DOMElement, subview._DOMElement);
}
}
/* @ignore */
- (void)_setWindow:(CPWindow)aWindow
{
@@ -596,7 +668,7 @@ var CPViewFlags = { },
- (void)viewWithTag:(CPInteger)aTag
{
if ([self tag] === aTag)
if ([self tag] == aTag)
return self;
var index = 0,
@@ -816,6 +888,16 @@ var CPViewFlags = { },
return _CGRectMakeCopy(_bounds);
}
- (CGPoint)boundsOrigin
{
return _CGPointMakeCopy(_bounds.origin);
}
- (CGSize)boundsSize
{
return _CGSizeMakeCopy(_bounds.size);
}
/*!
Sets the location of the receiver inside its frame. The method
posts a CPViewBoundsDidChangeNotification to the
@@ -1202,6 +1284,14 @@ var CPViewFlags = { },
return self;
}
/*!
Returns \c YES if this view requires a panel to become key. Normally only text fields, so this returns \c NO.
*/
- (BOOL)needsPanelToBecomeKey
{
return NO;
}
/*!
Returns \c YES if mouse events aren't needed by the receiver and can be sent to the superview. The
default implementation returns \c NO if the view is opaque.
@@ -1863,12 +1953,11 @@ setBoundsOrigin:
- (BOOL)performKeyEquivalent:(CPEvent)anEvent
{
var subviews = [self subviews],
count = [subviews count];
var count = [_subviews count];
// Is reverse iteration correct here? It matches the other (correct) code like hit testing.
while (count--)
if ([subviews[count] performKeyEquivalent:anEvent])
if ([_subviews[count] performKeyEquivalent:anEvent])
return YES;
return NO;
@@ -2046,7 +2135,8 @@ setBoundsOrigin:
var theClass = [self class],
CPViewClass = [CPView class],
attributes = [];
attributes = [],
nullValue = [CPNull null];
for (; theClass && theClass !== CPViewClass; theClass = [theClass superclass])
{
@@ -2070,9 +2160,10 @@ setBoundsOrigin:
while (attributeCount--)
{
var attributeName = attributeKeys[attributeCount];
var attributeName = attributeKeys[attributeCount],
attributeValue = [attributeDictionary objectForKey:attributeName];
attributes.push([attributeDictionary objectForKey:attributeName]);
attributes.push(attributeValue === nullValue ? nil : attributeValue);
attributes.push(attributeName);
}
}
+179
View File
@@ -0,0 +1,179 @@
/*
* CPFlashView.j
* AppKit
*
* Created by Klaas Pieter Annema on September 3, 2009.
* Copyright 2009, Sofa BV
*
* 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/CPAnimation.j>
CPViewAnimationTargetKey = @"CPViewAnimationTarget";
CPViewAnimationStartFrameKey = @"CPViewAnimationStartFrame";
CPViewAnimationEndFrameKey = @"CPViewAnimationEndFrame";
CPViewAnimationEffectKey = @"CPViewAnimationEffect";
CPViewAnimationFadeInEffect = @"CPViewAnimationFadeIn";
CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut";
@implementation CPViewAnimation : CPAnimation
{
CPArray _viewAnimations;
}
- (id)initWithViewAnimations:(CPArray)viewAnimations
{
if (self = [super initWithDuration:0.5 animationCurve:CPAnimationLinear])
{
[self setViewAnimations:viewAnimations];
}
return self;
}
- (void)startAnimation
{
var animationIndex = [_viewAnimations count];
while (animationIndex--)
{
var dictionary = [_viewAnimations objectAtIndex:animationIndex],
view = [self _targetView:dictionary],
startFrame = [self _startFrame:dictionary];
[view setFrame:startFrame];
var effect = [self _effect:dictionary];
if (effect === CPViewAnimationFadeInEffect)
{
[view setAlphaValue:0.0];
[view setHidden:NO];
}
else if (effect === CPViewAnimationFadeOutEffect)
[view setAlphaValue:1.0];
}
[super startAnimation];
}
- (void)setCurrentProgress:(NSAnimationProgress)progress
{
[super setCurrentProgress:progress];
var animationIndex = [_viewAnimations count];
while (animationIndex--)
{
var dictionary = [_viewAnimations objectAtIndex:animationIndex],
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 = 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;
intermediateFrame.size.height = startFrame.size.height + differenceFrame.size.height * progress;
[view setFrame:intermediateFrame];
// Update the view's alpha value
var effect = [self _effect:dictionary];
if (effect === CPViewAnimationFadeInEffect)
[view setAlphaValue:1.0 * progress];
else if (effect === CPViewAnimationFadeOutEffect)
[view setAlphaValue:1.0 + ( 0.0 - 1.0 ) * progress];
if (progress === 1.0)
[view setHidden:CPRectIsNull(endFrame) || [view alphaValue] === 0.0];
}
}
- (void)stopAnimation
{
var animationIndex = [_viewAnimations count];
while (animationIndex--)
{
var dictionary = [_viewAnimations objectAtIndex:animationIndex],
view = [self _targetView:dictionary],
endFrame = [self _endFrame:dictionary];
[view setFrame:endFrame];
var effect = [self _effect:dictionary];
if (effect === CPViewAnimationFadeInEffect)
[view setAlphaValue:1.0];
else if (effect === CPViewAnimationFadeOutEffect)
[view setAlphaValue:0.0];
[view setHidden:CPRectIsNull(endFrame) || [view alphaValue] === 0.0];
}
[super stopAnimation];
}
- (id)_targetView:(CPDictionary)dictionary
{
var targetView = [dictionary valueForKey:CPViewAnimationTargetKey];
if (!targetView)
[CPException raise:CPInternalInconsistencyException reason:[CPString stringWithFormat:@"view animation: %@ does not have a target view", [dictionary description]]];
return targetView;
}
- (CPRect)_startFrame:(CPDictionary)dictionary
{
var startFrame = [dictionary valueForKey:CPViewAnimationStartFrameKey];
if (!startFrame)
return [[self _targetView:dictionary] frame];
return startFrame;
}
- (CPRect)_endFrame:(CPDictionary)dictionary
{
var endFrame = [dictionary valueForKey:CPViewAnimationEndFrameKey];
if (!endFrame)
return [[self _targetView:dictionary] frame];
return endFrame;
}
- (CPString)_effect:(CPDictionary)dictionary
{
return [dictionary valueForKey:CPViewAnimationEffectKey];
}
- (CPArray)viewAnimations
{
return _viewAnimations;
}
- (void)setViewAnimations:(CPArray)viewAnimations
{
if (viewAnimations != _viewAnimations)
{
[self stopAnimation];
_viewAnimations = [viewAnimations copy];
}
}
@end
+16 -4
View File
@@ -22,6 +22,7 @@
@import <AppKit/CPResponder.j>
var CPViewControllerCachedCibs;
/*! @class CPViewController
The CPViewController class provides the fundamental view-management controller for Cappuccino applications.
@@ -56,6 +57,12 @@
CPDictionary _cibExternalNameTable @accessors(property=cibExternalNameTable, readonly);
}
+ (void)initialize
{
if (self === CPViewController)
CPViewControllerCachedCibs = [CPDictionary dictionary];
}
/*!
Convenience initializer calls -initWithCibName:bundle: with nil for both parameters.
*/
@@ -113,11 +120,16 @@
{
if (_view)
return;
// check if a cib is already cached for the current _cibName
var cib = [CPViewControllerCachedCibs objectForKey:_cibName];
// if (_cibName)
// [CPException raise: reason:];
var cib = [[CPCib alloc] initWithContentsOfURL:[_cibBundle pathForResource:_cibName + @".cib"]];
if (!cib)
{
// if the cib isn't cached yet : fetch it and cache it
cib = [[CPCib alloc] initWithContentsOfURL:[_cibBundle pathForResource:_cibName + @".cib"]];
[CPViewControllerCachedCibs setObject:cib forKey:_cibName];
}
[cib instantiateCibWithExternalNameTable:_cibExternalNameTable];
}
+3 -2
View File
@@ -150,8 +150,10 @@ CPWebViewScrollNative = 2;
_frameView = [[CPView alloc] initWithFrame:[self bounds]];
[_frameView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
_scrollView = [[CPScrollView alloc] initWithFrame:[self bounds]];
[_scrollView setAutohidesScrollers:YES];
[_scrollView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
[_scrollView setDocumentView:_frameView];
@@ -166,7 +168,6 @@ CPWebViewScrollNative = 2;
- (void)setFrameSize:(CPSize)aSize
{
[super setFrameSize:aSize];
[self _resizeWebFrame];
}
@@ -180,7 +181,7 @@ CPWebViewScrollNative = 2;
}
else
{
[_frameView setFrameSize:[_scrollView bounds].size];
[_frameView setFrameSize:[_scrollView contentSize]];
// try to get the document size so we can correctly set the frame
var win = null;
+142 -38
View File
@@ -175,6 +175,7 @@ CPWindowBelow = 2;
CPWindowWillCloseNotification = @"CPWindowWillCloseNotification";
CPWindowDidBecomeMainNotification = @"CPWindowDidBecomeMainNotification";
CPWindowDidResignMainNotification = @"CPWindowDidResignMainNotification";
CPWindowDidResizeNotification = @"CPWindowDidResizeNotification";
CPWindowDidMoveNotification = @"CPWindowDidMoveNotification";
CPWindowWillBeginSheetNotification = @"CPWindowWillBeginSheetNotification";
CPWindowDidEndSheetNotification = @"CPWindowDidEndSheetNotification";
@@ -257,6 +258,7 @@ var CPWindowSaveImage = nil,
BOOL _hasShadow;
BOOL _isMovableByWindowBackground;
unsigned _shadowStyle;
BOOL _showsResizeIndicator;
BOOL _isDocumentEdited;
BOOL _isDocumentSaving;
@@ -332,6 +334,11 @@ var CPWindowSaveImage = nil,
CPWindowSavingImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPProgressIndicator/CPProgressIndicatorSpinningStyleRegular.gif"] size:CGSizeMake(16.0, 16.0)]
}
- (id)init
{
return [self initWithContentRect:_CGRectMakeZero() styleMask:CPTitledWindowMask];
}
/*!
Initializes the window. The method also takes a style bit mask made up
of any of the following values:
@@ -421,6 +428,8 @@ CPTexturedBackgroundWindowMask
_defaultButtonEnabled = YES;
_keyViewLoopIsDirty = YES;
[self setShowsResizeIndicator:_styleMask & CPResizableWindowMask];
}
return self;
@@ -501,6 +510,7 @@ CPTexturedBackgroundWindowMask
[_windowView addSubview:_contentView];
[_windowView setTitle:_title];
[_windowView noteToolbarChanged];
[_windowView setShowsResizeIndicator:[self showsResizeIndicator]];
[self setFrame:[self frameRectForContentRect:contentRect]];
}
@@ -604,8 +614,41 @@ CPTexturedBackgroundWindowMask
@param shouldDisplay whether the window should redraw its views
@param shouldAnimate whether the window resize should be animated
*/
- (void)_setClippedFrame:(CGRect)aFrame display:(BOOL)shouldDisplay animate:(BOOL)shouldAnimate
{
aFrame.size.width = MIN(MAX(aFrame.size.width, _minSize.width), _maxSize.width)
aFrame.size.height = MIN(MAX(aFrame.size.height, _minSize.height), _maxSize.height);
[self setFrame:aFrame display:shouldDisplay animate:shouldAnimate];
}
- (void)setFrame:(CGRect)aFrame display:(BOOL)shouldDisplay animate:(BOOL)shouldAnimate
{
aFrame = _CGRectMakeCopy(aFrame);
var value = aFrame.origin.x,
delta = value - FLOOR(value);
if (delta)
aFrame.origin.x = value > 0.879 ? CEIL(value) : FLOOR(value);
value = aFrame.origin.y;
delta = value - FLOOR(value);
if (delta)
aFrame.origin.y = value > 0.879 ? CEIL(value) : FLOOR(value);
value = aFrame.size.width;
delta = value - FLOOR(value);
if (delta)
aFrame.size.width = value > 0.15 ? CEIL(value) : FLOOR(value);
value = aFrame.size.height;
delta = value - FLOOR(value);
if (delta)
aFrame.size.height = value > 0.15 ? CEIL(value) : FLOOR(value);
if (shouldAnimate)
{
var animation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:aFrame];
@@ -637,16 +680,16 @@ CPTexturedBackgroundWindowMask
if (!_CGSizeEqualToSize(size, newSize))
{
size.width = MIN(MAX(newSize.width, _minSize.width), _maxSize.width);
size.height = MIN(MAX(newSize.height, _minSize.height), _maxSize.height);
size.width = newSize.width;
size.height = newSize.height;
[_windowView setFrameSize:size];
if (_hasShadow)
[_shadowView setFrameSize:_CGSizeMake(SHADOW_MARGIN_LEFT + size.width + SHADOW_MARGIN_RIGHT, SHADOW_MARGIN_BOTTOM + size.height + SHADOW_MARGIN_TOP + SHADOW_DISTANCE)];
if (!_isAnimating && [_delegate respondsToSelector:@selector(windowDidResize:)])
[_delegate windowDidResize:self];
if (!_isAnimating)
[[CPNotificationCenter defaultCenter] postNotificationName:CPWindowDidResizeNotification object:self];
}
if ([self _sharesChromeWithPlatformWindow])
@@ -656,7 +699,7 @@ CPTexturedBackgroundWindowMask
- (void)setFrame:(CGRect)aFrame display:(BOOL)shouldDisplay
{
[super setFrame:aFrame display:shouldDisplay animate:NO];
[self _setClippedFrame:aFrame display:shouldDisplay animate:NO];
}
/*!
@@ -664,7 +707,7 @@ CPTexturedBackgroundWindowMask
*/
- (void)setFrame:(CGRect)aFrame
{
[self setFrame:aFrame display:YES animate:NO];
[self _setClippedFrame:aFrame display:YES animate:NO];
}
/*!
@@ -673,7 +716,7 @@ CPTexturedBackgroundWindowMask
*/
- (void)setFrameOrigin:(CGPoint)anOrigin
{
[self setFrame:_CGRectMake(anOrigin.x, anOrigin.y, _CGRectGetWidth(_frame), _CGRectGetHeight(_frame)) display:YES animate:NO];
[self _setClippedFrame:_CGRectMake(anOrigin.x, anOrigin.y, _CGRectGetWidth(_frame), _CGRectGetHeight(_frame)) display:YES animate:NO];
}
/*!
@@ -682,7 +725,7 @@ CPTexturedBackgroundWindowMask
*/
- (void)setFrameSize:(CGSize)aSize
{
[self setFrame:_CGRectMake(_CGRectGetMinX(_frame), _CGRectGetMinY(_frame), aSize.width, aSize.height) display:YES animate:NO];
[self _setClippedFrame:_CGRectMake(_CGRectGetMinX(_frame), _CGRectGetMinY(_frame), aSize.width, aSize.height) display:YES animate:NO];
}
/*!
@@ -711,6 +754,9 @@ CPTexturedBackgroundWindowMask
*/
- (void)orderOut:(id)aSender
{
if ([self _sharesChromeWithPlatformWindow])
[_platformWindow orderOut:self];
if ([_delegate respondsToSelector:@selector(windowWillClose:)])
[_delegate windowWillClose:self];
@@ -722,9 +768,6 @@ CPTexturedBackgroundWindowMask
CPApp._keyWindow = nil;
}
if ([self _sharesChromeWithPlatformWindow])
[_platformWindow orderOut:self];
}
/*!
@@ -770,7 +813,7 @@ CPTexturedBackgroundWindowMask
*/
- (BOOL)showsResizeIndicator
{
return [_windowView showsResizeIndicator];
return _showsResizeIndicator;
}
/*!
@@ -778,8 +821,14 @@ CPTexturedBackgroundWindowMask
@param shouldShowResizeIndicator \c YES sets the window to show its resize indicator.
*/
- (void)setShowsResizeIndicator:(BOOL)shouldShowResizeIndicator
{
[_windowView setShowsResizeIndicator:shouldShowResizeIndicator];
{
shouldShowResizeIndicator = !!shouldShowResizeIndicator;
if (_showsResizeIndicator === shouldShowResizeIndicator)
return;
_showsResizeIndicator = shouldShowResizeIndicator;
[_windowView setShowsResizeIndicator:[self showsResizeIndicator]];
}
/*!
@@ -930,21 +979,24 @@ CPTexturedBackgroundWindowMask
return _hasShadow;
}
/*!
Sets whether the window should have a drop shadow.
@param shouldHaveShadow \c YES to have a drop shadow.
*/
- (void)setHasShadow:(BOOL)shouldHaveShadow
- (void)_updateShadow
{
if (_hasShadow === shouldHaveShadow)
return;
_hasShadow = shouldHaveShadow;
if ([self _sharesChromeWithPlatformWindow])
return [_platformWindow setHasShadow:shouldHaveShadow];
{
if (_shadowView)
{
#if PLATFORM(DOM)
CPDOMDisplayServerRemoveChild(_DOMElement, _shadowView._DOMElement);
#endif
_shadowView = nil;
}
if (_hasShadow)
[_platformWindow setHasShadow:_hasShadow];
return;
}
if (_hasShadow && !_shadowView)
{
var bounds = [_windowView bounds];
@@ -978,7 +1030,7 @@ CPTexturedBackgroundWindowMask
CPDOMDisplayServerInsertBefore(_DOMElement, _shadowView._DOMElement, _windowView._DOMElement);
#endif
}
else if (_shadowView)
else if (!_hasShadow && _shadowView)
{
#if PLATFORM(DOM)
CPDOMDisplayServerRemoveChild(_DOMElement, _shadowView._DOMElement);
@@ -987,6 +1039,20 @@ CPTexturedBackgroundWindowMask
}
}
/*!
Sets whether the window should have a drop shadow.
@param shouldHaveShadow \c YES to have a drop shadow.
*/
- (void)setHasShadow:(BOOL)shouldHaveShadow
{
if (_hasShadow === shouldHaveShadow)
return;
_hasShadow = shouldHaveShadow;
[self _updateShadow];
}
- (void)setShadowStyle:(unsigned)aStyle
{
_shadowStyle = aStyle;
@@ -1028,6 +1094,13 @@ CPTexturedBackgroundWindowMask
selector:@selector(windowDidMove:)
name:CPWindowDidMoveNotification
object:self];
if ([_delegate respondsToSelector:@selector(windowDidResize:)])
[defaultCenter
addObserver:_delegate
selector:@selector(windowDidResize:)
name:CPWindowDidResizeNotification
object:self];
}
/*!
@@ -1075,7 +1148,7 @@ CPTexturedBackgroundWindowMask
\c aResponder accept first responder, then finally tell it to become first responder.
@return \c YES if the attempt was successful. \c NO otherwise.
*/
- (void)makeFirstResponder:(CPResponder)aResponder
- (BOOL)makeFirstResponder:(CPResponder)aResponder
{
if (_firstResponder == aResponder)
return YES;
@@ -1255,7 +1328,7 @@ CPTexturedBackgroundWindowMask
var theWindow = [anEvent window];
if ([theWindow isKeyWindow] || [theWindow becomesKeyOnlyIfNeeded])
if ([theWindow isKeyWindow] || [theWindow becomesKeyOnlyIfNeeded] && ![_leftMouseDownView needsPanelToBecomeKey])
return [_leftMouseDownView mouseDown:anEvent];
else
{
@@ -1627,6 +1700,17 @@ CPTexturedBackgroundWindowMask
if (!(_styleMask & CPClosableWindowMask))
return;
if ([self isFullBridge])
{
var event = [CPApp currentEvent];
if ([event type] === CPKeyDown && [event characters] === "w" && ([event modifierFlags] & CPPlatformActionKeyMask))
{
[[self platformWindow] _propagateCurrentDOMEvent:YES];
return;
}
}
// Only send ONE windowShouldClose: message.
if ([_delegate respondsToSelector:@selector(windowShouldClose:)])
{
@@ -1831,8 +1915,8 @@ CPTexturedBackgroundWindowMask
sheetFrame.origin.y = CGRectGetMinY(_frame) + CGRectGetMinY(contentRect);
sheetFrame.origin.x = CGRectGetMinX(_frame) + FLOOR((CGRectGetWidth(_frame) - CGRectGetWidth(sheetFrame)) / 2.0);
[attachedSheet setFrameOrigin:sheetFrame.origin];
[attachedSheet setFrame:sheetFrame display:YES animate:NO];
}
/* @ignore */
@@ -1866,7 +1950,7 @@ CPTexturedBackgroundWindowMask
[CPApp runModalForWindow:aSheet];
[aSheet orderFront:self];
[aSheet setFrame:startFrame];
[aSheet setFrame:startFrame display:YES animate:NO];
_sheetContext["opened"] = YES;
[aSheet _setFrame:endFrame delegate:self duration:0.2 curve:CPAnimationEaseOut];
@@ -1930,7 +2014,8 @@ CPTexturedBackgroundWindowMask
- (void)_setUpMasksForView:(CPView)aView
{
var views = [CPArray arrayWithArray:[aView subviews]];
var views = [aView subviews];
[views addObject:aView];
for (var i = 0, count = [views count]; i < count; i++)
@@ -1945,7 +2030,8 @@ CPTexturedBackgroundWindowMask
- (void)_restoreMasksForView:(CPView)aView
{
var views = [CPArray arrayWithArray:[aView subviews]];
var views = [aView subviews];
[views addObject:aView];
for (var i = 0, count = [views count]; i < count; i++)
@@ -2285,6 +2371,8 @@ var keyViewComparator = function(a, b, context)
return;
_sharesChromeWithPlatformWindow = shouldShareFrameWithPlatformWindow;
[self _updateShadow];
}
- (BOOL)_sharesChromeWithPlatformWindow
@@ -2298,9 +2386,21 @@ var keyViewComparator = function(a, b, context)
*/
- (CPUndoManager)undoManager
{
// If we've ever created an undo manager, return it.
if (_undoManager)
return _undoManager;
// If not, check to see if the document has one.
var documentUndoManager = [[_windowController document] undoManager];
if (documentUndoManager)
return documentUndoManager;
// If not, check to see if the delegate has one.
if (_delegateRespondsToWindowWillReturnUndoManagerSelector)
return [_delegate windowWillReturnUndoManager:self];
// If not, create one.
if (!_undoManager)
_undoManager = [[CPUndoManager alloc] init];
@@ -2406,9 +2506,13 @@ var interpolate = function(fromValue, toValue, progress)
if (value == 1.0)
_window._isAnimating = NO;
[_window setFrameOrigin:CGPointMake(interpolate(CGRectGetMinX(_startFrame), CGRectGetMinX(_targetFrame), value), interpolate(CGRectGetMinY(_startFrame), CGRectGetMinY(_targetFrame), value))];
[_window setFrameSize:CGSizeMake(interpolate(CGRectGetWidth(_startFrame), CGRectGetWidth(_targetFrame), value), interpolate(CGRectGetHeight(_startFrame), CGRectGetHeight(_targetFrame), value))];
var newFrame = CGRectMake(interpolate(CGRectGetMinX(_startFrame), CGRectGetMinX(_targetFrame), value),
interpolate(CGRectGetMinY(_startFrame), CGRectGetMinY(_targetFrame), value),
interpolate(CGRectGetWidth(_startFrame), CGRectGetWidth(_targetFrame), value),
interpolate(CGRectGetHeight(_startFrame), CGRectGetHeight(_targetFrame), value));
[_window setFrame:newFrame display:YES animate:NO];
}
@end
@@ -38,6 +38,11 @@ var _CPToolbarViewBackgroundColor = nil;
return _CPToolbarViewBackgroundColor;
}
- (void)setShowsResizeIndicator:(BOOL)shouldShowResizeIndicator
{
// We don't ever want to show the resize indicator.
}
- (void)tile
{
[super tile];
+1 -1
View File
@@ -48,7 +48,7 @@ var HUD_TITLEBAR_HEIGHT = 26.0;
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground2.png"] size:CPSizeMake(6.0, 78.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground3.png"] size:CPSizeMake(6.0, 1.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground4.png"] size:CPSizeMake(1.0, 1.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground4.png"] size:CPSizeMake(5.0, 5.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground5.png"] size:CPSizeMake(6.0, 1.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground6.png"] size:CPSizeMake(6.0, 6.0)],
+11 -10
View File
@@ -37,6 +37,7 @@ var _CPWindowViewResizeIndicatorImage = nil;
CPView _toolbarView;
// BOOL _isAnimatingToolbar;
CGRect _resizeFrame;
CGPoint _mouseDraggedPoint;
@@ -81,8 +82,6 @@ var _CPWindowViewResizeIndicatorImage = nil;
_styleMask = aStyleMask;
_resizeIndicatorOffset = CGSizeMake(0.0, 0.0);
_toolbarOffset = CGSizeMake(0.0, 0.0);
[self setShowsResizeIndicator:!(_styleMask & CPBorderlessBridgeWindowMask) && (_styleMask & CPResizableWindowMask)];
}
return self;
@@ -162,10 +161,15 @@ var _CPWindowViewResizeIndicatorImage = nil;
if (!visibleFrame)
visibleFrame = [[CPPlatformWindow primaryPlatformWindow] visibleFrame];
var minPointY = 0;
if([CPMenu menuBarVisible])
minPointY = [[CPApp mainMenu] menuBarHeight];
var restrictedPoint = CGPointMake(0, 0);
restrictedPoint.x = MIN(MAX(aPoint.x, -_frame.size.width + 4.0), CGRectGetMaxX(visibleFrame) - 4.0);
restrictedPoint.y = MIN(MAX(aPoint.y, 0.0), CGRectGetMaxY(visibleFrame) - 8.0);
restrictedPoint.y = MIN(MAX(aPoint.y, minPointY), CGRectGetMaxY(visibleFrame) - 8.0);
return restrictedPoint;
}
@@ -213,13 +217,13 @@ var _CPWindowViewResizeIndicatorImage = nil;
[_resizeIndicator setImage:_CPWindowViewResizeIndicatorImage];
[_resizeIndicator setAutoresizingMask:CPViewMinXMargin | CPViewMinYMargin];
[self addSubview:_resizeIndicator];
}
else
{
[_resizeIndicator removeFromSuperview];
_resizeIndicator = nil;
}
}
@@ -322,11 +326,8 @@ var _CPWindowViewResizeIndicatorImage = nil;
if (toolbarView)
{
[toolbarView removeFromSuperview];
[toolbarView setLabelColor:[self toolbarLabelColor]];
if ([self respondsToSelector:@selector(toolbarLabelShadowColor)])
[toolbarView setLabelShadowColor:[self toolbarLabelShadowColor]];
[toolbarView FIXME_setIsHUD:_styleMask & CPHUDBackgroundWindowMask];
[self addSubview:toolbarView];
}
+9 -22
View File
@@ -144,7 +144,7 @@
{
var theWindow = [self window];
if ([theWindow respondsToSelector:@selector(becomesKeyOnlyIfNeeded)] && [theWindow becomesKeyOnlyIfNeeded])
if ([theWindow respondsToSelector:@selector(becomesKeyOnlyIfNeeded)] && [theWindow becomesKeyOnlyIfNeeded])
[theWindow orderFront:aSender];
else
[theWindow makeKeyAndOrderFront:aSender];
@@ -173,6 +173,14 @@
if (_window === nil && [_cibOwner isKindOfClass:[CPDocument class]])
[self setWindow:[_cibOwner valueForKey:@"window"]];
if (!_window)
{
var reason = [CPString stringWithFormat:@"Window for %@ could not be loaded from Cib or no window specified. \
Override loadWindow to load the window manually.", self];
[CPException raise:CPInternalInconsistencyException reason:reason];
}
[self windowDidLoad];
[_document windowControllerDidLoadCib:self];
@@ -399,27 +407,6 @@
*/
- (void)setDocumentEdited:(BOOL)isEdited
{
// we ignore this. in a multi-doc world, we base this flag on the logical OR
// of all the open documents edited state. so this is just a hint to re-check that state.
//[[self window] setDocumentEdited:isEdited];
[self _synchronizeDocumentEditedState];
}
- (void)_synchronizeDocumentEditedState
{
var docs = [self documents],
count = [docs count],
isEdited = NO;
while (count--)
{
if ([docs[count] isDocumentEdited])
{
isEdited = YES;
break;
}
}
[[self window] setDocumentEdited:isEdited];
}
+1 -1
View File
@@ -171,7 +171,7 @@ var CPCibObjectDataKey = @"CPCibObjectDataKey";
- (void)connection:(CPURLConnection)aConnection didReceiveData:(CPString)data
{
_data = [CPData dataWithString:data];
_data = [CPData dataWithEncodedString:data];
}
- (void)connection:(CPURLConnection)aConnection didFailWithError:(CPError)anError
+1 -1
View File
@@ -32,7 +32,7 @@
var selectorName = _label,
selectorNameLength = [selectorName length];
if (selectorNameLength && selectorName[selectorNameLength - 1] !== ':')
if (selectorNameLength && selectorName.charAt(selectorNameLength - 1) !== ':')
selectorName += ':';
var selector = CPSelectorFromString(selectorName);
+39 -19
View File
@@ -27,8 +27,6 @@
var CPCibOwner = @"CPCibOwner";
var LoadInfoForCib = {};
@implementation CPObject (CPCibLoading)
- (void)awakeFromCib
@@ -63,9 +61,11 @@ var LoadInfoForCib = {};
+ (void)loadCibFile:(CPString)anAbsolutePath externalNameTable:(CPDictionary)aNameTable loadDelegate:aDelegate
{
var cib = [[CPCib alloc] initWithContentsOfURL:anAbsolutePath loadDelegate:self];
LoadInfoForCib[[cib UID]] = { loadDelegate:aDelegate, externalNameTable:aNameTable };
[[CPCib alloc]
initWithContentsOfURL:anAbsolutePath
loadDelegate:[[_CPCibLoadDelegate alloc]
initWithLoadDelegate:aDelegate
externalNameTable:aNameTable]];
}
+ (void)loadCibNamed:(CPString)aName owner:(id)anOwner loadDelegate:(id)aDelegate
@@ -82,20 +82,40 @@ var LoadInfoForCib = {};
- (void)loadCibFile:(CPString)aFileName externalNameTable:(CPDictionary)aNameTable loadDelegate:(id)aDelegate
{
var cib = [[CPCib alloc] initWithCibNamed:aFileName bundle:self loadDelegate:[self class]];
LoadInfoForCib[[cib UID]] = { loadDelegate:aDelegate, externalNameTable:aNameTable };
}
+ (void)cibDidFinishLoading:(CPCib)aCib
{
var loadInfo = LoadInfoForCib[[aCib UID]];
delete LoadInfoForCib[[aCib UID]];
[aCib instantiateCibWithExternalNameTable:loadInfo.externalNameTable];
[loadInfo.loadDelegate cibDidFinishLoading:aCib];
[[CPCib alloc]
initWithCibNamed:aFileName
bundle:self
loadDelegate:[[_CPCibLoadDelegate alloc]
initWithLoadDelegate:aDelegate
externalNameTable:aNameTable]];
}
@end
@implementation _CPCibLoadDelegate : CPObject
{
id _loadDelegate;
CPDictionary _externalNameTable;
}
- (id)initWithLoadDelegate:(id)aLoadDelegate externalNameTable:(id)anExternalNameTable
{
self = [self init];
if (self)
{
_loadDelegate = aLoadDelegate;
_externalNameTable = anExternalNameTable;
}
return self;
}
- (void)cibDidFinishLoading:(CPCib)aCib
{
[aCib instantiateCibWithExternalNameTable:_externalNameTable];
[_loadDelegate cibDidFinishLoading:aCib];
}
@end
+7 -3
View File
@@ -37,7 +37,13 @@
- (void)setCustomClassName:(CPString)aClassName
{
if (_className === aClassName)
return;
_className = aClassName;
[self setNeedsDisplay:YES];
[self setNeedsLayout];
}
@end
@@ -97,9 +103,7 @@ var _CPCibCustomViewClassNameKey = @"_CPCibCustomViewClassNameKey";
[view setBounds:[self bounds]];
// Since the object replacement logic hasn't had a chance to kick in yet, we need to do it manually:
// we need to copy subviews since each time we add a subview to a different view its removed from the original subviews array
var subviews = [[self subviews] copy],
var subviews = [self subviews],
index = 0,
count = subviews.length;
+2 -3
View File
@@ -14,7 +14,7 @@ var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinS
_CPCibWindowTemplateWindowViewKey = @"_CPCibWindowTemplateWindowViewKey",
_CPCibWindowTemplateWindowAutorecalculatesKeyViewLoop = @"_CPCibWindowTemplateWindowAutorecalculatesKeyViewLoop";
_CPCibWindowTemplateWindowIsFullPlatformWindowKey = @"_CPCibWindowTemplateWindowIsFullPlatformWindowKey";
_CPCibWindowTemplateWindowIsFullPlatformWindowKey = @"_CPCibWindowTemplateWindowIsFullPlatformWindowKey";
@implementation _CPCibWindowTemplate : CPObject
{
@@ -134,9 +134,8 @@ var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinS
[theWindow setMinSize:_minSize];
if (_maxSize)
[theWindow setMaxSize:_maxSize];
[theWindow setLevel:CPFloatingWindowLevel];
//[result setHidesOnDeactivate:(_wtFlags&0x80000000)?YES:NO];
//[result setHidesOnDeactivate:(_wtFlags&0x80000000)?YES:NO];
[theWindow setTitle:_windowTitle];
// FIXME: we can't autoresize yet...
-1
View File
@@ -312,7 +312,6 @@ function CGContextDrawLinearGradient(aContext, aGradient, aStartPoint, anEndPoin
}
aContext.gState.gradient = vml.join("");
console.log(vml.join(""));
// if (aContext.buffer != nil)
// aContext.buffer += vml.join("");
-4
View File
@@ -4,10 +4,6 @@
<dict>
<key>CPBundleIdentifier</key>
<string>com.280n.AppKit</string>
<key>Default Themes Path</key>
<string>Default.cptheme</string>
<key>Default Theme Name</key>
<string>Default</string>
<key>CPBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CPBundleName</key>
+53
View File
@@ -0,0 +1,53 @@
require("../common.jake");
$BUILD_PATH = FILE.join($BUILD_DIR, $CONFIGURATION, 'AppKit');
AppKitFiles = new FileList("**/*.j").exclude('CoreGraphics/CGContextCanvas.j', 'CoreGraphics/CGContextVML.j', 'Themes/**/*', 'Tools/**/*', "Platform/DOM/CPPlatform.j", "Platform/DOM/CPPlatformString.j");
FIXME_fileDependency (FILE.join("Platform", "CPPlatform.j"), FILE.join("Platform", "DOM", "CPPlatform.j"));
FIXME_fileDependency (FILE.join("Platform", "CPPlatformString.j"), FILE.join("Platform", "DOM", "CPPlatformString.j"));
appKitTask = framework ("AppKit", function(appKitTask)
{
appKitTask.setBuildIntermediatesPath(FILE.join($BUILD_DIR, "AppKit.build", $CONFIGURATION))
appKitTask.setBuildPath($BUILD_CONFIGURATION_DIR);
appKitTask.setAuthor("280 North, Inc.");
appKitTask.setEmail("feedback @nospam@ 280north.com");
appKitTask.setSummary("AppKit classes for Cappuccino");
appKitTask.setIdentifier("com.280n.AppKit");
appKitTask.setVersion("0.7.9");
appKitTask.setLicense(BundleTask.License.LGPL_v2_1);
appKitTask.setSources(AppKitFiles);
appKitTask.setResources(new FileList("Resources/**/*"));
appKitTask.setFlattensSources(true);
appKitTask.setInfoPlistPath("Info.plist");
if ($CONFIGURATION === "Release")
appKitTask.setCompilerFlags("-O");
else
appKitTask.setCompilerFlags("-DDEBUG -g");
});
$BUILD_CJS_CAPPUCCINO_APPKIT = FILE.join($BUILD_CJS_CAPPUCCINO_FRAMEWORKS, "AppKit");
filedir ($BUILD_CJS_CAPPUCCINO_APPKIT, ["AppKit"], function()
{
cp_r(appKitTask.buildProductPath(), $BUILD_CJS_CAPPUCCINO_APPKIT);
});
subtasks (["Themes"], ["clean", "clobber"]);
task ("Theme", [$BUILD_CJS_CAPPUCCINO_APPKIT], function()
{
subjake(["Themes"], "build");
cp_r(FILE.join($BUILD_DIR, $CONFIGURATION, 'Aristo.blend'), FILE.join($BUILD_PATH, 'Resources', 'Aristo.blend'));
cp_r(FILE.join($BUILD_DIR, $CONFIGURATION, 'Aristo.blend'), FILE.join($BUILD_CJS_CAPPUCCINO_APPKIT, "Resources", "Aristo.blend"));
});
task ("build", ["AppKit", $BUILD_CJS_CAPPUCCINO_APPKIT, "Theme"]);
CLOBBER.include($BUILD_CJS_CAPPUCCINO_APPKIT);
-471
View File
@@ -1,471 +0,0 @@
/*
* CPTableColumn.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 <Foundation/Foundation.j>
/*
@ignore
*/
/*
@global
@class CPTableColumn
*/
CPTableColumnNoResizing = 0;
/*
@global
@class CPTableColumn
*/
CPTableColumnAutoresizingMask = 1;
/*
@global
@class CPTableColumn
*/
CPTableColumnUserResizingMask = 2;
#define PurgableInfoMake(aView, aRow) { view:(aView), row:(aRow) }
#define PurgableInfoView(anInfo) ((anInfo).view)
#define PurgableInfoRow(anInfo) ((anInfo).row)
/*!
@ingroup appkit
@class CPTableColumn
An CPTableColumn object mainly keeps information about the width of the column, its minimum and maximum width; whether the column can be edited or resized; and the cells used to draw the column header and the data in the column. You can change all these attributes of the column by calling the appropriate methods. Please note that the table column does not hold nor has access to the data to be displayed in the column; this data is maintained in the table view's data source.</p>
<p>Each CPTableColumn object is identified by a CPString, called the column identifier. The reason is that, after a column has been added to a table view, the user might move the columns around, so there is a need to identify the columns regardless of its position in the table.
@ignore
*/
@implementation CPTableColumn : CPObject
{
CPString _identifier;
CPView _headerView;
CPTableView _tableView;
float _width;
float _minWidth;
float _maxWidth;
unsigned _resizingMask;
CPView _dataView; // default data view for this column
Object _dataViewData; // cache of data view archives (key=data view UID, value=data view archive)
Object _dataViewForView; // mapping from view instances back to their data view prototype (key=view instance UID, value=data view)
Object _purgableInfosForDataView; // (key=data view UID, value=)
}
/*!
Initializes the table column with the specified identifier.
@param anIdentifier the identifier
@return the initialized table column
*/
- (id)initWithIdentifier:(CPString)anIdentifier
{
self = [super init];
if (self)
{
[self _init];
_identifier = anIdentifier;
_width = 40.0;
_minWidth = 8.0;
_maxWidth = 1000.0;
var dataView = [[CPTextField alloc] initWithFrame:CPRectMakeZero()];
[dataView setValue:[CPColor whiteColor] forThemeAttribute:"text-color" inState:CPThemeStateHighlighted];
[self setDataView:dataView];
_headerView = [[CPTextField alloc] initWithFrame:CPRectMakeZero()];
[_headerView setBackgroundColor:[CPColor greenColor]];
}
return self;
}
- (void)_init
{
_dataViewData = {};
_dataViewForView = {};
_purgableInfosForDataView = {};
}
/*!
Sets the table column's identifier
@param anIdentifier the new identifier
*/
- (void)setIdentifier:(CPString)anIdentifier
{
_identifier = anIdentifier;
}
/*!
Returns the table column's identifier
*/
- (CPString)identifier
{
return _identifier;
}
// Setting the CPTableView
/*!
Sets the table's view. This is called automatically by Cappuccino.
@param aTableView the new table view
*/
- (void)setTableView:(CPTableView)aTableView
{
_tableView = aTableView;
}
/*!
Returns the column's table view.
*/
- (CPTableView)tableView
{
return _tableView;
}
// Controlling size
/*!
Sets the column's width.
@param aWidth the new column width
*/
- (void)setWidth:(float)aWidth
{
_width = aWidth;
}
/*!
Returns the column's width
*/
- (float)width
{
return _width;
}
/*!
Sets column's minimum width.
@param aWidth the new minimum column width
*/
- (void)setMinWidth:(float)aWidth
{
if (_width < (_minWidth = aWidth))
[self setWidth:_minWidth];
}
/*!
The column's minimum width
*/
- (float)minWidth
{
return _minWidth;
}
/*!
Sets the column's maximum width.
@param aWidth the new maximum width
*/
- (void)setMaxWidth:(float)aWidth
{
if (_width > (_maxmimumWidth = aWidth))
[self setWidth:_maxWidth];
}
/*!
Sets the resizing mask. The mask is one of:
<pre>
CPTableColumnNoResizing;
CPTableColumnAutoresizingMask;
CPTableColumnUserResizingMask;
</pre>
@param aMask the new resizing mask
*/
- (void)setResizingMask:(unsigned)aMask
{
_resizingMask = aMask;
}
/*!
Returns the column's resizing mask. One of:
<pre>
CPTableColumnNoResizing;
CPTableColumnAutoresizingMask;
CPTableColumnUserResizingMask;
</pre>
*/
- (unsigned)resizingMask
{
return _resizingMask;
}
/*!
Resizes the column according to the min, max and set width.
*/
- (void)sizeToFit
{
var width = CPRectGetWidth([_headerView frame]);
if (width < _minWidth)
[self setMinWidth:width];
else if (width > _maxWidth)
[self setMaxWidth:width]
if (_width != width)
[self setWidth:width];
}
/*!
Sets whether the column in this data is editable.
@param aFlag <code>YES</code> means the column data is editable
*/
- (void)setEditable:(BOOL)aFlag
{
_isEditable = aFlag;
}
/*!
Returns <code>YES</code> if the column data is editable.
*/
- (BOOL)isEditable
{
return _isEditable;
}
//Setting the column header view
/*!
Sets the view that draws the column's header.
@param aHeaderView the view that will draws the column header
*/
- (void)setHeaderView:(CPView)aView
{
_headerView = aView;
}
/*!
Return the view that draws the column's header
*/
- (CPView)headerView
{
return _headerView;
}
/*!
Sets the data cell that draws rows in this column.
*/
- (void)setDataCell:(CPView <CPCoding>)aView
{
[self setDataView:aView];
}
/*
Sets the data view that draws rows in this column.
*/
- (void)setDataView:(CPView <CPCoding>)aView
{
if (_dataView)
_dataViewData[[_dataView UID]] = nil;
_dataView = aView;
_dataViewData[[aView UID]] = [CPKeyedArchiver archivedDataWithRootObject:aView];
}
/*!
Returns the data cell that draws rows in this column
*/
- (CPCell)dataCell
{
return _dataView;
}
/*
Returns the data view that draws rows in this column
*/
- (CPView)dataView
{
return [self dataCell];
}
/*!
By default returns the value from <code>dataCell</code>. This can
be overridden by a subclass to return different cells for different
rows.
@param aRowIndex the index of the row to obtain the cell for
*/
- (CPCell)dataCellForRow:(int)aRowIndex
{
return [self dataView];
}
- (CPView)dataViewForRow:(int)aRowIndex
{
return [self dataCellForRow:aRowIndex];
}
/*
- (void)_markViewAsPurgable:(CPView)aView
{
var viewUID = [aView UID],
dataViewUID = [_dataViewForView[viewUID] UID];
if (!_purgableInfosForDataView[dataViewUID])
_purgableInfosForDataView[dataViewUID] = [CPDictionary dictionary];
[_purgableInfosForDataView[dataViewUID] setObject:aView forKey:viewUID];
}
*/
- (void)_markView:(CPView)aView inRow:(unsigned)aRow asPurgable:(BOOL)isPurgable
{
var viewUID = [aView UID],
dataViewUID = [_dataViewForView[viewUID] UID];
if (!_purgableInfosForDataView[dataViewUID])
{
if (!isPurgable)
return;
_purgableInfosForDataView[dataViewUID] = {};
}
if (!isPurgable) {
if (_purgableInfosForDataView[dataViewUID][viewUID])
CPLog.warn("removing unpurgable " + _purgableInfosForDataView[dataViewUID][viewUID]);
delete _purgableInfosForDataView[dataViewUID][viewUID];
}
else
_purgableInfosForDataView[dataViewUID][viewUID] = PurgableInfoMake(aView, aRow);
}
- (CPView)_newDataViewForRow:(int)aRowIndex avoidingRows:(CPRange)rows
{
var view = [self dataViewForRow:aRowIndex],
viewUID = [view UID],
purgableInfos = _purgableInfosForDataView[viewUID];
if (purgableInfos)
{
for (var key in purgableInfos)
{
var info = purgableInfos[key];
//if (!CPLocationInRange(PurgableInfoRow(info), rows))
//{
//CPLog.debug("yes, a purged view is usable, its called: " + PurgableInfoView(info));
delete purgableInfos[key];
return PurgableInfoView(info);
//}
//else
// CPLog.warn("avoiding");
}
}
// if we haven't cached an archive of the data view, do it now
if (!_dataViewData[viewUID])
_dataViewData[viewUID] = [CPKeyedArchiver archivedDataWithRootObject:view];
// unarchive the data view cache
var newView = [CPKeyedUnarchiver unarchiveObjectWithData:_dataViewData[viewUID]];
// map the new view's UID to it's data view prototype
_dataViewForView[[newView UID]] = view;
CPLog.warn("creating cell: %s", newView);
return newView;
}
- (void)_purge
{
for (var viewUID in _purgableInfosForDataView)
{
var purgableInfos = _purgableInfosForDataView[viewUID];
for (var key in purgableInfos)
{
var view = PurgableInfoView(purgableInfos[key]);
if (!view)
CPLog.info("key="+key+" view=" + view + " purgableInfos[key]="+purgableInfos[key])
else if (view._superview) {
//CPLog.error("PURGING: (removing)" + view);
//[view removeFromSuperview];
[view setHidden:YES];
}
//else
// CPLog.warn("PURGING: (already removed)" + view);
//delete purgableInfos[key];
}
}
}
@end
var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
CPTableColumnHeaderViewKey = @"CPTableColumnHeaderViewKey",
CPTableColumnDataViewKey = @"CPTableColumnDataViewKey",
CPTableColumnWidthKey = @"CPTableColumnWidthKey",
CPTableColumnMinWidthKey = @"CPTableColumnMinWidthKey",
CPTableColumnMaxWidthKey = @"CPTableColumnMaxWidthKey",
CPTableColumnResizingMaskKey = @"CPTableColumnResizingMaskKey";
@implementation CPTableColumn (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
[self _init];
_identifier = [aCoder decodeObjectForKey:CPTableColumnIdentifierKey];
[self setHeaderView:[aCoder decodeObjectForKey:CPTableColumnHeaderViewKey]];
[self setDataView:[aCoder decodeObjectForKey:CPTableColumnDataViewKey]];
_width = [aCoder decodeFloatForKey:CPTableColumnWidthKey];
_minWidth = [aCoder decodeFloatForKey:CPTableColumnMinWidthKey];
_maxWidth = [aCoder decodeFloatForKey:CPTableColumnMaxWidthKey];
_resizingMask = [aCoder decodeBoolForKey:CPTableColumnResizingMaskKey];
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[aCoder encodeObject:_identifier forKey:CPTableColumnIdentifierKey];
[aCoder encodeObject:_headerView forKey:CPTableColumnHeaderViewKey];
[aCoder encodeObject:_dataView forKey:CPTableColumnDataViewKey];
[aCoder encodeObject:_width forKey:CPTableColumnWidthKey];
[aCoder encodeObject:_minWidth forKey:CPTableColumnMinWidthKey];
[aCoder encodeObject:_maxWidth forKey:CPTableColumnMaxWidthKey];
[aCoder encodeObject:_resizingMask forKey:CPTableColumnResizingMaskKey];
}
@end
File diff suppressed because it is too large. Load diff
+42 -20
View File
@@ -1,56 +1,78 @@
/*
* CPPlatform.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 <Foundation/CPObject.j>
#include "Platform.h"
@implementation CPPlatform : CPObject
@implementation CPBasePlatform : CPObject
{
}
+ (void)bootstrap
{
#if PLATFORM(DOM)
var body = document.getElementsByTagName("body")[0];
body.innerHTML = ""; // Get rid of anything that might be lingering in the body element.
body.style.overflow = "hidden";
if (document.documentElement)
document.documentElement.style.overflow = "hidden";
#endif
[CPPlatformString bootstrap];
[CPPlatformWindow setPrimaryPlatformWindow:[[CPPlatformWindow alloc] _init]];
}
+ (BOOL)isBrowser
{
return typeof window.cpIsDesktop === "undefined";
return NO;
}
+ (BOOL)supportsDragAndDrop
{
return CPFeatureIsCompatible(CPHTMLDragAndDropFeature);
return NO;
}
+ (BOOL)supportsNativeMainMenu
{
return (typeof window["cpSetMainMenu"] === "function");
return NO;
}
+ (void)terminateApplication
{
if (typeof window["cpTerminate"] === "function")
window.cpTerminate();
}
+ (void)activateIgnoringOtherApps:(BOOL)shouldIgnoreOtherApps
{
#if PLATFORM(DOM)
if (typeof window["cpActivateIgnoringOtherApps"] === "function")
window.cpActivateIgnoringOtherApps(!!shouldIgnoreOtherApps);
#endif
}
+ (void)hideOtherApplications:(id)aSender
{
}
+ (void)hide:(id)aSender
{
}
@end
#if PLATFORM(DOM)
#include "DOM/CPPlatform.j"
#else
@implementation CPPlatform : CPBasePlatform
{
}
@end
#endif
+31 -84
View File
@@ -1,4 +1,24 @@
/*
* CPPlatformString.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 <Foundation/CPObject.j>
@@ -6,99 +26,26 @@
#include "Platform.h"
#if PLATFORM(DOM)
var DOMIFrameElement = nil,
DOMSpanElement = nil,
DefaultFont = nil;
#endif
@implementation CPPlatformString : CPObject
@implementation CPBasePlatformString : CPObject
{
}
+ (void)bootstrap
{
#if PLATFORM(DOM)
DOMIFrameElement = document.createElement("iframe");
DOMIFrameElement.name = name = "iframe_" + FLOOR(RAND() * 10000);
DOMIFrameElement.style.position = "absolute";
DOMIFrameElement.style.left = "-100px";
DOMIFrameElement.style.top = "-100px";
DOMIFrameElement.style.width = "1px";
DOMIFrameElement.style.height = "1px";
DOMIFrameElement.style.borderWidth = "0px";
DOMIFrameElement.style.background = "blue";
DOMIFrameElement.style.overflow = "hidden";
DOMIFrameElement.style.zIndex = 100000000000;
document.getElementsByTagName("body")[0].appendChild(DOMIFrameElement);
var DOMIFrameDocument = (DOMIFrameElement.contentDocument || DOMIFrameElement.contentWindow.document);
DOMIFrameDocument.write("<html><head></head><body></body></html>");
DOMIFrameDocument.close();
DOMSpanElement = DOMIFrameDocument.createElement("span");
DOMSpanElement.style.position = "absolute";
DOMSpanElement.style.whiteSpace = "pre";
DOMSpanElement.style.visibility = "visible";
DOMSpanElement.style.padding = "0px";
DOMSpanElement.style.margin = "0px";
DOMSpanElement.style.background = "red";
DOMIFrameDocument.getElementsByTagName("body")[0].appendChild(DOMSpanElement);
#endif
}
+ (CGSize)sizeOfString:(CPString)aString withFont:(CPFont)aFont forWidth:(float)aWidth
{
#if PLATFORM(DOM)
if (!aFont)
{
if (!DefaultFont)
DefaultFont = [CPFont systemFontOfSize:12.0];
aFont = DefaultFont;
}
var style = DOMSpanElement.style;
if (aWidth === NULL)
{
style.width = "";
style.whiteSpace = "pre";
}
else
{
style.width = ROUND(aWidth) + "px";
if (document.attachEvent)
style.wordWrap = "break-word";
else
{
style.whiteSpace = "-o-pre-wrap";
style.whiteSpace = "-pre-wrap";
style.whiteSpace = "-moz-pre-wrap";
style.whiteSpace = "pre-wrap";
}
}
style.font = [aFont cssString];
if (CPFeatureIsCompatible(CPJavascriptInnerTextFeature))
DOMSpanElement.innerText = aString;
else if (CPFeatureIsCompatible(CPJavascriptTextContentFeature))
DOMSpanElement.textContent = aString;
return _CGSizeMake(DOMSpanElement.clientWidth, DOMSpanElement.clientHeight);
#else
return _CGSizeMakeZero();
#endif
}
@end
#if PLATFORM(DOM)
#include "DOM/CPPlatformString.j"
#else
@implementation CPPlatformString : CPBasePlatformString
{
}
@end
#endif
+32 -1
View File
@@ -1,9 +1,31 @@
/*
* CPPlatformWindow.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 <Foundation/CPObject.j>
#import "Platform.h"
#import "../CoreGraphics/CGGeometry.h"
var PrimaryPlatformWindow = NULL;
@implementation CPPlatformWindow : CPObject
@@ -30,6 +52,10 @@ var PrimaryPlatformWindow = NULL;
Object _charCodes;
unsigned _keyCode;
unsigned _lastKey;
BOOL _capsLockActive;
BOOL _ignoreNativeCopyOrCutEvent;
BOOL _ignoreNativePastePreparation;
BOOL _DOMEventMode;
@@ -41,6 +67,11 @@ var PrimaryPlatformWindow = NULL;
#endif
}
+ (CPSet)visiblePlatformWindows
{
return [CPSet set];
}
+ (CPPlatformWindow)primaryPlatformWindow
{
return PrimaryPlatformWindow;
@@ -95,7 +126,7 @@ var PrimaryPlatformWindow = NULL;
frame.origin = CGPointMakeZero();
if ([CPMenu menuBarVisible])
if ([CPMenu menuBarVisible] && [CPPlatformWindow primaryPlatformWindow] === self)
{
var menuBarHeight = [[CPApp mainMenu] menuBarHeight];
+126
View File
@@ -0,0 +1,126 @@
/*
* CPPlatform+DOM.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
*/
if (typeof window["CPPlatformEnableHTMLDragAndDrop"] === "undefined")
CPPlatformEnableHTMLDragAndDrop = NO;
CPPlatformDidClearBodyElementNotification = @"CPPlatformDidClearBodyElementNotification";
CPPlatformWillClearBodyElementNotification = @"CPPlatformWillClearBodyElementNotification";
var screenNeedsInitialization = NO,
mainBodyElement = nil,
elementRemovalTest = new RegExp("\\bcpdontremove\\b", "g");
@implementation CPPlatform : CPBasePlatform
{
}
+ (void)initialize
{
if (self !== [CPPlatform class])
return;
screenNeedsInitialization = [CPPlatform isBrowser];
}
+ (BOOL)isBrowser
{
return typeof window.cpIsDesktop === "undefined";
}
+ (BOOL)supportsDragAndDrop
{
return CPFeatureIsCompatible(CPHTMLDragAndDropFeature) && (CPPlatformEnableHTMLDragAndDrop || ![self isBrowser]);
}
+ (BOOL)supportsNativeMainMenu
{
return (typeof window["cpSetMainMenu"] === "function");
}
+ (void)terminateApplication
{
if (typeof window["cpTerminate"] === "function")
window.cpTerminate();
}
+ (void)activateIgnoringOtherApps:(BOOL)shouldIgnoreOtherApps
{
if (typeof window["cpActivateIgnoringOtherApps"] === "function")
window.cpActivateIgnoringOtherApps(!!shouldIgnoreOtherApps);
}
+ (void)hideOtherApplications:(id)aSender
{
if (typeof window["cpHideOtherApplications"] === "function")
window.cpHideOtherApplications();
}
+ (void)hide:(id)aSender
{
if (typeof window["cpHide"] === "function")
window.cpHide();
}
+ (DOMElement)mainBodyElement
{
if (!mainBodyElement)
mainBodyElement = document.getElementById("cappuccino-body") || document.body;
return mainBodyElement;
}
+ (void)initializeScreenIfNecessary
{
if (!screenNeedsInitialization)
return;
screenNeedsInitialization = NO;
[[CPNotificationCenter defaultCenter]
postNotificationName:CPPlatformWillClearBodyElementNotification
object:self];
var bodyElement = [self mainBodyElement];
// Get rid of any of the original contents of the page.
var children = bodyElement.childNodes,
length = children.length;
while (length--)
{
var element = children[length];
if (!element.className || element.className.match(elementRemovalTest) === null)
bodyElement.removeChild(element);
}
bodyElement.style.overflow = "hidden";
if (document.documentElement)
document.documentElement.style.overflow = "hidden";
[[CPNotificationCenter defaultCenter]
postNotificationName:CPPlatformDidClearBodyElementNotification
object:self];
}
@end
+118
View File
@@ -0,0 +1,118 @@
/*
* CPPlatformString.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
*/
#include "../CoreGraphics/CGGeometry.h"
var DOMSpanElement = nil,
DOMIFrameElement = nil,
DefaultFont = nil;
@implementation CPPlatformString : CPBasePlatformString
{
}
+ (void)bootstrap
{
[self createDOMElements];
}
+ (void)createDOMElements
{
DOMIFrameElement = document.createElement("iframe");
// necessary for Safari caching bug:
DOMIFrameElement.name = "iframe_" + FLOOR(RAND() * 10000);
DOMIFrameElement.style.position = "absolute";
DOMIFrameElement.style.left = "-100px";
DOMIFrameElement.style.top = "-100px";
DOMIFrameElement.style.width = "1px";
DOMIFrameElement.style.height = "1px";
DOMIFrameElement.style.borderWidth = "0px";
DOMIFrameElement.style.overflow = "hidden";
DOMIFrameElement.style.zIndex = 100000000000;
DOMIFrameElement.className = "cpdontremove";
var bodyElement = [CPPlatform mainBodyElement];
bodyElement.appendChild(DOMIFrameElement);
var DOMIFrameDocument = (DOMIFrameElement.contentDocument || DOMIFrameElement.contentWindow.document);
DOMIFrameDocument.write("<html><head></head><body></body></html>");
DOMIFrameDocument.close();
// IE needs this wide <div> to prevent unwanted text wrapping:
var DOMDivElement = DOMIFrameDocument.createElement("div");
DOMDivElement.style.position = "absolute";
DOMDivElement.style.width = "100000px";
DOMIFrameDocument.body.appendChild(DOMDivElement);
DOMSpanElement = DOMIFrameDocument.createElement("span");
DOMSpanElement.style.position = "absolute";
DOMSpanElement.style.whiteSpace = "pre";
DOMSpanElement.style.visibility = "visible";
DOMSpanElement.style.padding = "0px";
DOMSpanElement.style.margin = "0px";
DOMDivElement.appendChild(DOMSpanElement);
}
+ (CGSize)sizeOfString:(CPString)aString withFont:(CPFont)aFont forWidth:(float)aWidth
{
if (!aFont)
{
if (!DefaultFont)
DefaultFont = [CPFont systemFontOfSize:12.0];
aFont = DefaultFont;
}
if (!DOMIFrameElement)
[self createDOMElements];
var style = DOMSpanElement.style;
if (!aWidth)
{
style.width = "";
style.whiteSpace = "pre";
}
else
{
style.width = ROUND(aWidth) + "px";
style.wordWrap = "break-word";
style.whiteSpace = "-o-pre-wrap";
style.whiteSpace = "-pre-wrap";
style.whiteSpace = "-moz-pre-wrap";
style.whiteSpace = "pre-wrap";
}
style.font = [aFont cssString];
if (CPFeatureIsCompatible(CPJavascriptInnerTextFeature))
DOMSpanElement.innerText = aString;
else if (CPFeatureIsCompatible(CPJavascriptTextContentFeature))
DOMSpanElement.textContent = aString;
return _CGSizeMake(DOMSpanElement.clientWidth, DOMSpanElement.clientHeight);
}
@end
+391 -166
View File
@@ -1,5 +1,5 @@
/*
* _CPDOMWindow.j
* CPPlatformWindow+DOM.j
* AppKit
*
* Created by Francisco Tolmasky.
@@ -19,6 +19,93 @@
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* THIS DOCUMENTATION STOLEN DIRECTLY FROM GOOGLE CLOSURE (licensed under Apache 2)
*
* Different web browsers have very different keyboard event handling. Most
* importantly is that only certain browsers repeat keydown events:
* IE, Opera, FF/Win32, and Safari 3 repeat keydown events.
* FF/Mac and Safari 2 do not.
*
* For the purposes of this code, "Safari 3" means WebKit 525+, when WebKit
* decided that they should try to match IE's key handling behavior.
* Safari 3.0.4, which shipped with Leopard (WebKit 523), has the
* Safari 2 behavior.
*
* Firefox, Safari, Opera prevent on keypress
*
* IE prevents on keydown
*
* Firefox does not fire keypress for shift, ctrl, alt
* Firefox does fire keydown for shift, ctrl, alt, meta
* Firefox does not repeat keydown for shift, ctrl, alt, meta
*
* Firefox does not fire keypress for up and down in an input
*
* Opera fires keypress for shift, ctrl, alt, meta
* Opera does not repeat keypress for shift, ctrl, alt, meta
*
* Safari 2 and 3 do not fire keypress for shift, ctrl, alt
* Safari 2 does not fire keydown for shift, ctrl, alt
* Safari 3 *does* fire keydown for shift, ctrl, alt
*
* IE provides the keycode for keyup/down events and the charcode (in the
* keycode field) for keypress.
*
* Mozilla provides the keycode for keyup/down and the charcode for keypress
* unless it's a non text modifying key in which case the keycode is provided.
*
* Safari 3 provides the keycode and charcode for all events.
*
* Opera provides the keycode for keyup/down event and either the charcode or
* the keycode (in the keycode field) for keypress events.
*
* Firefox x11 doesn't fire keydown events if a another key is already held down
* until the first key is released. This can cause a key event to be fired with
* a keyCode for the first key and a charCode for the second key.
*
* Safari 2 in keypress (not supported)
*
* charCode keyCode which
* ENTER: 13 13 13
* F1: 63236 63236 63236
* F8: 63243 63243 63243
* ...
* p: 112 112 112
* P: 80 80 80
*
* Firefox, keypress:
*
* charCode keyCode which
* ENTER: 0 13 13
* F1: 0 112 0
* F8: 0 119 0
* ...
* p: 112 0 112
* P: 80 0 80
*
* Opera, Mac+Win32, keypress:
*
* charCode keyCode which
* ENTER: undefined 13 13
* F1: undefined 112 0
* F8: undefined 119 0
* ...
* p: undefined 112 112
* P: undefined 80 80
*
* IE7, keydown
*
* charCode keyCode which
* ENTER: undefined 13 undefined
* F1: undefined 112 undefined
* F8: undefined 119 undefined
* ...
* p: undefined 80 undefined
* P: undefined 80 undefined
*/
@import <Foundation/CPObject.j>
@import <Foundation/CPRunLoop.j>
@@ -30,33 +117,12 @@
@import "CPPlatform.j"
@import "CPPlatformWindow.j"
@import "CPPlatformWindow+DOMKeys.j"
#import "../../CoreGraphics/CGGeometry.h"
var DoubleClick = "dblclick",
MouseDown = "mousedown",
MouseUp = "mouseup",
MouseMove = "mousemove",
MouseDrag = "mousedrag",
KeyUp = "keyup",
KeyDown = "keydown",
KeyPress = "keypress",
Copy = "copy",
Paste = "paste",
Resize = "resize",
ScrollWheel = "mousewheel",
TouchStart = "touchstart",
TouchMove = "touchmove",
TouchEnd = "touchend",
TouchCancel = "touchcancel";
var ExcludedDOMElements = [];
ExcludedDOMElements["INPUT"] = YES;
ExcludedDOMElements["SELECT"] = YES;
ExcludedDOMElements["TEXTAREA"] = YES;
ExcludedDOMElements["OPTION"] = YES;
// List of all open native windows
var PlatformWindows = [CPSet set];
// Define up here so compressor knows about em.
var CPDOMEventGetClickCount,
@@ -68,9 +134,12 @@ var CPDOMEventGetClickCount,
//might be mac only, we should investigate futher later.
var KeyCodesToPrevent = {},
CharacterKeysToPrevent = {},
KeyCodesWithoutKeyPressEvents = { '8':1, '9':1, '16':1, '37':1, '38':1, '39':1, '40':1, '46':1, '33':1, '34':1 };
MozKeyCodeToKeyCodeMap = {
61: 187, // =, equals
59: 186 // ;, semicolon
};
var CTRL_KEY_CODE = 17;
KeyCodesToPrevent[CPKeyCodes.A] = YES;
var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
@@ -159,11 +228,40 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
_DOMWindow.blur();
}
- (void)createDOMElements
{
var theDocument = _DOMWindow.document;
// This guy fixes an issue in Firefox where if you focus the URL field, we stop getting key events
_DOMFocusElement = theDocument.createElement("input");
_DOMFocusElement.style.position = "absolute";
_DOMFocusElement.style.zIndex = "-1000";
_DOMFocusElement.style.opacity = "0";
_DOMFocusElement.style.filter = "alpha(opacity=0)";
_DOMFocusElement.className = "cpdontremove";
_DOMBodyElement.appendChild(_DOMFocusElement);
// Create Native Pasteboard handler.
_DOMPasteboardElement = theDocument.createElement("textarea");
_DOMPasteboardElement.style.position = "absolute";
_DOMPasteboardElement.style.top = "-10000px";
_DOMPasteboardElement.style.zIndex = "999";
_DOMPasteboardElement.className = "cpdontremove";
_DOMBodyElement.appendChild(_DOMPasteboardElement);
// Make sure the pastboard element is blurred.
_DOMPasteboardElement.blur();
}
- (void)registerDOMWindow
{
var theDocument = _DOMWindow.document;
_DOMBodyElement = theDocument.getElementsByTagName("body")[0];
_DOMBodyElement = theDocument.getElementById("cappuccino-body") || theDocument.body;
// FIXME: Always do this?
if ([CPPlatform supportsDragAndDrop])
@@ -171,27 +269,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
_DOMBodyElement.webkitTouchCallout = "none";
_DOMFocusElement = theDocument.createElement("input");
_DOMFocusElement.style.position = "absolute";
_DOMFocusElement.style.zIndex = "-1000";
_DOMFocusElement.style.opacity = "0";
_DOMFocusElement.style.filter = "alpha(opacity=0)";
_DOMBodyElement.appendChild(_DOMFocusElement);
// Create Native Pasteboard handler.
_DOMPasteboardElement = theDocument.createElement("input");
_DOMPasteboardElement.style.position = "absolute";
_DOMPasteboardElement.style.top = "-10000px";
_DOMPasteboardElement.style.zIndex = "99";
_DOMBodyElement.appendChild(_DOMPasteboardElement);
// Make sure the pastboard element is blurred.
_DOMPasteboardElement.blur();
[self createDOMElements];
[self _addLayers];
var theClass = [self class],
@@ -203,6 +281,14 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
resizeEventImplementation = class_getMethodImplementation(theClass, resizeEventSelector),
resizeEventCallback = function (anEvent) { resizeEventImplementation(self, nil, anEvent); },
copyEventSelector = @selector(copyEvent:),
copyEventImplementation = class_getMethodImplementation(theClass, copyEventSelector),
copyEventCallback = function (anEvent) {copyEventImplementation(self, nil, anEvent); },
pasteEventSelector = @selector(pasteEvent:),
pasteEventImplementation = class_getMethodImplementation(theClass, pasteEventSelector),
pasteEventCallback = function (anEvent) {pasteEventImplementation(self, nil, anEvent); },
keyEventSelector = @selector(keyEvent:),
keyEventImplementation = class_getMethodImplementation(theClass, keyEventSelector),
keyEventCallback = function (anEvent) { keyEventImplementation(self, nil, anEvent); },
@@ -219,6 +305,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
touchEventImplementation = class_getMethodImplementation(theClass, touchEventSelector),
touchEventCallback = function (anEvent) { touchEventImplementation(self, nil, anEvent); };
if (theDocument.addEventListener)
{
if ([CPPlatform supportsDragAndDrop])
@@ -235,6 +322,10 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
theDocument.addEventListener("mousedown", mouseEventCallback, NO);
theDocument.addEventListener("mousemove", mouseEventCallback, NO);
theDocument.addEventListener("beforecopy", copyEventCallback, NO);
theDocument.addEventListener("beforecut", copyEventCallback, NO);
theDocument.addEventListener("beforepaste", pasteEventCallback, NO);
theDocument.addEventListener("keyup", keyEventCallback, NO);
theDocument.addEventListener("keydown", keyEventCallback, NO);
theDocument.addEventListener("keypress", keyEventCallback, NO);
@@ -262,6 +353,10 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
theDocument.removeEventListener("keydown", keyEventCallback, NO);
theDocument.removeEventListener("keypress", keyEventCallback, NO);
theDocument.removeEventListener("beforecopy", copyEventCallback, NO);
theDocument.removeEventListener("beforecut", copyEventCallback, NO);
theDocument.removeEventListener("beforepaste", pasteEventCallback, NO);
theDocument.removeEventListener("touchstart", touchEventCallback, NO);
theDocument.removeEventListener("touchend", touchEventCallback, NO);
theDocument.removeEventListener("touchmove", touchEventCallback, NO);
@@ -274,6 +369,8 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
//_DOMWindow.removeEventListener("beforeunload", this, NO);
[PlatformWindows removeObject:self];
self._DOMWindow = nil;
}, NO);
}
@@ -293,38 +390,45 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
_DOMWindow.onmousewheel = scrollEventCallback;
theDocument.onmousewheel = scrollEventCallback;
theDocument.body.ondrag = function () { return NO; };
theDocument.body.onselectstart = function () { return _DOMWindow.event.srcElement === _DOMPasteboardElement; };
_DOMBodyElement.ondrag = function () { return NO; };
_DOMBodyElement.onselectstart = function () { return _DOMWindow.event.srcElement === _DOMPasteboardElement; };
_DOMWindow.attachEvent("onbeforeunload", function()
{
[self updateFromNativeContentRect];
[self _removeLayers];
theDocument.removeEvent("onmouseup", mouseEventCallback);
theDocument.removeEvent("onmousedown", mouseEventCallback);
theDocument.removeEvent("onmousemove", mouseEventCallback);
theDocument.removeEvent("ondblclick", mouseEventCallback);
theDocument.detachEvent("onmouseup", mouseEventCallback);
theDocument.detachEvent("onmousedown", mouseEventCallback);
theDocument.detachEvent("onmousemove", mouseEventCallback);
theDocument.detachEvent("ondblclick", mouseEventCallback);
theDocument.removeEvent("onkeyup", keyEventCallback);
theDocument.removeEvent("onkeydown", keyEventCallback);
theDocument.removeEvent("onkeypress", keyEventCallback);
theDocument.detachEvent("onkeyup", keyEventCallback);
theDocument.detachEvent("onkeydown", keyEventCallback);
theDocument.detachEvent("onkeypress", keyEventCallback);
_DOMWindow.removeEvent("onresize", resizeEventCallback);
_DOMWindow.detachEvent("onresize", resizeEventCallback);
_DOMWindow.onmousewheel = NULL;
theDocument.onmousewheel = NULL;
theDocument.body.ondrag = NULL;
theDocument.body.onselectstart = NULL;
_DOMBodyElement.ondrag = NULL;
_DOMBodyElement.onselectstart = NULL;
//_DOMWindow.removeEvent("beforeunload", this);
[PlatformWindows removeObject:self];
self._DOMWindow = nil;
}, NO);
}
}
+ (CPSet)visiblePlatformWindows
{
return PlatformWindows;
}
- (void)orderFront:(id)aSender
{
if (_DOMWindow)
@@ -332,6 +436,8 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
_DOMWindow = window.open("", "_blank", "menubar=no,location=no,resizable=yes,scrollbars=no,status=no,left=" + _CGRectGetMinX(_contentRect) + ",top=" + _CGRectGetMinY(_contentRect) + ",width=" + _CGRectGetWidth(_contentRect) + ",height=" + _CGRectGetHeight(_contentRect));
[PlatformWindows addObject:self];
// FIXME: cpSetFrame?
_DOMWindow.document.write("<html><head></head><body style = 'background-color:transparent;'></body></html>");
_DOMWindow.document.close();
@@ -346,6 +452,8 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
}
[self registerDOMWindow];
_DOMBodyElement.style.cursor = [[CPCursor currentCursor] _cssString];
}
- (void)orderOut:(id)aSender
@@ -378,17 +486,25 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
DOMDragElement.style.left = -_CGRectGetWidth(draggedWindowFrame) + "px";
DOMDragElement.style.top = -_CGRectGetHeight(draggedWindowFrame) + "px";
document.getElementsByTagName("body")[0].appendChild(DOMDragElement);
_DOMBodyElement.appendChild(DOMDragElement);
var draggingOffset = [dragServer draggingOffset];
aDOMEvent.dataTransfer.setDragImage(DOMDragElement, draggingOffset.width, draggingOffset.height);
aDOMEvent.dataTransfer.effectAllowed = "all";
[dragServer draggingStartedInPlatformWindow:self globalLocation:[CPPlatform isBrowser] ? location : _CGPointMake(aDOMEvent.screenX, aDOMEvent.screenY)];
}
else if (type === "drag")
[dragServer draggingSourceUpdatedWithGlobalLocation:[CPPlatform isBrowser] ? location : _CGPointMake(aDOMEvent.screenX, aDOMEvent.screenY)];
{
var y = aDOMEvent.screenY;
if (CPFeatureIsCompatible(CPHTML5DragAndDropSourceYOffBy1))
y -= 1;
[dragServer draggingSourceUpdatedWithGlobalLocation:[CPPlatform isBrowser] ? location : _CGPointMake(aDOMEvent.screenX, y)];
}
else if (type === "dragover" || type === "dragleave")
{
@@ -411,7 +527,20 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
}
else if (type === "dragend")
[dragServer draggingEndedInPlatformWindow:self globalLocation:[CPPlatform isBrowser] ? location : _CGPointMake(aDOMEvent.screenX, aDOMEvent.screenY)];
{
var dropEffect = aDOMEvent.dataTransfer.dropEffect;
if (dropEffect === "move")
dragOperation = CPDragOperationMove;
else if (dropEffect === "copy")
dragOperation = CPDragOperationCopy;
else if (dropEffect === "link")
dragOperation = CPDragOperationLink;
else
dragOperation = CPDragOperationNone;
[dragServer draggingEndedInPlatformWindow:self globalLocation:[CPPlatform isBrowser] ? location : _CGPointMake(aDOMEvent.screenX, aDOMEvent.screenY) operation:dragOperation];
}
else //if (type === "drop")
{
@@ -438,72 +567,93 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
(aDOMEvent.ctrlKey ? CPControlKeyMask : 0) |
(aDOMEvent.altKey ? CPAlternateKeyMask : 0) |
(aDOMEvent.metaKey ? CPCommandKeyMask : 0);
if (ExcludedDOMElements[sourceElement.tagName] && sourceElement != _DOMFocusElement && sourceElement != _DOMPasteboardElement)
return;
//We want to stop propagation if this is a command key AND this character or keycode has been added to our blacklist
StopDOMEventPropagation = !(modifierFlags & (CPControlKeyMask | CPCommandKeyMask)) ||
//We want to stop propagation if this is a command key AND this character or keycode has been added to our blacklist
StopDOMEventPropagation = !!(!(modifierFlags & (CPControlKeyMask | CPCommandKeyMask)) ||
CharacterKeysToPrevent[String.fromCharCode(aDOMEvent.keyCode || aDOMEvent.charCode).toLowerCase()] ||
KeyCodesToPrevent[aDOMEvent.keyCode];
KeyCodesToPrevent[aDOMEvent.keyCode]);
var isNativePasteEvent = NO,
isNativeCopyOrCutEvent = NO,
overrideCharacters = nil;
switch (aDOMEvent.type)
{
case "keydown": // Grab and store the keycode now since it is correct and consistent at this point.
_keyCode = aDOMEvent.keyCode;
if (aDOMEvent.keyCode.keyCode in MozKeyCodeToKeyCodeMap)
_keyCode = MozKeyCodeToKeyCodeMap[aDOMEvent.keyCode];
else
_keyCode = aDOMEvent.keyCode;
var characters = String.fromCharCode(_keyCode).toLowerCase();
overrideCharacters = modifierFlags & CPShiftKeyMask ? characters.toUpperCase() : characters;
// If this could be a native PASTE event, then we need to further examine it before
// sending a CPEvent. Select our element to see if anything gets pasted in it.
if (characters == "v" && (modifierFlags & CPPlatformActionKeyMask))
overrideCharacters = (modifierFlags & CPShiftKeyMask || _capsLockActive) ? characters.toUpperCase() : characters;
// check for caps lock state
if (_keyCode === CPKeyCodes.CAPS_LOCK)
_capsLockActive = YES;
if (modifierFlags & (CPControlKeyMask | CPCommandKeyMask))
{
_DOMPasteboardElement.select();
_DOMPasteboardElement.value = "";
isNativePasteEvent = YES;
//we are simply going to skip all keypress events that use cmd/ctrl key
//this lets us be consistent in all browsers and send on the keydown
//which means we can cancel the event early enough, but only if sendEvent needs to
var eligibleForCopyPaste = [self _validateCopyCutOrPasteEvent:aDOMEvent flags:modifierFlags];
// If this could be a native PASTE event, then we need to further examine it before
// sending a CPEvent. Select our element to see if anything gets pasted in it.
if (characters === "v" && eligibleForCopyPaste)
{
if (!_ignoreNativePastePreparation)
{
_DOMPasteboardElement.select();
_DOMPasteboardElement.value = "";
}
isNativePasteEvent = YES;
}
// However, of this could be a native COPY event, we need to let the normal event-process take place so it
// can capture our internal Cappuccino pasteboard.
else if ((characters == "c" || characters == "x") && eligibleForCopyPaste)
{
isNativeCopyOrCutEvent = YES;
if (_ignoreNativeCopyOrCutEvent)
break;
}
}
else if (CPKeyCodes.firesKeyPressEvent(_keyCode, _lastKey, aDOMEvent.shiftKey, aDOMEvent.ctrlKey, aDOMEvent.altKey))
{
// this branch is taken by events which fire keydown, keypress, and keyup.
// this is the only time we'll ALLOW character keys to propagate (needed for text fields)
StopDOMEventPropagation = NO;
break;
}
else
{
//this branch is taken by "remedial" key events
// In this state we continue to keypress and send the CPEvent
}
// Normally we return now because we let keypress send the actual CPEvent keyDown event, since we don't have
// a complete set of information yet.
// However, of this could be a native COPY event, we need to let the normal event-process take place so it
// can capture our internal Cappuccino pasteboard.
else if ((characters == "c" || characters == "x") && (modifierFlags & CPPlatformActionKeyMask))
isNativeCopyOrCutEvent = YES;
case "keypress":
// we unconditionally break on keypress events with modifiers,
// because we forced the event to be sent on the keydown
if (aDOMEvent.type === "keypress" && (modifierFlags & (CPControlKeyMask | CPCommandKeyMask)))
break;
// Also, certain browsers (IE and Safari), have broken keyboard supportwhere they don't send keypresses for certain events.
// So, allow the keypress event to handle the event if we are not a browser with broken (remedial) key support...
else if (!CPFeatureIsCompatible(CPJavascriptRemedialKeySupport))
return;
// Or, if this is not one of those special keycodes, and also not a ctrl+event
else if (!KeyCodesWithoutKeyPressEvents[_keyCode] && (_keyCode == CTRL_KEY_CODE || !(modifierFlags & CPControlKeyMask)))
return;
// If this is in fact our broke state, continue to keypress and send the keydown.
case "keypress": // If the source of this event is our pasteboard element, then simply let it continue
// as normal, so that the paste event can successfully complete.
if ((aDOMEvent.target || aDOMEvent.srcElement) == _DOMPasteboardElement)
return;
var keyCode = _keyCode,
charCode = aDOMEvent.keyCode || aDOMEvent.charCode,
isARepeat = (_charCodes[keyCode] != nil);
_lastKey = keyCode;
_charCodes[keyCode] = charCode;
var characters = overrideCharacters || String.fromCharCode(charCode),
charactersIgnoringModifiers = characters.toLowerCase();
// Safari won't send proper capitalization during cmd-key events
if (!overrideCharacters && (modifierFlags & CPCommandKeyMask) && (modifierFlags & CPShiftKeyMask))
if (!overrideCharacters && (modifierFlags & CPCommandKeyMask) && ((modifierFlags & CPShiftKeyMask) || _capsLockActive))
characters = characters.toUpperCase();
event = [CPEvent keyEventWithType:CPKeyDown location:location modifierFlags:modifierFlags
@@ -514,7 +664,6 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
{
_pasteboardKeyDownEvent = event;
window.setNativeTimeout(function () { [self _checkPasteboardElement] }, 0);
return;
}
break;
@@ -522,12 +671,20 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
case "keyup": var keyCode = aDOMEvent.keyCode,
charCode = _charCodes[keyCode];
_keyCode = -1;
_lastKey = -1;
_charCodes[keyCode] = nil;
_ignoreNativeCopyOrCutEvent = NO;
_ignoreNativePastePreparation = NO;
// check for caps lock state
if (keyCode === CPKeyCodes.CAPS_LOCK)
_capsLockActive = NO;
var characters = String.fromCharCode(charCode),
charactersIgnoringModifiers = characters.toLowerCase();
if (!(modifierFlags & CPShiftKeyMask))
if (!(modifierFlags & CPShiftKeyMask) && (modifierFlags & CPCommandKeyMask) && !_capsLockActive)
characters = charactersIgnoringModifiers;
event = [CPEvent keyEventWithType:CPKeyUp location:location modifierFlags:modifierFlags
@@ -535,40 +692,126 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
characters:characters charactersIgnoringModifiers:charactersIgnoringModifiers isARepeat:NO keyCode:keyCode];
break;
}
if (event)
if (event && !isNativePasteEvent)
{
event._DOMEvent = aDOMEvent;
[CPApp sendEvent:event];
if (isNativeCopyOrCutEvent)
{
var pasteboard = [CPPasteboard generalPasteboard],
types = [pasteboard types];
// If this is a native copy event, then check if the pasteboard has anything in it.
if (types.length)
{
if ([types indexOfObjectIdenticalTo:CPStringPboardType] != CPNotFound)
_DOMPasteboardElement.value = [pasteboard stringForType:CPStringPboardType];
else
_DOMPasteboardElement.value = [pasteboard _generateStateUID];
_DOMPasteboardElement.select();
window.setNativeTimeout(function() { [self _clearPasteboardElement]; }, 0);
}
return;
[self _primePasteboardElement];
}
}
if (StopDOMEventPropagation)
CPDOMEventStop(aDOMEvent, self);
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
}
- (void)copyEvent:(DOMEvent)aDOMEvent
{
if ([self _validateCopyCutOrPasteEvent:aDOMEvent flags:CPPlatformActionKeyMask] && !_ignoreNativeCopyOrCutEvent)
{
//we have to send out a fake copy or cut event so that we can force the copy/cut mechanisms to take place
var cut = aDOMEvent.type === "beforecut",
keyCode = cut ? CPKeyCodes.X : CPKeyCodes.C,
characters = cut ? "x" : "c",
timestamp = aDOMEvent.timeStamp ? aDOMEvent.timeStamp : new Date(),
windowNumber = [[CPApp keyWindow] windowNumber],
modifierFlags = CPPlatformActionKeyMask;
event = [CPEvent keyEventWithType:CPKeyDown location:location modifierFlags:modifierFlags
timestamp:timestamp windowNumber:windowNumber context:nil
characters:characters charactersIgnoringModifiers:characters isARepeat:NO keyCode:keyCode];
event._DOMEvent = aDOMEvent;
[CPApp sendEvent:event];
[self _primePasteboardElement];
//then we have to IGNORE the real keyboard event to prevent a double copy
//safari also sends the beforecopy event twice, so we additionally check here and prevent two events
_ignoreNativeCopyOrCutEvent = YES;
}
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
}
- (void)pasteEvent:(DOMEvent)aDOMEvent
{
if ([self _validateCopyCutOrPasteEvent:aDOMEvent flags:CPPlatformActionKeyMask])
{
_DOMPasteboardElement.focus();
_DOMPasteboardElement.select();
_DOMPasteboardElement.value = "";
_ignoreNativePastePreparation = YES;
}
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
}
- (void)_validateCopyCutOrPasteEvent:(DOMEvent)aDOMEvent flags:(unsigned)modifierFlags
{
return (
((aDOMEvent.target || aDOMEvent.srcElement).nodeName.toUpperCase() !== "INPUT" &&
(aDOMEvent.target || aDOMEvent.srcElement).nodeName.toUpperCase() !== "TEXTAREA"
) || aDOMEvent.target === _DOMPasteboardElement
) &&
(modifierFlags & CPPlatformActionKeyMask);
}
- (void)_primePasteboardElement
{
var pasteboard = [CPPasteboard generalPasteboard],
types = [pasteboard types];
if (types.length)
{
if ([types indexOfObjectIdenticalTo:CPStringPboardType] != CPNotFound)
_DOMPasteboardElement.value = [pasteboard stringForType:CPStringPboardType];
else
_DOMPasteboardElement.value = [pasteboard _generateStateUID];
_DOMPasteboardElement.focus();
_DOMPasteboardElement.select();
window.setNativeTimeout(function() { [self _clearPasteboardElement]; }, 0);
}
}
- (void)_checkPasteboardElement
{
var value = _DOMPasteboardElement.value;
if ([value length])
{
var pasteboard = [CPPasteboard generalPasteboard];
if ([pasteboard _stateUID] != value)
{
[pasteboard declareTypes:[CPStringPboardType] owner:self];
[pasteboard setString:value forType:CPStringPboardType];
}
}
[self _clearPasteboardElement];
[CPApp sendEvent:_pasteboardKeyDownEvent];
_pasteboardKeyDownEvent = nil;
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
}
- (void)_clearPasteboardElement
{
_DOMPasteboardElement.value = "";
_DOMPasteboardElement.blur();
}
- (void)scrollEvent:(DOMEvent)aDOMEvent
@@ -652,7 +895,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
if (StopDOMEventPropagation)
CPDOMEventStop(aDOMEvent, self);
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
}
@@ -662,6 +905,9 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
// We should pay attention to mouse down and mouse up in conjunction with this.
//window.liveResize = YES;
if ([CPPlatform isBrowser])
[CPApp._activeMenu cancelTracking];
var oldSize = [self contentRect].size;
[self updateFromNativeContentRect];
@@ -796,7 +1042,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
else if (type === "mousedown")
{
if (ExcludedDOMElements[sourceElement.tagName] && sourceElement != _DOMFocusElement)
if (sourceElement.tagName === "INPUT" && sourceElement != _DOMFocusElement)
{
if ([CPPlatform supportsDragAndDrop])
{
@@ -901,6 +1147,8 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
- (void)order:(CPWindowOrderingMode)aPlace window:(CPWindow)aWindow relativeTo:(CPWindow)otherWindow
{
[CPPlatform initializeScreenIfNecessary];
// Grab the appropriate level for the layer, and create it if
// necessary (if we are not simply removing the window).
var layer = [self layerAtLevel:[aWindow level] create:aPlace != CPWindowOut];
@@ -979,8 +1227,16 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
StopDOMEventPropagation = !aFlag;
}
- (BOOL)_willPropagateCurrentDOMEvent
{
return !StopDOMEventPropagation;
}
- (CPWindow)hitTest:(CPPoint)location
{if (self._only) return self._only;
{
if (self._only)
return self._only;
var levels = _windowLevels,
layers = _windowLayers,
levelCount = levels.length,
@@ -1003,37 +1259,6 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
return theWindow;
}
- (void)_checkPasteboardElement
{
var value = _DOMPasteboardElement.value;
if ([value length])
{
var pasteboard = [CPPasteboard generalPasteboard];
if ([pasteboard _stateUID] != value)
{
[pasteboard declareTypes:[CPStringPboardType] owner:self];
[pasteboard setString:value forType:CPStringPboardType];
}
}
[self _clearPasteboardElement];
[CPApp sendEvent:_pasteboardKeyDownEvent];
_pasteboardKeyDownEvent = nil;
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
}
- (void)_clearPasteboardElement
{
_DOMPasteboardElement.value = "";
_DOMPasteboardElement.blur();
}
/*!
When using command (mac) or control (windows), keys are propagated to the browser by default.
To prevent a character key from propagating (to prevent its default action, and instead use it
@@ -0,0 +1,231 @@
/*
* CPPlatformWindow+DOMKeys.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
*/
// Keycodes taken and modified from Google Closure, available under Apache 2 License
CPKeyCodes = {
BACKSPACE: 8,
TAB: 9,
NUM_CENTER: 12,
ENTER: 13,
SHIFT: 16,
CTRL: 17,
ALT: 18,
PAUSE: 19,
CAPS_LOCK: 20,
ESC: 27,
SPACE: 32,
PAGE_UP: 33, // also NUM_NORTH_EAST
PAGE_DOWN: 34, // also NUM_SOUTH_EAST
END: 35, // also NUM_SOUTH_WEST
HOME: 36, // also NUM_NORTH_WEST
LEFT: 37, // also NUM_WEST
UP: 38, // also NUM_NORTH
RIGHT: 39, // also NUM_EAST
DOWN: 40, // also NUM_SOUTH
PRINT_SCREEN: 44,
INSERT: 45, // also NUM_INSERT
DELETE: 46, // also NUM_DELETE
ZERO: 48,
ONE: 49,
TWO: 50,
THREE: 51,
FOUR: 52,
FIVE: 53,
SIX: 54,
SEVEN: 55,
EIGHT: 56,
NINE: 57,
QUESTION_MARK: 63, // needs localization
A: 65,
B: 66,
C: 67,
D: 68,
E: 69,
F: 70,
G: 71,
H: 72,
I: 73,
J: 74,
K: 75,
L: 76,
M: 77,
N: 78,
O: 79,
P: 80,
Q: 81,
R: 82,
S: 83,
T: 84,
U: 85,
V: 86,
W: 87,
X: 88,
Y: 89,
Z: 90,
META: 91,
CONTEXT_MENU: 93,
NUM_ZERO: 96,
NUM_ONE: 97,
NUM_TWO: 98,
NUM_THREE: 99,
NUM_FOUR: 100,
NUM_FIVE: 101,
NUM_SIX: 102,
NUM_SEVEN: 103,
NUM_EIGHT: 104,
NUM_NINE: 105,
NUM_MULTIPLY: 106,
NUM_PLUS: 107,
NUM_MINUS: 109,
NUM_PERIOD: 110,
NUM_DIVISION: 111,
F1: 112,
F2: 113,
F3: 114,
F4: 115,
F5: 116,
F6: 117,
F7: 118,
F8: 119,
F9: 120,
F10: 121,
F11: 122,
F12: 123,
NUMLOCK: 144,
SEMICOLON: 186, // needs localization
DASH: 189, // needs localization
EQUALS: 187, // needs localization
COMMA: 188, // needs localization
PERIOD: 190, // needs localization
SLASH: 191, // needs localization
APOSTROPHE: 192, // needs localization
SINGLE_QUOTE: 222, // needs localization
OPEN_SQUARE_BRACKET: 219, // needs localization
BACKSLASH: 220, // needs localization
CLOSE_SQUARE_BRACKET: 221, // needs localization
WIN_KEY: 224,
MAC_FF_META: 224, // Firefox (Gecko) fires this for the meta key instead of 91
WIN_IME: 229
};
/*!
* Returns true if the key fires a keypress event in the current browser.
*
* Accoridng to MSDN [1] IE only fires keypress events for the following keys:
* - Letters: A - Z (uppercase and lowercase)
* - Numerals: 0 - 9
* - Symbols: ! @ # $ % ^ & * ( ) _ - + = < [ ] { } , . / ? \ | ' ` " ~
* - System: ESC, SPACEBAR, ENTER
*
* That's not entirely correct though, for instance there's no distinction
* between upper and lower case letters.
*
* [1] http://msdn2.microsoft.com/en-us/library/ms536939(VS.85).aspx)
*
* Safari is similar to IE, but does not fire keypress for ESC.
*
* Additionally, IE6 does not fire keydown or keypress events for letters when
* the control or alt keys are held down and the shift key is not. IE7 does
* fire keydown in these cases, though, but not keypress.
*
* @param keyCode A key code.
* @param opt_heldKeyCode Key code of a currently-held key.
* @param opt_shiftKey Whether the shift key is held down.
* @param opt_ctrlKey Whether the control key is held down.
* @param opt_altKey Whether the alt key is held down.
* @return Returns YES if it's a key that fires a keypress event.
*/
CPKeyCodes.firesKeyPressEvent = function(keyCode, opt_heldKeyCode, opt_shiftKey, opt_ctrlKey, opt_altKey)
{
if (!CPFeatureIsCompatible(CPJavascriptRemedialKeySupport))
return true;
if (CPBrowserIsOperatingSystem(CPMacOperatingSystem) && opt_altKey)
return CPKeyCodes.isCharacterKey(keyCode);
// Alt but not AltGr which is represented as Alt+Ctrl.
if (opt_altKey && !opt_ctrlKey)
return false;
// Saves Ctrl or Alt + key for IE7, which won't fire keypress.
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine) && !opt_shiftKey && (opt_ctrlKey || opt_altKey))
return false;
// When Ctrl+<somekey> is held in IE, it only fires a keypress once, but it
// continues to fire keydown events as the event repeats.
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine) && opt_ctrlKey && opt_heldKeyCode == keyCode)
return false;
switch (keyCode)
{
case CPKeyCodes.ENTER: return true;
case CPKeyCodes.ESC: return !CPBrowserIsEngine(CPWebKitBrowserEngine);
}
return CPKeyCodes.isCharacterKey(keyCode);
};
/*!
* Test for whether or not a given keyCode represents a character key.
*
* @param keyCode A key code.
* @return Returns YES if the keyCode is a character key.
*/
CPKeyCodes.isCharacterKey = function(keyCode)
{
if (keyCode >= CPKeyCodes.ZERO && keyCode <= CPKeyCodes.NINE)
return true;
if (keyCode >= CPKeyCodes.NUM_ZERO && keyCode <= CPKeyCodes.NUM_MULTIPLY)
return true;
if (keyCode >= CPKeyCodes.A && keyCode <= CPKeyCodes.Z)
return true;
switch (keyCode)
{
case CPKeyCodes.SPACE:
case CPKeyCodes.QUESTION_MARK:
case CPKeyCodes.NUM_PLUS:
case CPKeyCodes.NUM_MINUS:
case CPKeyCodes.NUM_PERIOD:
case CPKeyCodes.NUM_DIVISION:
case CPKeyCodes.SEMICOLON:
case CPKeyCodes.DASH:
case CPKeyCodes.EQUALS:
case CPKeyCodes.COMMA:
case CPKeyCodes.PERIOD:
case CPKeyCodes.SLASH:
case CPKeyCodes.APOSTROPHE:
case CPKeyCodes.SINGLE_QUOTE:
case CPKeyCodes.OPEN_SQUARE_BRACKET:
case CPKeyCodes.BACKSLASH:
case CPKeyCodes.CLOSE_SQUARE_BRACKET:
return true;
default:
return false;
}
}
-79
View File
@@ -1,79 +0,0 @@
#!/usr/bin/env ruby
require 'rake'
require '../common'
require 'objective-j'
require 'objective-j/bundletask'
$BUILD_PATH = File.join($BUILD_DIR, $CONFIGURATION, 'AppKit')
$ENVIRONMENT_PRODUCT = File.join($ENVIRONMENT_FRAMEWORKS_DIR, 'AppKit')
$THEME_PRODUCT = File.join($BUILD_PATH, 'Resources', 'Aristo.blend')
$ENVIRONMENT_THEME_PRODUCT = File.join($ENVIRONMENT_PRODUCT, 'Resources', 'Aristo.blend')
AppKitFiles = FileList['**/*.j'].exclude('CoreGraphics/CGContextCanvas.j', 'CoreGraphics/CGContextVML.j', 'Themes/**', 'Tools/**')
ObjectiveJ::BundleTask.new(:AppKit) do |t|
t.name = 'AppKit'
t.identifier = 'com.280n.AppKit'
t.version = '0.7.1'
t.author = '280 North, Inc.'
t.email = 'feedback @nospam@ 280north.com'
t.summary = 'AppKit classes for Cappuccino'
t.sources = AppKitFiles
t.resources = FileList['Resources/*']
t.license = ObjectiveJ::License::LGPL_v2_1
t.build_path = $BUILD_PATH
t.flag = '-DDEBUG -g' if $CONFIGURATION == 'Debug'
t.flag = '-O' if $CONFIGURATION == 'Release'
t.platforms = [ObjectiveJ::Platform::Browser, ObjectiveJ::Platform::Rhino]
t.type = ObjectiveJ::Bundle::Type::Framework
end
# It would be nice to just have ENVIRONMENT_PRODUCT depend on THEME_PRODUCT,
# but this would be a circular dependency because THEME_PRODUCT needs
# ENVIRONMENT_PRODUCT up-to-date since it runs an objj application that uses
# AppKit.
file_d $ENVIRONMENT_PRODUCT => [:AppKit] do
cp_r(File.join($BUILD_PATH, '.'), $ENVIRONMENT_PRODUCT)
end
file_d $ENVIRONMENT_THEME_PRODUCT => $THEME_PRODUCT do
cp_r(File.join($THEME_PRODUCT, '.'), $ENVIRONMENT_THEME_PRODUCT)
end
ThemeFiles = FileList['Themes/Aristo/*']
file_d $THEME_PRODUCT => ThemeFiles << $ENVIRONMENT_PRODUCT do
File.popen("blend -d Themes/Aristo/ThemeDescriptors.j -o #{$THEME_PRODUCT} -R Themes/Aristo/Resources") do |blend|
blend.sync = true
while str = blend.gets
puts str
end
end
rake abort if ($? != 0)
end
task :build => [:build_subprojects, :AppKit, $ENVIRONMENT_PRODUCT, $THEME_PRODUCT, $ENVIRONMENT_THEME_PRODUCT]
task :clean => :clean_suprojects
task :clobber => :clobber_subprojects
subprojects = %w{Tools}
task :build_subprojects do
subrake(subprojects, :build)
end
task :clean_suprojects do
subrake(subprojects, :clean)
end
task :clobber_subprojects do
subrake(subprojects, :clobber)
end
CLOBBER.include($ENVIRONMENT_PRODUCT)
+1
View File
@@ -0,0 +1 @@
280NPLIST;1.0;D;K;4;$topD;K;18;CPCibObjectDataKeyD;K;6;CP$UIDd;1;2E;K;21;CPCibObjectRecordsKeyD;K;6;CP$UIDd;1;4E;E;K;8;$objectsA;S;5;$nullD;K;10;$classnameS;16;_CPCibObjectDataK;8;$classesA;S;16;_CPCibObjectDataS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;1;1E;K;28;_CPCibObjectDataNamesKeysKeyD;K;6;CP$UIDd;1;5E;K;30;_CPCibObjectDataNamesValuesKeyD;K;6;CP$UIDd;1;6E;K;30;_CPCibObjectDataClassesKeysKeyD;K;6;CP$UIDd;1;7E;K;32;_CPCibObjectDataClassesValuesKeyD;K;6;CP$UIDd;1;8E;K;30;_CPCibObjectDataConnectionsKeyD;K;6;CP$UIDd;1;9E;K;28;_CPCibObjectDataFrameworkKeyD;K;6;CP$UIDd;2;10E;K;26;_CPCibObjectDataNextOidKeyD;K;6;CP$UIDd;2;11E;K;30;_CPCibObjectDataObjectsKeysKeyD;K;6;CP$UIDd;2;12E;K;32;_CPCibObjectDataObjectsValuesKeyD;K;6;CP$UIDd;2;13E;K;26;_CPCibObjectDataOidKeysKeyD;K;6;CP$UIDd;2;14E;K;28;_CPCibObjectDataOidValuesKeyD;K;6;CP$UIDd;2;15E;K;28;_CPCibObjectDataFileOwnerKeyD;K;6;CP$UIDd;2;17E;K;33;_CPCibObjectDataVisibleWindowsKeyD;K;6;CP$UIDd;2;19E;E;D;K;10;$classnameS;7;CPArrayK;8;$classesA;S;7;CPArrayS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;21E;D;K;6;CP$UIDd;2;22E;D;K;6;CP$UIDd;2;23E;D;K;6;CP$UIDd;2;24E;D;K;6;CP$UIDd;2;25E;D;K;6;CP$UIDd;2;26E;D;K;6;CP$UIDd;2;27E;D;K;6;CP$UIDd;2;28E;D;K;6;CP$UIDd;2;29E;D;K;6;CP$UIDd;2;30E;D;K;6;CP$UIDd;2;31E;D;K;6;CP$UIDd;2;32E;D;K;6;CP$UIDd;2;33E;D;K;6;CP$UIDd;2;21E;D;K;6;CP$UIDd;2;34E;D;K;6;CP$UIDd;2;35E;D;K;6;CP$UIDd;2;36E;D;K;6;CP$UIDd;2;37E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;17E;D;K;6;CP$UIDd;2;39E;D;K;6;CP$UIDd;2;40E;D;K;6;CP$UIDd;2;42E;D;K;6;CP$UIDd;2;44E;D;K;6;CP$UIDd;2;46E;D;K;6;CP$UIDd;2;47E;D;K;6;CP$UIDd;2;48E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;49E;D;K;6;CP$UIDd;2;50E;D;K;6;CP$UIDd;2;51E;D;K;6;CP$UIDd;2;52E;D;K;6;CP$UIDd;2;53E;D;K;6;CP$UIDd;2;54E;D;K;6;CP$UIDd;2;54E;D;K;6;CP$UIDd;2;54E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;56E;E;E;S;16;IBCocoaFrameworkd;3;461D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;39E;D;K;6;CP$UIDd;2;40E;D;K;6;CP$UIDd;2;42E;D;K;6;CP$UIDd;2;44E;D;K;6;CP$UIDd;2;46E;D;K;6;CP$UIDd;2;47E;D;K;6;CP$UIDd;2;48E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;D;K;6;CP$UIDd;2;17E;D;K;6;CP$UIDd;2;17E;D;K;6;CP$UIDd;2;39E;D;K;6;CP$UIDd;2;42E;D;K;6;CP$UIDd;2;42E;D;K;6;CP$UIDd;2;42E;D;K;6;CP$UIDd;2;42E;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;6;$classD;K;6;CP$UIDd;1;3E;K;10;CP.objectsA;E;E;D;K;10;$classnameS;18;_CPCibCustomObjectK;8;$classesA;S;18;_CPCibCustomObjectS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;16E;K;27;_CPCibCustomObjectClassNameD;K;6;CP$UIDd;2;57E;E;D;K;10;$classnameS;5;CPSetK;8;$classesA;S;5;CPSetS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;18E;K;15;CPSetObjectsKeyD;K;6;CP$UIDd;2;58E;E;D;K;10;$classnameS;15;CibObjectRecordK;8;$classesA;S;15;CibObjectRecordS;8;CPObjectE;E;D;K;6;$classD;K;6;CP$UIDd;2;20E;K;24;CibObjectRecordParentKeyD;K;6;CP$UIDd;1;0E;K;26;CibObjectRecordChildrenKeyD;K;6;CP$UIDd;2;59E;K;24;CibObjectRecordObjectKeyD;K;6;CP$UIDd;2;60E;K;23;CibObjectRecordLabelKeyD;K;6;CP$UIDd;2;61E;E;D;K;6;$classD;K;6;CP$UIDd;2;20E;K;24;CibObjectRecordParentKeyD;K;6;CP$UIDd;1;0E;K;26;CibObjectRecordChildrenKeyD;K;6;CP$UIDd;2;62E;K;24;CibObjectRecordObjectKeyD;K;6;CP$UIDd;2;63E;K;23;CibObjectRecordLabelKeyD;K;6;CP$UIDd;1;0E;E;D;K;6;$classD;K;6;CP$UIDd;2;20E;K;24;CibObjectRecordParentKeyD;K;6;CP$UIDd;2;42E;K;26;CibObjectRecordChildrenKeyD;K;6;CP$UIDd;2;64E;K;24;CibObjectRecordObjectKeyD;K;6;CP$UIDd;2;48E;K;23;CibObjectRecordLabelKeyD;K;6;CP$UIDd;2;54E;E;D;K;6;$classD;K;6;CP$UIDd;2;20E;K;24;CibObjectRecordParentKeyD;K;6;CP$UIDd;1;0E;K;26;CibObjectRecordChildrenKeyD;K;6;CP$UIDd;2;65E;K;24;CibObjectRecordObjectKeyD;K;6;CP$UIDd;2;66E;K;23;CibObjectRecordLabelKeyD;K;6;CP$UIDd;1;0E;E;D;K;6;$classD;K;6;CP$UIDd;2;20E;K;24;CibObjectRecordParentKeyD;K;6;CP$UIDd;1;0E;K;26;CibObjectRecordChildrenKeyD;K;6;CP$UIDd;2;67E;K;24;CibObjectRecordObjectKeyD;K;6;CP$UIDd;2;68E;K;23;CibObjectRecordLabelKeyD;K;6;CP$UIDd;1;0E;E;D;K;6;$classD;K;6;CP$UIDd;2;20E;K;24;CibObjectRecordParentKeyD;K;6;CP$UIDd;2;42E;K;26;CibObjectRecordChildrenKeyD;K;6;CP$UIDd;2;69E;K;24;CibObjectRecordObjectKeyD;K;6;CP$UIDd;2;47E;K;23;CibObjectRecordLabelKeyD;K;6;CP$UIDd;2;54E;E;D;K;6;$classD;K;6;CP$UIDd;2;20E;K;24;CibObjectRecordParentKeyD;K;6;CP$UIDd;1;0E;K;26;CibObjectRecordChildrenKeyD;K;6;CP$UIDd;2;70E;K;24;CibObjectRecordObjectKeyD;K;6;CP$UIDd;2;71E;K;23;CibObjectRecordLabelKeyD;K;6;CP$UIDd;1;0E;E;D;K;6;$classD;K;6;CP$UIDd;2;20E;K;24;CibObjectRecordParentKeyD;K;6;CP$UIDd;1;0E;K;26;CibObjectRecordChildrenKeyD;K;6;CP$UIDd;2;72E;K;24;CibObjectRecordObjectKeyD;K;6;CP$UIDd;2;73E;K;23;CibObjectRecordLabelKeyD;K;6;CP$UIDd;1;0E;E;D;K;6;$classD;K;6;CP$UIDd;2;20E;K;24;CibObjectRecordParentKeyD;K;6;CP$UIDd;2;42E;K;26;CibObjectRecordChildrenKeyD;K;6;CP$UIDd;2;74E;K;24;CibObjectRecordObjectKeyD;K;6;CP$UIDd;2;46E;K;23;CibObjectRecoLine truncated
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

+18
View File
@@ -0,0 +1,18 @@
<html>
<head>
</head>
<body>
<div>Test custom cursors with .cur images.</div>
<div style="width: 20px; height: 20px; margin: 10px; background: #ddd; cursor: url(disappearingItemCursor.cur), default">disappearingItemCursor</div>
<div style="width: 20px; height: 20px; margin: 10px; background: #ddd; cursor: url(closedHandCursor.cur), default">closedHandCursor</div>
<div style="width: 20px; height: 20px; margin: 10px; background: #ddd; cursor: url(contextMenuCursor.cur), default">contextMenuCursor</div>
<div style="width: 20px; height: 20px; margin: 10px; background: #ddd; cursor: url(dragCopyCursor.cur), default">dragCopyCursor</div>
<div style="width: 20px; height: 20px; margin: 10px; background: #ddd; cursor: url(dragLinkCursor.cur), default">dragLinkCursor</div>
<div style="width: 20px; height: 20px; margin: 10px; background: #ddd; cursor: url(openHandCursor.cur), default">openHandCursor</div>
<div style="width: 20px; height: 20px; margin: 10px; background: #ddd; cursor: url(resizeDownCursor.cur), default">resizeDownCursor</div>
<div style="width: 20px; height: 20px; margin: 10px; background: #ddd; cursor: url(resizeLeftCursor.cur), default">resizeLeftCursor</div>
<div style="width: 20px; height: 20px; margin: 10px; background: #ddd; cursor: url(resizeRightCursor.cur), default">resizeRightCursor</div>
<div style="width: 20px; height: 20px; margin: 10px; background: #ddd; cursor: url(resizeUpCursor.cur), default">resizeUpCursor</div>
</body>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 259 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 B

Loaded 100 of 463 files, more files were not shown because too many files have changed in this diff. Show more