Compare commits

...
108 Commits
Author SHA1 Message Date
Ross Boucher 1db2e0282a Typo in the new platform window code for cursors 2009-12-04 18:41:57 -08:00
Ross Boucher 2351f73c76 Make the new cursor stuff work across platform windows 2009-12-04 18:07:53 -08:00
Ross Boucher 20a38c3aac Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2009-12-04 16:49:22 -08:00
Ross Boucher bca25d0f5f Fix for windows being super floaty 2009-12-04 16:48:43 -08:00
Ross Boucher b26853e4d7 Fix for a path issue with non flattened source files in jake 2009-12-04 16:47:50 -08:00
Francisco Ryan Tolmasky I 39049f82fc Fix for nib2cib incorrectly requiring at least 2 arguments.
Reviewed by me.
2009-12-04 15:02:59 -08:00
Francisco Ryan Tolmasky I a30250f758 Merge branch 'menus' into jake
Closes #73.
Closes #75.
Closes #121.
Closes #130.
Closes #197.

Reviewed by me.
2009-12-04 12:39:49 -08:00
Francisco Ryan Tolmasky I 629737cda3 Apply positioning heuristics to +[CPMenu popUpMenu...] as well.
Reviewed by me.
2009-12-04 12:12:53 -08:00
Francisco Ryan Tolmasky I ec41411675 Fix for disabled menu item shadows, and slighlty better positioning for pop up menus.
Reviewed by me.
2009-12-04 11:55:01 -08:00
Francisco Ryan Tolmasky I becdf2bfeb Fix for menus not having the proper font.
Reviewed by me.
2009-12-04 11:35:40 -08:00
Ross Boucher 1e723945f8 Should have removed rather than commented out these lines 2009-12-04 11:25:20 -08:00
Ross Boucher dfb7599bb6 Remove the cursor hack from CPImageAndTextView, set the cursor globally to the default in CPApplication 2009-12-04 11:22:57 -08:00
Ross Boucher e1d3363ad9 A couple fixes to the CPCursor stuff 2009-12-04 11:12:13 -08:00
cacaodevandRoss Boucher c36c750c5d CPCursor implementation tested in WebKit/FF/IE/Opera. See comments in the file for more details. 2009-12-04 11:02:57 -08:00
Francisco Ryan Tolmasky I c7581c0847 Merge branch 'jake' into menus
Conflicts:
	AppKit/CPMenu.j
2009-12-03 22:50:13 -08:00
Ross Boucher 936d65291f Temporary fix until Francisco merges in the menu branch. 2009-12-03 19:31:52 -08:00
Francisco Ryan Tolmasky I a64030ad93 Merge branch 'jake' into menus 2009-12-03 19:25:38 -08:00
cacaodevandRoss Boucher 01d60ad4e9 CPSearchField changes from issue #194 2009-12-03 19:24:43 -08:00
Francisco Ryan Tolmasky I 06b64c6a87 Fix for a few edge cases, and added showsStateColumn support to nib2cib.
Reviewed by me.
2009-12-03 19:24:03 -08:00
Francisco Ryan Tolmasky I 0eff4e2bc0 Fix for moving to a base menu resetting the child menu.
Reviewed by me.
2009-12-03 17:58:49 -08:00
Ross Boucher 44d6139db2 Fix for some resizing issues in CPWebView. 2009-12-03 17:39:44 -08:00
Francisco Ryan Tolmasky I 506e3004b7 Merge branch 'jake' into menus 2009-12-03 17:02:02 -08:00
Francisco Ryan Tolmasky I 9ce4c7a468 Don't highlight items while scrolling.
Reviewed by me.
2009-12-03 16:59:10 -08:00
Ross Boucher 2fc724e469 Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2009-12-03 16:29:46 -08:00
Ross Boucher afb69a7f03 Set the created window to not be at 0,0. We need real cascading support. 2009-12-03 16:29:08 -08:00
Ross Boucher cd2dd9f12d Remove dead variables 2009-12-03 16:28:56 -08:00
Francisco Ryan Tolmasky I 29963f74d6 Made menu positioning smarter.
Reviewed by me.
2009-12-03 16:24:35 -08:00
Francisco Ryan Tolmasky I 565a017ebd Merge branch 'jake' into menus 2009-12-03 11:21:35 -08:00
Derek HammerandFrancisco Ryan Tolmasky I 0b85847524 Adding reset to CPAppBootstrapper so that application can be restarted programmatically 2009-12-03 11:20:44 -08:00
Francisco Ryan Tolmasky I cfc46edfb8 Fix for properly positioning pop up button menus.
Reviewed by me.
2009-12-03 01:27:53 -08:00
Francisco Ryan Tolmasky I f250373673 Fix for actions not being sent in submenus.
Reviewed by me.
2009-12-03 00:42:13 -08:00
Francisco Ryan Tolmasky I b0acc13da7 Fix for exceptions when not on a menu item.
Reviewed by me.
2009-12-02 23:08:33 -08:00
Francisco Ryan Tolmasky I d705af8965 Added support for indentation levels in menu items.
Reviewed by me.
2009-12-02 20:41:52 -08:00
Francisco Ryan Tolmasky I a401dfddff Merge branch 'jake' into menus 2009-12-02 20:19:14 -08:00
Francisco Ryan Tolmasky I f579fd925e Fixed state columns not showing up.
Reviewed by me.
2009-12-02 20:18:25 -08:00
Ross Boucher e6d86eaa9b Throw an exception for -1 indexes in CPArray objectAtIndex: 2009-12-02 19:19:18 -08:00
Francisco Ryan Tolmasky I 348e45a5cd Some cleanup and a fix for custom views in menus.
Reviewed by me.
2009-12-02 18:40:47 -08:00
Ross Boucher 2120e9cf2a Potential fix for a drawing issue in IE. 2009-12-02 18:27:18 -08:00
Ross Boucher 3002acc895 Change for the way in which we detect full bridge window close 2009-12-02 18:26:55 -08:00
Francisco Ryan Tolmasky I 0b3c313280 Fix for highlight look in menu bars.
Reviewed by me.
2009-12-02 18:12:50 -08:00
Francisco Ryan Tolmasky I 982ab4b4fa Merge branch 'jake' into menus 2009-12-02 17:18:11 -08:00
Ross Boucher a0ee2f384b Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2009-12-02 17:15:17 -08:00
Ross Boucher 56a739655f A whole bunch of textfield and key event fixes. 2009-12-02 17:14:47 -08:00
Francisco Ryan Tolmasky I 150ee44da0 Added background highlight to menu bar and fixed highligh turning off after stopping tracking in menu bar.
Reviewed by me.
2009-12-02 16:39:38 -08:00
Francisco Ryan Tolmasky I 78795e3167 Preliminary menu bar support.
Reviewed by me.
2009-12-02 15:57:52 -08:00
tlrobinson b0dd3cd818 Fix nib2cib. 2009-12-01 20:02:55 -08:00
Francisco Ryan Tolmasky I ef12ec54d7 Added new view for menu bar items.
Reviewed by me.
2009-12-01 19:19:24 -08:00
Francisco Ryan Tolmasky I 495b774965 A bit of cleanup.
Reviewed by me.
2009-12-01 17:49:15 -08:00
Ross Boucher 1381bb5c54 Prevent CPViewController from loading the same cibs lots of times. I think the solution should be made generic and put into CPCib though. Closes #348. 2009-12-01 09:25:49 -08:00
Ross Boucher f1d4794dd1 Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2009-12-01 09:14:45 -08:00
Thomas BalthazarandRoss Boucher d58473c270 Fix for GHissue #348 : CPViewController should cache the cib 2009-12-01 09:14:30 -08:00
Francisco Ryan Tolmasky I 7adf32f36e Changed menu bar background image.
Reviewed by me.
2009-11-30 23:41:16 -08:00
Francisco Ryan Tolmasky I 5c3beb4160 Fix for _minimumWidth not being defined in the CPMenu class, resulting in minimum widths being applied globally, and menus appearing in strange places in desktop mode.
Reviewed by me.
2009-11-30 23:20:56 -08:00
Francisco Ryan Tolmasky I b82c307007 Added -setMinimumWidth/minimumWidth to CPMenu.
Reviewed by me.
2009-11-30 23:08:05 -08:00
Francisco Ryan Tolmasky I a7010e7598 Accidentally broke normal menu items.
Reviewed by me.
2009-11-30 22:43:36 -08:00
Francisco Ryan Tolmasky I f850cbf780 Better handling of submenu actions.
Reviewed by me.
2009-11-30 22:30:41 -08:00
Tom Robinson 4581fe4f22 Cleanup command line tool args (change objj to include command at args[0]) 2009-11-30 21:45:01 -08:00
Francisco Ryan Tolmasky I 35df54ae99 Merge branch 'jake' into menus 2009-11-30 21:29:27 -08:00
Francisco Ryan Tolmasky I f8a5f91687 Fix for nib2cib leaving cells as targets for menu items.
Reviewed by me.
2009-11-30 21:28:42 -08:00
Francisco Ryan Tolmasky I 4b71557584 Added -popUpMenuPositioningItem:atLocation:inView:callback: and began porting existing uses to it.
Reviewed by me.
2009-11-30 20:54:53 -08:00
Tom Robinson feda903f2f Remove unused junk 2009-11-30 18:45:40 -08:00
Tom Robinson 150e264f0d Remove bake. 2009-11-30 17:21:16 -08:00
Tom Robinson b592f6ae92 Remove submodules 2009-11-30 17:15:37 -08:00
Francisco Ryan Tolmasky I 37ba8fb57d Merge branch 'jake' into menus 2009-11-30 02:02:48 -08:00
Francisco Ryan Tolmasky I 72f80cdbed Cleaned up menu constraints.
Reviewed by me.
2009-11-30 02:01:44 -08:00
Francisco Ryan Tolmasky I c070f20669 Better constraint support, and better support for moving out of submenus.
Reviewed by me.
2009-11-29 19:54:15 -08:00
Ross Boucher a4d5165a3d Fix for style issues. 2009-11-26 19:53:36 -05:00
Abhinav GuptaandRoss Boucher 4fdddfb585 Fixed CPString's commonPrefixWithString to be faster. 2009-11-26 19:49:41 -05:00
Abhinav GuptaandRoss Boucher 0575e96b60 Added commonPrefixWithString method to CPString and tests for it. 2009-11-26 18:13:01 -05:00
Ross Boucher d0a8749986 Fix a type in CPOutlineView. Closes #265. 2009-11-25 00:09:55 -05:00
Ross Boucher 44fbf8afe2 Add support for encoding dates, courtesy of luddep. 2009-11-24 23:02:38 -05:00
Ross Boucher 1eb9202233 A few style guideline changes. 2009-11-24 22:56:18 -05:00
Alexander LjungbergandRoss Boucher b7da92d225 CPDate initWithString: now takes proper international format strings like NSDate. Similarly CPDate description generates such strings. 2009-11-24 22:42:02 -05:00
Ross Boucher e4f6d0db1f Fixes an issue with HUD style alert panels. Closes #343. 2009-11-24 22:13:20 -05:00
Ross Boucher 0a8bd9f687 Remove the "Cancelled" message that Safari shows when an XHR is cancelled during startup. Closes #344. 2009-11-24 18:38:25 -05:00
Ross Boucher f2608998f9 Fixes a typo in CPRectContainsRect by simply calling out to CGRectContainsRect. We should explore simply removing this method entirely. Includes test cases. Closes #345. 2009-11-24 18:30:31 -05:00
Ross Boucher ffb08d32ce Fix an issue with storing 0 in a CPSet. Includes test cases. Closes #337. 2009-11-24 16:06:32 -05:00
Francisco Ryan Tolmasky I 119e776ddc Make scrolling work in submenus.
Reviewed by me.
2009-11-23 23:35:58 -08:00
Francisco Ryan Tolmasky I 652930d5aa Merge branch 'jake' into menus 2009-11-22 16:43:43 -08:00
Francisco Ryan Tolmasky I e3babe97e4 Update to fix menu item sizes breaking on second open.
Reviewed by me.
2009-11-20 23:34:21 -08:00
Ross Boucher 72d01865ae Add about panel 2009-11-20 18:06:16 -08:00
Ross Boucher b9664681a3 Better error reporting for narwhal-jsc 2009-11-19 15:29:20 -08:00
Ross Boucher fd5c545189 Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2009-11-19 14:54:51 -08:00
Ross Boucher 0639f4b00f Exit from subjake if the subjake returns non zero status code. Don't exit in the compiler (required for building in Atlas to not kill the process) 2009-11-19 14:48:18 -08:00
Tom Robinson ab49986238 Add --clone option to bootstrap, and prompt for location 2009-11-19 14:18:49 -08:00
Francisco Ryan Tolmasky I a4fdc50d1d Move these back into their own folders.
Reviewed by me.
2009-11-19 14:04:16 -08:00
Francisco Ryan Tolmasky I ed228b6183 Merge branch 'jake' into menus 2009-11-19 14:02:34 -08:00
Francisco Ryan Tolmasky I e0e675531a Temporarily move these out into the main folder.
Reviewed by me.
2009-11-19 14:02:16 -08:00
Francisco Ryan Tolmasky I 44e0879224 Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2009-11-19 13:26:36 -08:00
Francisco Ryan Tolmasky I 1e6fa93ea2 Fix for NSScrollView breaking nib2cib.
Reviewed by me.
2009-11-19 13:26:02 -08:00
Tom Robinson 2aaed6bffd Replace outdated objj-executable with Narwhal magic. 2009-11-19 00:17:12 -08:00
Francisco Ryan Tolmasky I 2d367a8b47 Fix for not being able to drag window from spaces in toolbar.
Reviewed by me.
2009-11-18 22:08:57 -08:00
Francisco Ryan Tolmasky I 52c18abc5e Fix for class_addMethod with a root class.
Reviewed by me.
2009-11-18 21:56:10 -08:00
Ross Boucher 595c70ed56 Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2009-11-18 14:28:33 -08:00
Alexander LjungbergandRoss Boucher 9faec8decd Fixed: calling setIsPaneSplitter: on a CPTableView would change the divider width but the subviews would not change size to match. 2009-11-18 14:22:58 -08:00
Tom Robinson 90dc1f6cf8 Reorder shell config file checks. 2009-11-18 01:34:01 -08:00
Francisco Ryan Tolmasky I ba01976151 Added target and action to radio groups.
Reviewed by me.
2009-11-17 19:52:20 -08:00
Francisco Ryan Tolmasky I 4d7f5a8a09 Fix for fixing state after turning setAllowsMixedState to NO.
Reviewed by me.
2009-11-17 19:17:58 -08:00
Ross Boucher 2d01fa6f94 Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2009-11-17 17:04:12 -08:00
Ross Boucher 970f848b84 Make CPAlert slightly (but only slightly) more externally hackable 2009-11-17 17:03:42 -08:00
Tom Robinson 31feec0465 Flush stdin after writing file to ShrinkSafe process (fixes building in Rhino) 2009-11-17 17:02:07 -08:00
Francisco Ryan Tolmasky I 2466c14300 Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2009-11-17 14:49:30 -08:00
Francisco Ryan Tolmasky I 49927fcfb7 Fix for building projects where source files are in nested subfolders.
Reviewed by me.
2009-11-17 14:46:54 -08:00
Ross Boucher f612683dfb Taking this out for now. 2009-11-17 10:26:58 -08:00
Ross Boucher 11e6ad2153 Adding a simple way to set a function for the target/action 2009-11-17 09:28:44 -08:00
Klaas Pieter AnnemaandRoss Boucher d041c69e0d Added a check if the window is loaded in CPWindowController 2009-11-17 09:19:05 -08:00
Randall LueckeandRoss Boucher b394052145 fixed tableview typo 2009-11-17 09:16:30 -08:00
Francisco Ryan Tolmasky I e94ddb4179 First pass at submenus.
Reviewed by me.
2009-11-12 18:20:16 -08:00
106 changed files with 5586 additions and 5193 deletions
-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"
+6 -3
View File
@@ -148,8 +148,8 @@ 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:[CPTheme themeNamed: _windowStyle === CPHUDBackgroundWindowMask ? "Aristo-HUD" : "Aristo"]];
[[_alertPanel contentView] addSubview:button];
}
@@ -161,6 +161,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 +263,9 @@ var CPAlertWarningImage,
[button setTag:_buttonCount];
[button setAction:@selector(_notifyDelegate:)];
[button setBezelStyle:(_windowStyle == CPHUDBackgroundWindowMask) ? CPHUDBezelStyle : CPRoundRectBezelStyle];
[button setTheme:[CPTheme themeNamed: _windowStyle === CPHUDBackgroundWindowMask ? "Aristo-HUD" : "Aristo"]];
[button setAutoresizingMask:CPViewMinXMargin|CPViewMinYMargin];
[[_alertPanel contentView] addSubview:button];
if (_buttonCount == 0)
+113 -14
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"];
@@ -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:
@@ -462,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]))
@@ -559,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
@@ -1004,4 +1098,9 @@ var _CPAppBootstrapperActions = nil;
[self performActions];
}
+ (void)reset
{
_CPAppBootstrapperActions = nil;
}
@end
+2 -2
View File
@@ -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
+19 -2
View File
@@ -31,6 +31,11 @@ CPKHTMLBrowserEngine = 3;
CPOperaBrowserEngine = 4;
CPWebKitBrowserEngine = 5;
// Operating Systems
CPMacOperatingSystem = 0;
CPWindowsOperatingSystem = 1;
CPOtherOperatingSystem = 2;
// Features
CPCSSRGBAFeature = 1 << 5;
@@ -183,11 +188,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";
@@ -198,6 +212,9 @@ if (USER_AGENT.indexOf("Mac") != -1)
}
else
{
if (USER_AGENT.indexOf("Windows") !== -1)
OPERATING_SYSTEM = CPWindowsOperatingSystem;
CPPlatformActionKeyMask = CPControlKeyMask;
CPUndoKeyEquivalent = @"Z";
+264
View File
@@ -0,0 +1,264 @@
/*
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
*/
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
{
document.body.style.cursor = 'none'; // Not supported in IE
}
+ (void)unhide
{
document.body.style.cursor = [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
{
document.body.style.cursor = _cssString;
currentCursor = self;
#if PLATFORM(DOM)
var platformWindows = [[CPPlatformWindow visiblePlatformWindows] allObjects];
for (var i = 0, count = [platformWindows count]; i < count; i++)
platformWindows[i]._DOMWindow.document.body.style.cursor = _cssString;
#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
+5 -1
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];
}
+11
View File
@@ -285,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
*/
+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);
}
/*!
-2014
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+556
View File
@@ -0,0 +1,556 @@
#include "../CoreGraphics/CGGeometry.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
+312
View File
@@ -0,0 +1,312 @@
#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],
menuLocation = [activeMenuContainer convertGlobalToBase:globalLocation],
activeItemIndex = activeMenuContainer ? [activeMenuContainer itemIndexAtPoint:menuLocation] : CPNotFound,
activeMenu = activeMenuContainer ? [activeMenuContainer menu] : nil,
activeItem = activeItemIndex !== CPNotFound ? [activeMenu itemAtIndex:activeItemIndex] : nil,
mouseOverMenuView = activeMenuContainer ? [activeItem view] : nil;
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,25 @@ CPControlKeyMask
return _keyEquivalentModifierMask;
}
- (CPString)keyEquivalentStringRepresentation
{
if (![_keyEquivalent length])
return @"";
var string = _keyEquivalent.toUpperCase();
if (_keyEquivalentModifierMask & CPCommandKeyMask)
string = "⌘" + string;
if (_keyEquivalentModifierMask & CPShiftKeyMask)
string = "⇧" + string;
if (_keyEquivalentModifierMask & CPControlKeyMask)
string = "^" + string;
return string;
}
// Managing Mnemonics
/*!
Sets the index of the mnemonic character in the title. The character
@@ -643,7 +677,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 +776,11 @@ CPControlKeyMask
return _menuItemView;
}
- (BOOL)_isSelectable
{
return ![self submenu] || [self action] !== @selector(submenuAction:) || [self target] !== [self menu];
}
@end
var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
@@ -765,6 +804,8 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
CPMenuItemKeyEquivalentKey = @"CPMenuItemKeyEquivalentKey",
CPMenuItemKeyEquivalentModifierMaskKey = @"CPMenuItemKeyEquivalentModifierMaskKey",
CPMenuItemIndentationLevelKey = @"CPMenuItemIndentationLevelKey",
CPMenuItemRepresentedObjectKey = @"CPMenuItemRepresentedObjectKey",
CPMenuItemViewKey = @"CPMenuItemViewKey";
@@ -804,8 +845,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 +855,9 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
// int _mnemonicLocation;
// BOOL _isAlternate;
// int _indentationLevel;
// Default is 0.
[self setIndentationLevel:[aCoder decodeIntForKey:CPMenuItemIndentationLevelKey] || 0];
// CPString _toolTip;
@@ -856,423 +900,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
+1 -1
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;
+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
+5
View File
@@ -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
+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;
+3
View File
@@ -151,6 +151,9 @@ var CPSplitViewHorizontalImage = nil,
_DOMDividerElements = [];
#endif
// The divider changes size when pane splitter mode is toggled, so the
// subviews need to change size too.
_needsResizeSubviews = YES;
[self setNeedsDisplay:YES];
}
+1 -1
View File
@@ -236,7 +236,7 @@ CPTableViewSolidHorizontalGridLineMask = 1 << 1;
if ([_dataSource respondsToSelector:@selector(tableView:setObjectValue:forTableColumn:row:)])
_implementedDataSourceMethods |= CPTableViewDataSource_tableView_setObjectValue_forTableColumn_row_;
if ([_dataSource respondsToSelector:@selector(tableView:setObjectValue:forTableColumn:row:)])
if ([_dataSource respondsToSelector:@selector(tableView:acceptDrop:row:dropOperation:)])
_implementedDataSourceMethods |= CPTableViewDataSource_tableView_acceptDrop_row_dropOperation_;
if ([_dataSource respondsToSelector:@selector(tableView:namesOfPromisedFilesDroppedAtDestination:forDraggedRowsWithIndexes:)])
+19 -11
View File
@@ -55,11 +55,7 @@ var CPTextFieldDOMInputElement = nil,
CPTextFieldInputIsActive = NO,
CPTextFieldCachedSelectStartFunction = nil,
CPTextFieldCachedDragFunction = nil,
CPTextFieldBlurFunction = nil,
CPTextFieldKeyUpFunction = nil,
CPTextFieldKeyPressFunction = nil,
CPTextFieldKeyDownFunction = nil;
CPTextFieldBlurFunction = nil;
#endif
@@ -246,10 +242,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;
}
@@ -639,6 +631,9 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
else
[[self window] selectNextKeyView:self];
if ([[[self window] firstResponder] respondsToSelector:@selector(selectText:)])
[[[self window] firstResponder] selectText:self];
[[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
}
else
@@ -781,11 +776,24 @@ 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)selectAll:(id)sender
{
[self selectText:sender];
}
#pragma mark Setting the Delegate
- (void)setDelegate:(id)aDelegate
+8 -1
View File
@@ -957,7 +957,14 @@ var TOP_MARGIN = 5.0,
- (void)mouseDown:(CPEvent)anEvent
{
if ([_toolbarItem view])
return;
return [[self nextResponder] mouseDown:anEvent];
var identifier = [_toolbarItem itemIdentifier];
if (identifier === CPToolbarSpaceItemIdentifier ||
identifier === CPToolbarFlexibleSpaceItemIdentifier ||
identifier === CPToolbarSeparatorItemIdentifier)
return [[self nextResponder] mouseDown:anEvent];
[super mouseDown:anEvent];
}
+1 -1
View File
@@ -596,7 +596,7 @@ var CPViewFlags = { },
- (void)viewWithTag:(CPInteger)aTag
{
if ([self tag] === aTag)
if ([self tag] == aTag)
return self;
var index = 0,
+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;
+18
View File
@@ -333,6 +333,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:
@@ -610,6 +615,8 @@ CPTexturedBackgroundWindowMask
*/
- (void)setFrame:(CGRect)aFrame display:(BOOL)shouldDisplay animate:(BOOL)shouldAnimate
{
aFrame = _CGRectMakeCopy(aFrame);
var value = aFrame.origin.x,
delta = value - FLOOR(value);
@@ -1678,6 +1685,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:)])
{
+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)],
+9 -1
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];
+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...
+9
View File
@@ -30,6 +30,10 @@ var PrimaryPlatformWindow = NULL;
Object _charCodes;
unsigned _keyCode;
unsigned _lastKey;
BOOL _capsLockActive;
BOOL _ignoreNativeCopyOrCutEvent;
BOOL _ignoreNativePastePreparation;
BOOL _DOMEventMode;
@@ -41,6 +45,11 @@ var PrimaryPlatformWindow = NULL;
#endif
}
+ (CPSet)visiblePlatformWindows
{
return [CPSet set];
}
+ (CPPlatformWindow)primaryPlatformWindow
{
return PrimaryPlatformWindow;
+231 -116
View File
@@ -66,7 +66,7 @@
* 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 in keypress
* Safari 2 in keypress (not supported)
*
* charCode keyCode which
* ENTER: 13 13 13
@@ -117,26 +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";
// List of all open native windows
var PlatformWindows = [CPSet set];
// Define up here so compressor knows about em.
var CPDOMEventGetClickCount,
@@ -148,9 +134,12 @@ var CPDOMEventGetClickCount,
//might be mac only, we should investigate futher later.
var KeyCodesToPrevent = {},
CharacterKeysToPrevent = {},
KeyCodesWithoutKeyPressEvents = { '8':1, '9':1, '16':1, '33':1, '34':1, '35':1, '36':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];
@@ -251,6 +240,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
_DOMBodyElement.webkitTouchCallout = "none";
// 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";
@@ -261,11 +251,11 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
_DOMBodyElement.appendChild(_DOMFocusElement);
// Create Native Pasteboard handler.
_DOMPasteboardElement = theDocument.createElement("input");
_DOMPasteboardElement = theDocument.createElement("textarea");
_DOMPasteboardElement.style.position = "absolute";
_DOMPasteboardElement.style.top = "-10000px";
_DOMPasteboardElement.style.zIndex = "99";
_DOMPasteboardElement.style.zIndex = "999";
_DOMBodyElement.appendChild(_DOMPasteboardElement);
@@ -283,6 +273,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); },
@@ -299,6 +297,7 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
touchEventImplementation = class_getMethodImplementation(theClass, touchEventSelector),
touchEventCallback = function (anEvent) { touchEventImplementation(self, nil, anEvent); };
if (theDocument.addEventListener)
{
if ([CPPlatform supportsDragAndDrop])
@@ -315,6 +314,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);
@@ -342,6 +345,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);
@@ -354,6 +361,8 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
//_DOMWindow.removeEventListener("beforeunload", this, NO);
[PlatformWindows removeObject:self];
self._DOMWindow = nil;
}, NO);
}
@@ -400,11 +409,18 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
//_DOMWindow.removeEvent("beforeunload", this);
[PlatformWindows removeObject:self];
self._DOMWindow = nil;
}, NO);
}
}
+ (CPSet)visiblePlatformWindows
{
return PlatformWindows;
}
- (void)orderFront:(id)aSender
{
if (_DOMWindow)
@@ -412,6 +428,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();
@@ -425,6 +443,8 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
_DOMWindow.cpSetShadowStyle(_shadowStyle);
}
_DOMWindow.document.body.style.cursor = [[CPCursor currentCursor] _cssString];
[self registerDOMWindow];
}
@@ -538,12 +558,11 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
(aDOMEvent.ctrlKey ? CPControlKeyMask : 0) |
(aDOMEvent.altKey ? CPAlternateKeyMask : 0) |
(aDOMEvent.metaKey ? CPCommandKeyMask : 0);
//We want to stop propagation if this is a command key AND this character or keycode has been added to our blacklist
StopDOMEventPropagation = !(modifierFlags & (CPControlKeyMask | CPCommandKeyMask)) ||
//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,
@@ -552,56 +571,80 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
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 | CPAlternateKeyMask))
{
_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 | CPAlternateKeyMask)))
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
@@ -612,7 +655,6 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
{
_pasteboardKeyDownEvent = event;
window.setNativeTimeout(function () { [self _checkPasteboardElement] }, 0);
return;
}
break;
@@ -620,12 +662,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
@@ -633,40 +683,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];
}
- (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
@@ -760,6 +896,8 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
// We should pay attention to mouse down and mouse up in conjunction with this.
//window.liveResize = YES;
[CPApp._activeMenu cancelTracking];
var oldSize = [self contentRect].size;
[self updateFromNativeContentRect];
@@ -1077,8 +1215,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,
@@ -1101,37 +1247,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;
}
}
File diff suppressed because one or more lines are too long
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.

Before

Width:  |  Height:  |  Size: 107 B

After

Width:  |  Height:  |  Size: 118 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 137 B

After

Width:  |  Height:  |  Size: 147 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

@@ -177,8 +177,8 @@ var BKLearnMoreToolbarItemIdentifier = @"BKLearnMoreToolbarItemId
var width = CGRectGetWidth([popUpButton frame]);
[toolbarItem setMinSize:CGSizeMake(width + 20.0, 32.0)];
[toolbarItem setMaxSize:CGSizeMake(width + 20.0, 32.0)];
[toolbarItem setMinSize:CGSizeMake(width + 20.0, 24.0)];
[toolbarItem setMaxSize:CGSizeMake(width + 20.0, 24.0)];
}
else if (anItemIdentifier === BKBackgroundColorToolbarItemIdentifier)
@@ -206,8 +206,8 @@ var BKLearnMoreToolbarItemIdentifier = @"BKLearnMoreToolbarItemId
var width = CGRectGetWidth([popUpButton frame]);
[toolbarItem setMinSize:CGSizeMake(width, 32.0)];
[toolbarItem setMaxSize:CGSizeMake(width, 32.0)];
[toolbarItem setMinSize:CGSizeMake(width, 24.0)];
[toolbarItem setMaxSize:CGSizeMake(width, 24.0)];
}
else if (anItemIdentifier === BKLearnMoreToolbarItemIdentifier)
{
@@ -227,8 +227,8 @@ var BKLearnMoreToolbarItemIdentifier = @"BKLearnMoreToolbarItemId
var width = CGRectGetWidth([button frame]);
[toolbarItem setMinSize:CGSizeMake(width, 32.0)];
[toolbarItem setMaxSize:CGSizeMake(width, 32.0)];
[toolbarItem setMinSize:CGSizeMake(width, 24.0)];
[toolbarItem setMaxSize:CGSizeMake(width, 24.0)];
}
return toolbarItem;
+2 -2
View File
@@ -340,7 +340,7 @@ var HORIZONTAL_MARGIN = 3.0,
textStyle.position = "absolute";
textStyle.whiteSpace = "pre";
textStyle.cursor = "default";
textStyle.zIndex = 200;
textStyle.overflow = "hidden";
@@ -376,7 +376,7 @@ var HORIZONTAL_MARGIN = 3.0,
shadowStyle.font = [_font ? _font : [CPFont systemFontOfSize:12.0] cssString];
shadowStyle.position = "absolute";
shadowStyle.whiteSpace = textStyle.whiteSpace;
shadowStyle.cursor = "default";
shadowStyle.zIndex = 150;
shadowStyle.textOverflow = textStyle.textOverflow;
-63
View File
@@ -1,63 +0,0 @@
#!/usr/bin/env narwhal
var FILE = require("file"),
ENV = require("system").env,
OS = require("os"),
Jake = require("jake");
/*,
Clean = require("jake/clean");
*/
require(FILE.absolute("../common.jake"));
$ENVIRONMENT_NARWHAL_PRODUCT = $ENVIRONMENT_DIR
$ENVIRONMENT_PACKAGES_PRODUCT = FILE.join($ENVIRONMENT_NARWHAL_PRODUCT, 'packages')
$EXTERNALS = ['browserjs', 'jack', 'narwhal', 'ojunit'];
$PACKAGES = ['browserjs', 'jack'];
function git_export(source, destination)
{
destination = FILE.join(FILE.absolute(destination), '');
OS.system("cd " + source + " && git checkout-index -a -f \"--prefix=" + destination + "\"");
};
filedir ($ENVIRONMENT_DIR, function()
{
FILE.mkdirs($ENVIRONMENT_DIR);
});
task ("update_submodules", function()
{
if (ENV['NOSUBUP'])
return;
if (executableExists("git"))
OS.system("cd .. && git submodule init && git submodule update");
else
throw "Git not installed";
});
task ("build", ["update_submodules", $ENVIRONMENT_DIR], function()
{
rm_rf($ENVIRONMENT_NARWHAL_PRODUCT);
git_export('narwhal', $ENVIRONMENT_NARWHAL_PRODUCT);
$PACKAGES.forEach(function(aPackage)
{
git_export(aPackage, FILE.join($ENVIRONMENT_PACKAGES_PRODUCT, aPackage));
});
symlink_executable(FILE.join($ENVIRONMENT_PACKAGES_PRODUCT, 'jack', 'bin', 'jackup'))
});
//CLOBBER.include($ENVIRONMENT_NARWHAL_PRODUCT)
task ("pull", function()
{
$EXTERNALS.forEach(function(external)
{
OS.system("cd " + external + " && git pull origin master");
});
});
-54
View File
@@ -1,54 +0,0 @@
#!/usr/bin/env ruby
require '../common'
require 'objective-j'
require 'rake'
require 'rake/clean'
require 'fileutils'
$ENVIRONMENT_NARWHAL_PRODUCT = $ENVIRONMENT_DIR
$ENVIRONMENT_PACKAGES_PRODUCT = File.join($ENVIRONMENT_NARWHAL_PRODUCT, 'packages')
$EXTERNALS = ['browserjs', 'jack', 'narwhal', 'ojunit']
$PACKAGES = ['browserjs', 'jack']
def git_export(source, dest)
dest = File.join(File.expand_path(dest), '');
system %{cd "#{source}" && git checkout-index -a -f "--prefix=#{dest}"}
end
file_d $ENVIRONMENT_DIR do
mkdir_p $ENVIRONMENT_DIR
end
task :update_submodules do
if !ENV['NOSUBUP'] then
if executable_exists? "git"
system %{cd .. && git submodule init && git submodule update}
else
puts "Git not installed"
rake abort
end
end
end
task :build => [:update_submodules, $ENVIRONMENT_DIR] do
rm_rf($ENVIRONMENT_NARWHAL_PRODUCT)
git_export('narwhal', $ENVIRONMENT_NARWHAL_PRODUCT)
$PACKAGES.each do |package|
git_export(package, File.join($ENVIRONMENT_PACKAGES_PRODUCT, package))
end
symlink_executable(File.join($ENVIRONMENT_PACKAGES_PRODUCT, 'jack', 'bin', 'jackup'))
end
CLOBBER.include($ENVIRONMENT_NARWHAL_PRODUCT)
task :pull do
$EXTERNALS.each do |external|
system "cd #{external} && git pull origin master"
end
end
Submodule External/browserjs deleted from 98a71a4122
-1
Submodule External/jack deleted from 3ee7b56812
-1
Submodule External/narwhal deleted from cd6e4b02ab
-1
Submodule External/ojunit deleted from 352b7e8c61
+2 -2
View File
@@ -521,8 +521,8 @@
*/
- (id)objectAtIndex:(int)anIndex
{
if (anIndex >= length)
[CPException raise:CPRangeException reason:@"index (" + anIndex + @") beyond bounds (" + length + @")"];
if (anIndex >= length || anIndex < 0)
[CPException raise:CPRangeException reason:@"index (" + anIndex + @") out of bounds (0 - " + length + @")"];
return self[anIndex];
}
+49 -2
View File
@@ -96,9 +96,28 @@ var CPDateReferenceDate = new Date(Date.UTC(2001,1,1,0,0,0,0));
return self;
}
/*!
Returns a CPDate initialized with a date and time specified by the given
string in international date format YYYY-MM-DD HH:MM:SS ±HHMM (e.g.
2009-11-17 17:52:04 +0000).
*/
- (id)initWithString:(CPString)description
{
self = new Date(description); // FIXME: not same format as NSString
var format = /(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2}) ([-+])(\d{2})(\d{2})/,
d = description.match(new RegExp(format));
if (!d || d.length != 10)
[CPException raise:CPInvalidArgumentException
reason:"initWithString: the string must be of YYYY-MM-DD HH:MM:SS ±HHMM format"];
var date = new Date(d[1], d[2]-1, d[3]),
timeZoneOffset = (Number(d[8]) * 60 + Number(d[9])) * (d[7] === '-' ? -1 : 1);
date.setHours(d[4]);
date.setMinutes(d[5]);
date.setSeconds(d[6]);
self = new Date(date.getTime() + (timeZoneOffset - date.getTimezoneOffset()) * 60 * 1000);
return self;
}
@@ -152,9 +171,37 @@ var CPDateReferenceDate = new Date(Date.UTC(2001,1,1,0,0,0,0));
return (self > anotherDate) ? self : anotherDate;
}
/*!
Returns the date as a string in the international format
YYYY-MM-DD HH:MM:SS ±HHMM.
*/
- (CPString)description
{
return self.toString(); // FIXME: not same format as NSDate
var hours = Math.floor(self.getTimezoneOffset() / 60),
minutes = self.getTimezoneOffset() - hours * 60;
return [CPString stringWithFormat:@"%04d-%02d-%02d %02d:%02d:%02d +%02d%02d", self.getFullYear(), self.getMonth()+1, self.getDate(), self.getHours(), self.getMinutes(), self.getSeconds(), hours, minutes];
}
@end
var CPDateTimeKey = @"CPDateTimeKey";
@implementation CPDate (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
if (self)
{
self.setTime([aCoder decodeIntForKey:CPDateTimeKey]);
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[aCoder encodeInt:self.getTime() forKey:CPDateTimeKey];
}
@end
+3 -1
View File
@@ -232,7 +232,9 @@
*/
- (BOOL)containsObject:(id)anObject
{
if (_contents[[anObject UID]] && [_contents[[anObject UID]] isEqual:anObject])
var obj = _contents[[anObject UID]];
if (obj !== undefined && [obj isEqual:anObject])
return YES;
return NO;
+38
View File
@@ -537,6 +537,44 @@ var CPStringRegexSpecialCharacters = [
return hash;
}
/*!
Returns a string containing characters the receiver and a given string have in common, starting from
the beginning of each up to the first characters that aren't equivalent.
@param aString the string with which to compare the receiver
*/
- (CPString)commonPrefixWithString:(CPString)aString
{
return [self commonPrefixWithString: aString options: 0];
}
/*!
Returns a string containing characters the receiver and a given string have in common, starting from
the beginning of each up to the first characters that aren't equivalent.
@param aString the string with which to compare the receiver
@param aMask options for comparision
*/
- (CPString)commonPrefixWithString:(CPString)aString options:(int)aMask
{
var len = 0, // length of common prefix
lhs = self,
rhs = aString,
min = MIN([lhs length], [rhs length]);
if (aMask & CPCaseInsensitiveSearch)
{
lhs = [lhs lowercaseString];
rhs = [rhs lowercaseString];
}
for (; len < min; len++ )
{
if ( [lhs characterAtIndex:len] !== [rhs characterAtIndex:len] )
break;
}
return [self substringToIndex:len];
}
/*!
Returns a copy of the receiver with all the first letters of words capitalized.
*/
+12 -11
View File
@@ -8,12 +8,12 @@ function printUsage()
print("this is where you say the usage");
}
function main()
exports.main = function(args)
{
// FIXME: ARGS
system.args.shift();
// TODO: args parser
args.shift();
if (system.args.length < 1)
if (args.length < 1)
return printUsage();
var allFiles = NO,
@@ -23,11 +23,11 @@ function main()
outExtension = nil;
index = 0,
count = system.args.length;
count = args.length;
for (; index < count; ++index)
{
var argument = system.args[index];
var argument = args[index];
if (argument.charAt(0) === '-' && !allFiles)
{
@@ -35,13 +35,13 @@ function main()
return printUsage();
else if (argument === "-convert")
format = system.args[++index];
format = args[++index];
else if (argument === "-o")
outPath = system.args[++index];
outPath = args[++index];
else if (argument === "-e")
outExtension = system.args[++index];
outExtension = args[++index];
else if (argument === "--")
allFiles = YES;
@@ -50,7 +50,7 @@ function main()
return printUsage();
}
else
filePaths.push(system.args[index]);
filePaths.push(args[index]);
}
index = 0;
@@ -76,4 +76,5 @@ function main()
}
}
main();
if (require.main == module.id)
exports.main(system.args);
+16 -31
View File
@@ -1,7 +1,6 @@
var FILE = require("file"),
readline = require("readline").readline;
var FILE = require("file");
var window = require("browser/window");
var window = exports.window = require("browser/window");
if (system.engine === "rhino")
{
@@ -105,37 +104,26 @@ with (window)
exports.IS_FILE = function(aFragment) { return (aFragment.type & FRAGMENT_FILE); }
exports.IS_LOCAL = function(aFragment) { return (aFragment.type & FRAGMENT_LOCAL); }
exports.IS_IMPORT = function(aFragment) { return (aFragment.type & FRAGMENT_IMPORT); }
/*
objj_set_evaluator(function(code) {
return function(OBJJ_CURRENT_BUNDLE) {
with (window) {
return eval("function(OBJJ_CURRENT_BUNDLE){"+code+"}");
}
}
});
*/
// runs the objj repl or file provided in args
exports.run = function(args)
{
args = args || [];
window.args = args;
// FIXME: ARGS
args.shift();
if (args.length > 0)
if (args && args.length > 1)
{
while (args.length && args[0].indexOf('-I') === 0)
OBJJ_INCLUDE_PATHS = args.shift().substr(2).split(':').concat(OBJJ_INCLUDE_PATHS);
var mainFilePath = FILE.canonical(args.shift());
var arg0 = args.slice(0,1),
argv = args.slice(1);
while (argv.length && argv[0].indexOf('-I') === 0)
OBJJ_INCLUDE_PATHS = argv.shift().substr(2).split(':').concat(OBJJ_INCLUDE_PATHS);
var mainFilePath = FILE.canonical(argv.shift());
objj_import(mainFilePath, YES, function() {
if (typeof main === "function")
main.apply(main, args);
main(arg0.concat(argv));
});
require("browser/timeout").serviceTimeouts();
}
else
{
@@ -144,9 +132,8 @@ exports.run = function(args)
try {
system.stdout.write("objj> ").flush();
var input = readline(),
result = objj_eval(input);
var result = objj_eval(require("readline").readline());
if (result !== undefined)
print(result);
@@ -157,8 +144,6 @@ exports.run = function(args)
require("browser/timeout").serviceTimeouts();
}
}
require("browser/timeout").serviceTimeouts();
}
// synchronously evals Objective-J code
@@ -43,6 +43,7 @@ function compress(/*String*/ aCode, /*String*/ FIXME)
chunk = "";
compressor.stdin.write(tmpFile + "\n");
compressor.stdin.flush();
while ((chunk = compressor.stdout.readLine()) !== "/*----*/\n")
output += chunk;
@@ -82,11 +83,11 @@ function compileWithResolvedFlags(aFilePath, objjcFlags, gccFlags)
for (var index = 0; index < fragments.length; index++)
{
var fragment = fragments[index];
if (IS_FILE(fragment))
preprocessed += (IS_LOCAL(fragment) ? MARKER_IMPORT_LOCAL : MARKER_IMPORT_STD) + ';' + GET_PATH(fragment).length + ';' + GET_PATH(fragment);
else
{
{
var code = GET_CODE(fragment);
if (shouldCheckSyntax)
@@ -98,23 +99,25 @@ function compileWithResolvedFlags(aFilePath, objjcFlags, gccFlags)
catch (e)
{
var lines = code.split("\n"),
PAD = 3;
print("Syntax error in "+GET_FILE(fragment).path+
" on preprocessed line number "+e.lineNumber+"\n"+
"\t"+lines.slice(Math.max(0, e.lineNumber - 1 - PAD), e.lineNumber+PAD).join("\n\t"));
OS.exit(1);
PAD = 3,
lineNumber = e.lineNumber || e.line,
errorInfo = "Syntax error in "+GET_FILE(fragment).path+
" on preprocessed line number "+lineNumber+"\n\n"+
"\t"+lines.slice(Math.max(0, lineNumber - 1 - PAD), lineNumber+PAD).join("\n\t");
print(errorInfo);
throw errorInfo;
}
}
if (shouldCompress)
{
code = compress("function(){" + code + '}', FILE.basename(aFilePath));
code = code.substr("function(){".length, code.length - "function(){};\n\n".length);
}
preprocessed += MARKER_CODE + ';' + code.length + ';' + code;
}
}
@@ -180,7 +183,7 @@ exports.compile = function(aFilePath, flags)
exports.main = function(args)
{
// FIXME: ARGS
// TODO: args parser
args.shift();
var resolved = resolveFlags(args),
@@ -197,4 +200,4 @@ exports.main = function(args)
}
if (require.main == module.id)
exports.main(system.args);
exports.main(system.args);
@@ -509,7 +509,11 @@ function directoryInCommon(filenames)
{
var directory = FILE.dirname(aFilename);
if (!aCommonDirectory)
if (directory === ".")
directory = "";
// Empty string is an acceptable common directory.
if (aCommonDirectory === null)
aCommonDirectory = directory;
else
@@ -665,7 +669,8 @@ BundleTask.prototype.defineSourceTasks = function()
else if (compilerFlags.join)
compilerFlags = compilerFlags.join(" ");
var environments = this.flattenedEnvironments();
var environments = this.flattenedEnvironments(),
flattensSources = this.flattensSources();
environments.forEach(function(/*Environment*/ anEnvironment)
{
@@ -683,7 +688,10 @@ BundleTask.prototype.defineSourceTasks = function()
}
var replacedFiles = [],
environmentCompilerFlags = anEnvironment.compilerFlags().join(" ") + " " + compilerFlags;
environmentCompilerFlags = anEnvironment.compilerFlags().join(" ") + " " + compilerFlags,
flattensSources = this.flattensSources(),
basePath = directoryInCommon(environmentSources),
basePathLength = basePath.length;
environmentSources.forEach(function(/*String*/ aFilename)
{
@@ -691,7 +699,8 @@ BundleTask.prototype.defineSourceTasks = function()
if (!FILE.exists(aFilename) || FILE.extension(aFilename) !== '.j')
return;
var compiledEnvironmentSource = FILE.join(sourcesPath, FILE.basename(aFilename));
var relativePath = aFilename.substring(basePathLength ? basePathLength + 1 : basePathLength),
compiledEnvironmentSource = FILE.join(sourcesPath, relativePath);
filedir (compiledEnvironmentSource, [aFilename], function()
{
@@ -701,9 +710,7 @@ BundleTask.prototype.defineSourceTasks = function()
filedir (staticPath, [compiledEnvironmentSource]);
// FIXME: how do we non flatten?
// dir in common
replacedFiles.push(flattensSources ? FILE.basename(aFilename) : FILE.relative(sourcesPath, aFilename));
replacedFiles.push(flattensSources ? FILE.basename(aFilename) : relativePath);
}, this);
this._replacedFiles[anEnvironment] = replacedFiles;
+10 -22
View File
@@ -1,27 +1,15 @@
#!/bin/bash
#!/usr/bin/env narwhal
# get the absolute path of the executable
SELF_PATH=$(cd -P -- "$(dirname -- "$0")" && pwd -P) && SELF_PATH=$SELF_PATH/$(basename -- "$0")
var FILE = require("file");
# resolve symlinks
while [ -h "$SELF_PATH" ]; do
DIR=$(dirname -- "$SELF_PATH")
SYM=$(readlink -- "$SELF_PATH")
SELF_PATH=$(cd -- "$DIR" && cd -- $(dirname -- "$SYM") && pwd)/$(basename -- "$SYM")
done
var cappuccinoPackage = FILE.path(module.path).dirname().dirname();
var mainPath = cappuccinoPackage.join("lib", FILE.basename(module.path), "main.j");
var frameworksPath = cappuccinoPackage.join("Frameworks");
SELF_DIR=`dirname $SELF_PATH`
export SELF_HOME=`dirname $SELF_DIR`
SELF_LIB="$SELF_HOME/lib"
// TODO: is specifying the Frameworks necessary?
system.args.splice(1, 0, "-I"+frameworksPath, String(mainPath));
FRAMEWORKS="$SELF_HOME/Frameworks"
MAIN="$SELF_LIB/$(basename $SELF_PATH)/main.j"
// HACK: remove use of SELF_HOME from capp gen
system.env["SELF_HOME"] = cappuccinoPackage;
# convert paths for Cygwin
if [[ `uname` == CYGWIN* ]]; then
FRAMEWORKS=`cygpath -w "$FRAMEWORKS"`
MAIN=`cygpath -w "$MAIN"`
fi
objj -I$FRAMEWORKS $MAIN "$@"
require("objective-j").run(system.args);
+3 -3
View File
@@ -161,12 +161,12 @@ function class_copyIvarList(/*Class*/ aClass)
#define METHOD_DISPLAY_NAME(aClass, aMethod) (ISMETA(aClass) ? '+' : '-') + " [" + class_getName(aClass) + ' ' + method_getName(aMethod) + ']'
function class_addMethod(/*Class*/ aClass, /*SEL*/ aName, /*IMP*/ anImplementation, /*String*/aType)
function class_addMethod(/*Class*/ aClass, /*SEL*/ aName, /*IMP*/ anImplementation, /*Array<String>*/ types)
{
if (aClass.method_hash[aName])
return NO;
var method = new objj_method(aName, anImplementation, aType);
var method = new objj_method(aName, anImplementation, types);
aClass.method_list.push(method);
aClass.method_dtable[aName] = method;
@@ -177,7 +177,7 @@ function class_addMethod(/*Class*/ aClass, /*SEL*/ aName, /*IMP*/ anImplementati
// FIXME: Should this be done here?
// If this is a root class...
if (!ISMETA(aClass) && GETMETA(aClass).isa === GETMETA(aClass))
class_addMethod(GETMETA(aClass), method);
class_addMethod(GETMETA(aClass), aName, anImplementation, types);
return YES;
}
+17
View File
@@ -0,0 +1,17 @@
@import <AppKit/CPGeometry.j>
@implementation CPGeometryTest : OJTestCase
{
}
- (void)testCPRectContainsRect
{
[self assertTrue:CPRectContainsRect(CGRectMake(0, 0, 500, 500), CGRectMake(0, 0, 50, 50))];
[self assertTrue:CPRectContainsRect(CGRectMake(0, 0, 500, 500), CGRectMake(50, 50, 50, 50))];
[self assertTrue:CPRectContainsRect(CGRectMake(0, 0, 500, 500), CGRectMake(450, 450, 50, 50))];
[self assertTrue:CPRectContainsRect(CGRectMake(0, 0, 500, 500), CGRectMake(500, 500, 0, 0))];
[self assertFalse:CPRectContainsRect(CGRectMake(0, 0, 500, 500), CGRectMake(50, 50, 500, 500))];
[self assertFalse:CPRectContainsRect(CGRectMake(0, 0, 500, 500), CGRectMake(500, 500, 1, 1))];
}
@end
+52
View File
@@ -0,0 +1,52 @@
/*
* AppController.j
* CursorTest
*
* Created by You on November 6, 2009.
* Copyright 2009, Your Company All rights reserved.
*/
@import <Foundation/CPObject.j>
var selectors = ["pointingHandCursor", "resizeDownCursor", "resizeLeftCursor", "resizeRightCursor", "resizeUpCursor", "resizeLeftRightCursor", "resizeUpDownCursor", "operationNotAllowedCursor", "dragCopyCursor", "dragLinkCursor", "contextualMenuCursor", "openHandCursor", "closedHandCursor", "disappearingItemCursor"];
@implementation AppController : CPObject
{
CPPopUpButton popup;
}
- (void)applicationDidFinishLaunching:(CPNotification)aNotification
{
var theWindow = [[CPWindow alloc] initWithContentRect:CGRectMakeZero() styleMask:CPBorderlessBridgeWindowMask],
contentView = [theWindow contentView];
popup = [[CPPopUpButton alloc] initWithFrame:CGRectMake(100,100,150,24)];
var menu = [popup menu];
for (var i = 0 , count = [selectors count];i < count;i++)
{
var selector = selectors[i];
var item = [[CPMenuItem alloc] initWithTitle:selector action:nil keyEquivalent:@""];
[item setTarget:self];
[menu addItem:item];
}
[contentView addSubview:popup];
var button = [[CPButton alloc] initWithFrame:CGRectMake(270,100,100,24)];
[button setAction:@selector(setCursor:)];
[button setTarget:self];
[button setTitle:@"set Cursor"];
[contentView addSubview:button];
[theWindow orderFront:self];
// Uncomment the following line to turn on the standard menu bar.
//[CPMenu setMenuBarVisible:YES];
}
-(void)setCursor:(id)sender
{
var selector = CPSelectorFromString([popup titleOfSelectedItem]);
var cursor = [CPCursor performSelector:selector];
[cursor set];
}
@end
+12
View File
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CPApplicationDelegateClass</key>
<string>AppController</string>
<key>CPBundleName</key>
<string>CursorTest</string>
<key>CPPrincipalClass</key>
<string>CPApplication</string>
</dict>
</plist>
+38
View File
@@ -0,0 +1,38 @@
/*
* Jakefile
* CursorTest
*
* Created by You on November 6, 2009.
* Copyright 2009, Your Company All rights reserved.
*/
var ENV = require("system").env,
FILE = require("file"),
task = require("jake").task,
FileList = require("jake").FileList,
app = require("cappuccino/jake").app,
configuration = ENV["CONFIG"] || ENV["CONFIGURATION"] || ENV["c"] || "Debug";
app ("CursorTest", function(task)
{
task.setBuildIntermediatesPath(FILE.join("Build", "CursorTest.build", configuration));
task.setBuildPath(FILE.join("Build", configuration));
task.setProductName("CursorTest");
task.setIdentifier("com.yourcompany.CursorTest");
task.setVersion("1.0");
task.setAuthor("Your Company");
task.setEmail("feedback @nospam@ yourcompany.com");
task.setSummary("CursorTest");
task.setSources(new FileList("**/*.j"));
task.setResources(new FileList("Resources/*"));
task.setIndexFilePath("index.html");
task.setInfoPlistPath("Info.plist");
if (configuration === "Debug")
task.setCompilerFlags("-DDEBUG -g");
else
task.setCompilerFlags("-O");
});
task ("default", ["CursorTest"]);
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

+84
View File
@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns = "http://www.w3.org/1999/xhtml" xml:lang = "en" lang = "en">
<!--
index-debug.html
CursorTest
Created by You on November 6, 2009.
Copyright 2009, Your Company All rights reserved.
-->
<head>
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
<title>CursorTest</title>
<script type = "text/javascript">
OBJJ_MAIN_FILE = "main.j";
OBJJ_INCLUDE_PATHS = ["Frameworks/Debug", "Frameworks", "SomethingElse"];
</script>
<script src = "Frameworks/Debug/Objective-J/Objective-J.js" type = "text/javascript"></script>
<script type = "text/javascript">
objj_msgSend_reset();
// DEBUG OPTIONS:
// Uncomment to enable printing of backtraces on exceptions:
//objj_msgSend_decorate(objj_backtrace_decorator);
// Uncomment to enable runtime type checking:
//objj_msgSend_decorate(objj_typecheck_decorator);
// Uncomment (along with both above) to print backtraces on type check errors:
//objj_typecheck_prints_backtrace = true;
</script>
<style type = "text/css">
body{margin:0; padding:0;}
#container {position: absolute; top:50%; left:50%;}
#content {width:800px; text-align:center; margin-left: -400px; height:50px; margin-top:-25px; line-height: 50px;}
#content {font-family: "Helvetica", "Arial", sans-serif; font-size: 18px; color: black; text-shadow: 0px 1px 0px white; }
#loadgraphic {margin-right: 0.2em; margin-bottom:-2px;}
</style>
<!--[if lt IE 7]>
<STYLE type="text/css">
#container { position: relative; top: 50%; }
#content { position: relative;}
</STYLE>
<![endif]-->
</head>
<body style="">
<div id="loadingcontainer" style=" background-color: #eeeeee; overflow:hidden; width:100%; height:100%; position: absolute; top: 0; left: 0;">
<script type = "text/javascript">
document.write("<div id='container'><p id='content'>" +
"<img id='loadgraphic' width='16' height='16' src='Resources/spinner.gif' /> " +
"Loading CursorTest...</p></div>");
</script>
<noscript>
<div id="container">
<div style="width: 440px; padding: 10px 25px 20px 25px; font-family: sans-serif; background-color: #ffffff; position: relative; left: -245px; top: -120px; text-align: center; -moz-border-radius: 20px; -webkit-border-radius: 20px; color: #555555">
<p style="line-height: 1.4em;">JavaScript is required for this site to work correctly but is either disabled or not supported by your browser.</p>
<p style="font-size:120%; padding:10px;"><a href="http://cappuccino.org/noscript">Show me how to enable JavaScript</a></p>
<p style="font-size:80%;">You may want to upgrade to a newer browser while you're at it:</p>
<ul style="margin:0;padding:0; text-align: center; font-size:80%;" >
<li style="display: inline;"><a href="http://www.apple.com/safari/download/">Safari</a></li>
<li style="display: inline;"><a href="http://www.mozilla.com/en-US/firefox/">Firefox</a></li>
<li style="display: inline;"><a href="http://www.google.com/chrome/">Chrome</a></li>
<li style="display: inline;"><a href="http://www.opera.com/download/">Opera</a></li>
<li style="display: inline;"><a href="http://www.microsoft.com/windows/downloads/ie/getitnow.mspx">Internet Explorer</a></li>
</ul>
</div>
</div>
</noscript>
</div>
</body>
</html>
+69
View File
@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns = "http://www.w3.org/1999/xhtml" xml:lang = "en" lang = "en">
<!--
index.html
CursorTest
Created by You on November 6, 2009.
Copyright 2009, Your Company All rights reserved.
-->
<head>
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
<title>CursorTest</title>
<script type = "text/javascript">
OBJJ_MAIN_FILE = "main.j";
</script>
<script src = "Frameworks/Objective-J/Objective-J.js" type = "text/javascript"></script>
<style type = "text/css">
body{margin:0; padding:0;}
#container {position: absolute; top:50%; left:50%;}
#content {width:800px; text-align:center; margin-left: -400px; height:50px; margin-top:-25px; line-height: 50px;}
#content {font-family: "Helvetica", "Arial", sans-serif; font-size: 18px; color: black; text-shadow: 0px 1px 0px white; }
#loadgraphic {margin-right: 0.2em; margin-bottom:-2px;}
</style>
<!--[if lt IE 7]>
<STYLE type="text/css">
#container { position: relative; top: 50%; }
#content { position: relative;}
</STYLE>
<![endif]-->
</head>
<body style="">
<div id="loadingcontainer" style=" background-color: #eeeeee; overflow:hidden; width:100%; height:100%; position: absolute; top: 0; left: 0;">
<script type = "text/javascript">
document.write("<div id='container'><p id='content'>" +
"<img id='loadgraphic' width='16' height='16' src='Resources/spinner.gif' /> " +
"Loading CursorTest...</p></div>");
</script>
<noscript>
<div id="container">
<div style="width: 440px; padding: 10px 25px 20px 25px; font-family: sans-serif; background-color: #ffffff; position: relative; left: -245px; top: -120px; text-align: center; -moz-border-radius: 20px; -webkit-border-radius: 20px; color: #555555">
<p style="line-height: 1.4em;">JavaScript is required for this site to work correctly but is either disabled or not supported by your browser.</p>
<p style="font-size:120%; padding:10px;"><a href="http://cappuccino.org/noscript">Show me how to enable JavaScript</a></p>
<p style="font-size:80%;">You may want to upgrade to a newer browser while you're at it:</p>
<ul style="margin:0;padding:0; text-align: center; font-size:80%;" >
<li style="display: inline;"><a href="http://www.apple.com/safari/download/">Safari</a></li>
<li style="display: inline;"><a href="http://www.mozilla.com/en-US/firefox/">Firefox</a></li>
<li style="display: inline;"><a href="http://www.google.com/chrome/">Chrome</a></li>
<li style="display: inline;"><a href="http://www.opera.com/download/">Opera</a></li>
<li style="display: inline;"><a href="http://www.microsoft.com/windows/downloads/ie/getitnow.mspx">Internet Explorer</a></li>
</ul>
</div>
</div>
</noscript>
</div>
</body>
</html>
+18
View File
@@ -0,0 +1,18 @@
/*
* AppController.j
* CursorTest
*
* Created by You on November 6, 2009.
* Copyright 2009, Your Company All rights reserved.
*/
@import <Foundation/Foundation.j>
@import <AppKit/AppKit.j>
@import "AppController.j"
function main(args, namedArgs)
{
CPApplicationMain(args, namedArgs);
}
+146
View File
@@ -0,0 +1,146 @@
/*
* AppController.j
*
* Created by __Me__ on __Date__.
* Copyright 2008 __MyCompanyName__. All rights reserved.
*/
@import <Foundation/Foundation.j>
@import <AppKit/AppKit.j>
var categories = ["firstName","lastName"];
@implementation AppController : CPObject
{
var searchField;
var table;
var tableArray;
var filteredArray;
var searchCategoryIndex;
}
- (void)applicationDidFinishLaunching:(CPNotification)aNotification
{
searchCategoryIndex = 0;
var theWindow = [[CPWindow alloc] initWithContentRect:CPMakeRect(0,10,500,300) styleMask:CPTitledWindowMask|CPResizableWindowMask],
contentView = [theWindow contentView];
var searchFieldContainer = [[CPView alloc] initWithFrame:CPMakeRect(10,10,220,50)];
[searchFieldContainer setBackgroundColor:[CPColor redColor]];
[searchFieldContainer setAutoresizingMask:CPViewWidthSizable];
searchField = [[CPSearchField alloc] initWithFrame:CPMakeRect(10,10,200,30)];
[searchField setRecentsAutosaveName:"autosave"];
[searchField setTarget:self];
[searchField setAction:@selector(updateFilter:)];
[searchField setAutoresizingMask:CPViewWidthSizable];
var template = [[CPMenu alloc] initWithTitle:@"Search Menu"];
var item;
item = [[CPMenuItem alloc] initWithTitle:@"Search by"
action:nil
keyEquivalent:@""];
[item setEnabled:NO];
[template addItem:item];
item = [[CPMenuItem alloc] initWithTitle:@"First Name"
action:@selector(changeCategory:)
keyEquivalent:@""];
[item setTarget:self];
[item setTag:1];
[template addItem:item];
item = [[CPMenuItem alloc] initWithTitle:@"Last Name"
action:@selector(changeCategory:)
keyEquivalent:@""];
[item setTarget:self];
[item setTag:2];
[template addItem:item];
item = [[CPMenuItem alloc] initWithTitle:@"Recent searches" action:NULL keyEquivalent:@""];
[item setTag:CPSearchFieldRecentsTitleMenuItemTag];
[template addItem:item];
item = [[CPMenuItem alloc] initWithTitle:@"" action:NULL keyEquivalent:@""];
[item setTag:CPSearchFieldRecentsMenuItemTag];
[template addItem:item];
item = [[CPMenuItem alloc] initWithTitle:@"Clear recents" action:NULL keyEquivalent:@""];
[item setTag:CPSearchFieldClearRecentsMenuItemTag];
[template addItem:item];
[searchField setSearchMenuTemplate:template];
[searchFieldContainer addSubview:searchField];
[contentView addSubview:searchFieldContainer];
tableArray = [CPArray arrayWithObjects:
[CPDictionary dictionaryWithObjects:["Jimmy","McNulty",46] forKeys:["firstName","lastName","age"]],
[CPDictionary dictionaryWithObjects:["Kima","Greggs",41] forKeys:["firstName","lastName","age"]],
[CPDictionary dictionaryWithObjects:["Lester","Freamon",57] forKeys:["firstName","lastName","age"]],
[CPDictionary dictionaryWithObjects:["Kevin ","Russel",37] forKeys:["firstName","lastName","age"]],
[CPDictionary dictionaryWithObjects:["William","Moreland",53] forKeys:["firstName","lastName","age"]],
[CPDictionary dictionaryWithObjects:["Cedric","Daniels",47] forKeys:["firstName","lastName","age"]],
[CPDictionary dictionaryWithObjects:["Roland","Pryzbylewski",27] forKeys:["firstName","lastName","age"]],
[CPDictionary dictionaryWithObjects:["Omar","Little",29] forKeys:["firstName","lastName","age"]],
[CPDictionary dictionaryWithObjects:["Avon","Barkstale",49] forKeys:["firstName","lastName","age"]],
nil];
filteredArray = tableArray;
table = [[CPTableView alloc] initWithFrame:CPMakeRect(10,60,300,300)];
[table setUsesAlternatingRowBackgroundColors:YES];
var colone = [[CPTableColumn alloc] initWithIdentifier:@"firstName"];
[colone setWidth:150];
[table addTableColumn:colone];
var coltwo = [[CPTableColumn alloc] initWithIdentifier:@"lastName"];
[coltwo setWidth:150];
[table addTableColumn:coltwo];
[table setDataSource:self];
[contentView addSubview:table];
[self changeCategory:[[searchField menu] itemAtIndex:1]];
[self updateFilter:nil];
[theWindow center];
[theWindow orderFront:self];
}
- (int)numberOfRowsInTableView:(CPTableView)aTableView
{
return [filteredArray count];
}
- (id)tableView:(CPTableView)aTableView objectValueForTableColumn:(CPTableColumn)aTableColumn row:(int)rowIndex
{
return [filteredArray[rowIndex] objectForKey:[aTableColumn identifier]];
}
- (void)changeCategory:(CPMenuItem)menuItem
{
[[[searchField menu] itemArray] makeObjectsPerformSelector:@selector(setState:) withObject:0];
[menuItem setState:1];
searchCategoryIndex = [menuItem tag] - 1;
[searchField setPlaceholderString:[menuItem title]];
}
- (void)updateFilter:(id)sender
{
var searchString = [searchField stringValue];
filteredArray = [self filteredArrayWithString:searchString];
[table reloadData];
}
- (CPArray)filteredArrayWithString:(CPString)string
{
var keyPath = categories[searchCategoryIndex];
CPLogConsole("Filter the table here. Predicate would be *" + keyPath + " CONTAINS '" + string + "'*");
return tableArray;
}
@end
+12
View File
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CPApplicationDelegateClass</key>
<string>AppController</string>
<key>CPBundleName</key>
<string>Hello World</string>
<key>CPPrincipalClass</key>
<string>CPApplication</string>
</dict>
</plist>
+82
View File
@@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns = "http://www.w3.org/1999/xhtml" xml:lang = "en" lang = "en">
<!--
index-debug.html
Untitled
Created by You on July 30, 2009.
Copyright 2009, Your Company All rights reserved.
-->
<head>
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
<title>Untitled</title>
<script type = "text/javascript">
OBJJ_MAIN_FILE = "main.j";
OBJJ_INCLUDE_PATHS = ["Frameworks/Debug", "Frameworks", "SomethingElse"];
</script>
<script src = "Frameworks/Debug/Objective-J/Objective-J.js" type = "text/javascript"></script>
<script type = "text/javascript">
// DEBUG OPTIONS:
// Uncomment to enable printing of backtraces on exceptions:
objj_msgSend_decorate(objj_backtrace_decorator);
// Uncomment to enable runtime type checking:
objj_msgSend_decorate(objj_typecheck_decorator);
// Uncomment (along with both above) to print backtraces on type check errors:
objj_typecheck_prints_backtrace = true;
</script>
<style type = "text/css">
body{margin:0; padding:0;}
#container {position: absolute; top:50%; left:50%;}
#content {width:800px; text-align:center; margin-left: -400px; height:50px; margin-top:-25px; line-height: 50px;}
#content {font-family: "Helvetica", "Arial", sans-serif; font-size: 18px; color: black; text-shadow: 0px 1px 0px white; }
#loadgraphic {margin-right: 0.2em; margin-bottom:-2px;}
</style>
<!--[if lt IE 7]>
<STYLE type="text/css">
#container { position: relative; top: 50%; }
#content { position: relative;}
</STYLE>
<![endif]-->
</head>
<body style="">
<div id="loadingcontainer" style=" background-color: #eeeeee; overflow:hidden; width:100%; height:100%; position: absolute; top: 0; left: 0;">
<script type = "text/javascript">
document.write("<div id='container'><p id='content'>" +
"<img id='loadgraphic' width='16' height='16' src='Resources/spinner.gif' /> " +
"Loading Untitled...</p></div>");
</script>
<noscript>
<div id="container">
<div style="width: 440px; padding: 10px 25px 20px 25px; font-family: sans-serif; background-color: #ffffff; position: relative; left: -245px; top: -120px; text-align: center; -moz-border-radius: 20px; -webkit-border-radius: 20px; color: #555555">
<p style="line-height: 1.4em;">JavaScript is required for this site to work correctly but is either disabled or not supported by your browser.</p>
<p style="font-size:120%; padding:10px;"><a href="http://cappuccino.org/noscript">Show me how to enable JavaScript</a></p>
<p style="font-size:80%;">You may want to upgrade to a newer browser while you're at it:</p>
<ul style="margin:0;padding:0; text-align: center; font-size:80%;" >
<li style="display: inline;"><a href="http://www.apple.com/safari/download/">Safari</a></li>
<li style="display: inline;"><a href="http://www.mozilla.com/en-US/firefox/">Firefox</a></li>
<li style="display: inline;"><a href="http://www.google.com/chrome/">Chrome</a></li>
<li style="display: inline;"><a href="http://www.opera.com/download/">Opera</a></li>
<li style="display: inline;"><a href="http://www.microsoft.com/windows/downloads/ie/getitnow.mspx">Internet Explorer</a></li>
</ul>
</div>
</div>
</noscript>
</div>
</body>
</html>
+36
View File
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns = "http://www.w3.org/1999/xhtml" xml:lang = "en" lang = "en">
<!--
//
// index.html
//
// Created by __Me__ on __Date__.
// Copyright 2008 __MyCompanyName__. All rights reserved.
//
-->
<head>
<title>CPSearchField Demo</title>
<script type = "text/javascript">
OBJJ_MAIN_FILE = "main.j";
</script>
<script src = "Frameworks/Objective-J/Objective-J.js" type = "text/javascript"></script>
</head>
<body>
<div style="position: absolute; left: 50%; top: 50%;">
<center>
<img src = "Frameworks/AppKit/Resources/CPProgressIndicator/CPProgressIndicatorSpinningStyleRegular.gif" style="left: -32px; position: relative; top: -32px;" />
</center>
</div>
</body>
</html>
+17
View File
@@ -0,0 +1,17 @@
/*
* main.j
*
* Created by __Me__ on __Date__.
* Copyright 2008 __MyCompanyName__. All rights reserved.
*/
@import <Foundation/Foundation.j>
@import <AppKit/AppKit.j>
@import "AppController.j"
function main(args, namedArgs)
{
CPApplicationMain(args, namedArgs);
}
+38
View File
@@ -25,4 +25,42 @@
[self assert:middle equals:[middle laterDate:past] message:"laterDate incorrect"];
}
- (void)testInitWithString
{
var tests = [
["1970-01-01 00:00:00 +0000", 0],
["1970-01-01 00:01:00 +0000", 60],
["1970-01-01 01:00:00 +0000", 60*60],
["1970-01-02 00:00:00 +0000", 24*60*60],
["2009-11-17 17:52:04 +0000", 1258480324],
];
for (var i = 0; i < tests.length; i++)
{
var parsed = [[CPDate alloc] initWithString:tests[i][0]];
var correctSeconds = tests[i][1];
[self assert:correctSeconds equals:[parsed timeIntervalSince1970]];
}
}
- (void)testEncoding
{
var date = new Date(),
encodedDate = [CPKeyedArchiver archivedDataWithRootObject:date],
decodedDate = [CPKeyedUnarchiver unarchiveObjectWithData:encodedDate];
[self assert:date equals:decodedDate];
}
- (void)testDescription
{
// Unfortunately the result will be different depending on the testing machine's timezone.
var expectedHour = 23
var expectedMinute = 31;
var offsetHours = Math.floor(new Date().getTimezoneOffset() / 60);
var offsetMinutes = new Date().getTimezoneOffset() - offsetHours * 60;
var expectedString = [CPString stringWithFormat:"2009-02-13 %02d:%02d:30 +%02d%02d", expectedHour-offsetHours, expectedMinute-offsetMinutes, offsetHours, offsetMinutes];
[self assert:expectedString equals: [[CPDate dateWithTimeIntervalSince1970: 1234567890] description]];
}
@end
+59
View File
@@ -0,0 +1,59 @@
@import <Foundation/CPSet.j>
@implementation CPSetTest : OJTestCase
{
CPSet set;
}
- (void)setUp
{
set = [CPSet new];
}
- (void)testAddObject
{
[self assertFalse:[set containsObject:"foo"]];
[set addObject:"foo"];
[self assertTrue:[set containsObject:"foo"]];
}
- (void)testAddZeroObject
{
[self assertFalse:[set containsObject:0]];
[set addObject:0];
[self assertTrue:[set containsObject:0]];
}
- (void)testRemoveObject
{
[set addObject:"foo"];
[self assertTrue:[set containsObject:"foo"]];
[set removeObject:"foo"];
[self assertFalse:[set containsObject:"foo"]];
}
- (void)testRemoveZeroObject
{
[set addObject:0];
[self assertTrue:[set containsObject:0]];
[set removeObject:0];
[self assertFalse:[set containsObject:0]];
}
- (void)testAddNilObject
{
[self assertFalse:[set containsObject:nil]];
[set addObject:nil];
[self assertFalse:[set containsObject:nil]];
}
- (void)testRemoveNilObject
{
[set addObject:nil];
[self assertFalse:[set containsObject:nil]];
[set removeObject:nil];
[self assertFalse:[set containsObject:nil]];
}
@end
+26
View File
@@ -151,6 +151,32 @@
[self assert:[testStrings[i][0] boolValue] equals:testStrings[i][1]];
}
- (void)testCommonPrefixWithString
{
var testStringsCase = [
["Hello", "Helicopter", "Hel"],
["Tester", "Taser", "T"],
["Abcd", "Abcd", "Abcd"],
["A long string", "A longer string", "A long"]
];
var testStringsCaseless = [
["hElLo", "HeLiCoPtEr", "hEl"],
["tEsTeR", "TaSeR", "t"],
["aBcD", "AbCd", "aBcD"],
["a LoNg StRiNg", "A lOnGeR sTrInG", "a LoNg"]
];
for (var i = 0; i < testStringsCase.length; i++)
[self assert: [testStringsCase[i][0] commonPrefixWithString:testStringsCase[i][1]]
equals: testStringsCase[i][2]];
for (var i = 0; i < testStringsCaseless.length; i++)
[self assert: [testStringsCaseless[i][0] commonPrefixWithString: testStringsCaseless[i][1]
options: CPCaseInsensitiveSearch]
equals: testStringsCaseless[i][2]];
}
- (void)testCapitalizedString
{
var testStrings = [
-676
View File
@@ -1,676 +0,0 @@
if (typeof debug == "undefined")
debug = false;
//window
if (!this.window)
this.window = this;
// DOMParser
/*function DOMParser() {};
DOMParser.prototype.parseFromString = function(text, contentType) {
return new DOMDocument(
new Packages.org.xml.sax.InputSource(
new Packages.java.io.StringReader(text)));
};*/
// Image
function Image() { }
// print, alert, prompt, confirm
if (!this.print)
{
if (this.Packages)
{
this.print = function(object)
{
Packages.java.lang.System.out.println(String(object));
}
}
}
window.alert = function(obj)
{
if (this.print)
print(String(obj));
}
// FIXME: prompt user for response?
window.confirm = function(obj)
{
window.alert(obj);
return true;
}
window.prompt = function(obj)
{
window.alert(obj);
return "";
}
// setTimeout, setInterval, clearTimeout, clearInterval
// This implementation is single-threaded (like browsers) but requires a call to serviceTimeouts()
// Also includes beginning of a multithreaded implementation (commented out)
window.setNativeTimeout = function(callback, delay)
{
return _scheduleTimeout(callback, delay, false);
}
window.setTimeout = window.setNativeTimeout;
window.setNativeInterval = function(callback, delay)
{
return _scheduleTimeout(callback, delay, true);
}
window.setInterval = window.setInterval;
window.clearTimeout = function(id)
{
if (_timeouts[id])
_timeouts[id] = null;
}
window.clearInterval = window.clearTimeout;
var _nextId = 0,
_timeouts = {},
_pendingTimeouts = [];
var _scheduleTimeout = function(callback, delay, repeat)
{
var date = new Date(new Date().getTime() + delay);
if (typeof callback == "function")
var func = callback;
else if (typeof callback == "string")
var func = new Function(callback);
else
return;
var timeout = {
callback: func,
date: date,
repeat: repeat,
interval: delay,
id : _nextId++
}
_timeouts[timeout.id] = timeout;
_pendingTimeouts.push(timeout);
// if (!_timersBlock)
// serviceTimeouts();
return timeout.id;
}
var _sortTimeouts = function()
{
}
//var _timersBlock = false,
// _timerThread = null,
// _nextTimeout = null;
function serviceTimeouts()
{
while (_pendingTimeouts.length > 0)
{
_pendingTimeouts = _pendingTimeouts.sort(function (a,b) { return a.date - b.date; });
var timeout = _pendingTimeouts.shift();
if (_timeouts[timeout.id])
{
var wait = timeout.date - new Date();
if (wait > 0)
{
//if (_timersBlock)
//{
Packages.java.lang.Thread.sleep(wait);
//}
//else
//{
// _pendingTimeouts.splice(0, 0, timeout);
//
// if (!_nextTimeout || _nextTimeout > timeout.date)
// {
// _nextTimeout = timeout.date;
//
//
// _timerThread = new java.lang.Thread(new java.lang.Runnable({
// run: function() {
// Packages.java.lang.Thread.sleep(wait);
// _nextTimeout = null;
// serviceTimeouts();
// }
// }));
//
// _timerThread.start();
// }
//
// return;
//}
}
// perform the callback
timeout.callback();
// if its an interval, reschedule it, otherwise clear it
if (timeout.repeat)
{
var now = new Date(),
proposed = new Date(timeout.date.getTime() + timeout.interval);
timeout.date = (proposed < now) ? now : proposed;
_pendingTimeouts.push(timeout);
}
else
_timeouts[timeout.id] = null;
}
}
}
// load
if (!this.load)
{
if (debug)
alert("Setting up 'load()'");
this.load = function(path)
{
var contents = readFile(path);
if (typeof Packages !== "undefined")
return Packages.org.mozilla.javascript.Context.getCurrentContext().evaluateString(window, contents, path, 0, null);
else
return eval(contents);
}
}
// readFile
if (!this.readFile)
{
if (this.File)
{
if (debug)
alert("Setting up 'readFile()' for SpiderMonkey");
this.readFile = function(path)
{
var f = new File(path);
if (!f.canRead)
{
if (debug)
alert("can't read: " + f.path);
return "";
}
if (debug)
alert("reading: " + f.path);
f.open("read", "text");
var result = f.readAll().join("\n");
f.close();
return result;
}
}
else if (this.Packages)
{
if (debug)
alert("Setting up 'readFile()' for Rhino");
this.readFile = function(path, characterCoding)
{
var f = new Packages.java.io.File(path);
if (!f.canRead())
{
if (debug)
alert("can't read: " + f.path);
return "";
}
if (debug)
alert("reading: " + f.getAbsolutePath());
var fis = new Packages.java.io.FileInputStream(f),
b = Packages.java.lang.reflect.Array.newInstance(Packages.java.lang.Byte.TYPE, fis.available());
fis.read(b);
fis.close();
if (characterCoding)
return String(new Packages.java.lang.String(b, characterCoding));
else
return String(new Packages.java.lang.String(b));
}
}
else
{
alert("Warning: No 'readFile' implementation available.")
}
}
var hex_lookup = "0123456789abcdef";
function bytesToHexString(buf)
{
var buffer = "";
for (var i = 0 ; i < buf.length; i++)
buffer += hex_lookup[(buf[i] >> 4) & 0x0F] + hex_lookup[buf[i] & 0x0F];
return buffer;
}
// Rhino utilities
if (this.Packages) {
if (debug)
alert("Setting up Rhino utilties");
jsArrayToJavaArray = function(js_array, type)
{
var java_class = null;
var java_converter = null;
switch (type || ((js_array && js_array.length > 0) && typeof js_array[0]))
{
case "string":
case "String":
java_class = Packages.java.lang.String;
java_converter = Packages.java.lang.String.valueOf;
break;
case "Boolean":
java_class = Packages.java.lang.Boolean;
java_converter = Packages.java.lang.Boolean.valueOf;
break;
case "boolean":
java_class = Packages.java.lang.Boolean.TYPE;
java_converter = function(input) { return Packages.java.lang.Boolean.valueOf(input).booleanValue(); };
break;
default:
return null;
}
if (js_array && js_array.length > 0)
{
var java_array = Packages.java.lang.reflect.Array.newInstance(java_class, js_array.length);
for (var i = 0; i < js_array.length; i++)
java_array[i] = java_converter ? java_converter(js_array[i]) : js_array[i];
return java_array;
}
return Packages.java.lang.reflect.Array.newInstance(java_class, 0);
}
jsObjectToJavaHashMap = function(js_object)
{
var map = Packages.java.util.HashMap();
for (var i in js_object)
map.put(i, js_object[i]);
return map;
}
objj_console = function()
{
var br = new Packages.java.io.BufferedReader(new Packages.java.io.InputStreamReader(Packages.java.lang.System["in"], "UTF-8"));
keepgoing = true;
while (keepgoing)
{
try {
Packages.java.lang.System.out.print("objj> ");
var input = String(br.readLine()),
fragments = objj_preprocess(input, new objj_bundle(), new objj_file(), OBJJ_PREPROCESSOR_DEBUG_SYMBOLS),
count = fragments.length,
ctx = (new objj_context);
if (count == 1 && (fragments[0].type & FRAGMENT_CODE))
{
var fragment = fragments[0];
var result = eval(fragment.info);
if (result != undefined)
print(result);
}
else if (count > 0)
{
while (count--)
{
var fragment = fragments[count];
if (fragment.type & FRAGMENT_FILE)
objj_request_file(fragment.info, (fragment.type & FRAGMENT_LOCAL), NULL);
ctx.pushFragment(fragment);
}
ctx.schedule();
}
serviceTimeouts();
} catch (e) {
print(e);
}
}
};
var _documentBuilderFactory = Packages.javax.xml.parsers.DocumentBuilderFactory.newInstance();
// setValidating to false doesn't seem to prevent it from downloading the DTD, but lets do it anyway
_documentBuilderFactory.setValidating(false);
_documentBuilder = _documentBuilderFactory.newDocumentBuilder();
// prevent the Java XML parser from downloading the plist DTD from Apple every time we parse a plist
_documentBuilder.setEntityResolver(new Packages.org.xml.sax.EntityResolver({
resolveEntity: function(publicId, systemId) {
//Packages.java.lang.System.out.println("publicId=" + publicId + " systemId=" + systemId);
// TODO: return a local copy of the DTD?
if (String(systemId) == "http://www.apple.com/DTDs/PropertyList-1.0.dtd")
return new Packages.org.xml.sax.InputSource(new Packages.java.io.StringReader(""));
return null;
}
}));
// throw an exception on error
_documentBuilder.setErrorHandler(function(exception, methodName) {
throw exception;
});
copyInputStreamToOutputStream = function(is, os)
{
var buf = Packages.java.lang.reflect.Array.newInstance(Packages.java.lang.Byte.TYPE, 1024*10);
var len = 0;
while ((len = is.read(buf)) != -1)
{
os.write(buf, 0, len);
}
}
var lineEnd = "\r\n";
var twoHyphens = "--";
var boundary = "----------------------------b453b5d52446";
//var boundary = "----CappuccinoBoundary" + (new Date().getTime());
multipartRequest = function(method, url, headers, parts)
{
var bufferSize = 1024*10,
buffer = Packages.java.lang.reflect.Array.newInstance(Packages.java.lang.Byte.TYPE, bufferSize);
var url = new Packages.java.net.URL(url),
connection = url.openConnection();
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setRequestMethod(method);
for (var i in headers)
{
print(i+":"+headers[i]);
connection.setRequestProperty(i, headers[i]);
}
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary="+ boundary);
var output = new Packages.java.io.DataOutputStream(connection.getOutputStream());
for (var i = 0; parts && i < parts.length; i++)
{
var part = parts[i];
output.writeBytes(twoHyphens + boundary + lineEnd);
if (part.headers)
{
for (var header in part.headers)
{
output.writeBytes(header +": " + part.headers[header] + lineEnd);
}
}
output.writeBytes(lineEnd);
if (part.data)
{
output.writeBytes(part.data);
}
else if (part.stream)
{
var n;
while ((n = part.stream.read(buffer, 0, bufferSize)) > 0)
{
output.write(buffer, 0, n)
}
}
output.writeBytes(lineEnd);
}
output.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
output.flush();
output.close();
var buffer,
input = new Packages.java.io.DataInputStream(connection.getInputStream()),
result = new Packages.java.lang.StringBuffer();
while (null != (buffer = input.readLine()))
result.append(buffer);
input.close();
return String(result.toString());
}
parseXMLString = function(string) {
return (_documentBuilder.parse(
new Packages.org.xml.sax.InputSource(
new Packages.java.io.StringReader(string))).getDocumentElement());
}
}
// Environment variables
function getenv(variable)
{
if (this.Packages)
return String(Packages.java.lang.System.getenv().get(variable) || "") || null;
else if (this.environment)
return environment[variable] || null;
return null;
}
// XMLHttpRequest
function XMLHttpRequest()
{
this.readyState = 0;
this.responseText = "";
this.responseXML = null;
this.status = null;
this.statusText = null;
this.onreadystatechange = null;
this.method = null;
this.url = null;
this.async = null;
this.username = null;
this.password = null;
}
XMLHttpRequest.prototype.abort = function()
{
this.readyState = 0;
}
XMLHttpRequest.prototype.open = function(method, url, async, username, password)
{
this.readyState = 1;
this.method = method;
this.url = url;
this.async = async;
this.username = username;
this.password = password;
}
XMLHttpRequest.prototype.send = function(body)
{
this.readyState = 3;
this.responseText = "";
this.responseXML = null;
try
{
this.responseText = readFile(this.url, "UTF-8"); // FIXME: should we really assume this is UTF-8?
if (debug)
alert("xhr response: " + this.url + " (length="+this.responseText.length+")");
}
catch (e)
{
if (debug)
alert("xhr exception: " + this.url);
this.responseText = "";
this.responseXML = null;
}
if (this.responseText.length > 0)
{
try
{
this.responseXML = _documentBuilder.parse(new Packages.org.xml.sax.InputSource(new Packages.java.io.StringReader(this.responseText)));
}
catch (e)
{
this.responseXML = null;
}
this.status = 200;
}
else {
if (debug)
alert("xhr empty: " + this.url);
this.status = 404;
}
this.readyState = 4;
if (this.onreadystatechange)
{
if (this.async)
setNativeTimeout(this.onreadystatechange, 0);
else
this.onreadystatechange();
}
}
XMLHttpRequest.prototype.getResponseHeader = function(header)
{
return (this.readyState < 3) ? "" : "";
}
XMLHttpRequest.prototype.getAllResponseHeaders = function()
{
return (this.readyState < 3) ? null : "";
}
XMLHttpRequest.prototype.setRequestHeader = function(name, value)
{
}
objj_request_xmlhttp = function()
{
return new XMLHttpRequest();
}
OBJJ_HOME = getenv("OBJJ_HOME");
if (!OBJJ_HOME)
{
OBJJ_HOME = "/usr/local/share/objj";
alert("OBJJ_HOME environment variable not set, defaulting to " + OBJJ_HOME);
}
function exec(/*Array*/ command, /*Boolean*/ showOutput)
{
var line = "",
output = "",
process = Packages.java.lang.Runtime.getRuntime().exec(command),//jsArrayToJavaArray(command));
reader = new Packages.java.io.BufferedReader(new Packages.java.io.InputStreamReader(process.getInputStream()));
while (line = reader.readLine())
{
if (showOutput)
Packages.java.lang.System.out.println(line);
output += line + '\n';
}
reader = new Packages.java.io.BufferedReader(new Packages.java.io.InputStreamReader(process.getErrorStream()));
while (line = reader.readLine())
Packages.java.lang.System.out.println(line);
try
{
if (process.waitFor() != 0)
Packages.java.lang.System.err.println("exit value = " + process.exitValue());
}
catch (anException)
{
Packages.java.lang.System.err.println(anException);
}
return output;
}
function getFiles(/*File*/ sourceDirectory, /*nil|String|Array<String>*/ extensions, /*Array*/ exclusions)
{
var matches = [],
files = sourceDirectory.listFiles(),
hasMultipleExtensions = typeof extensions !== "string";
if (files)
{
var index = 0,
count = files.length;
for (; index < count; ++index)
{
var file = files[index].getCanonicalFile(),
name = String(file.getName()),
isValidExtension = !extensions;
if (exclusions && fileArrayContainsFile(exclusions, file))
continue;
if (!isValidExtension)
if (hasMultipleExtensions)
{
var extensionCount = extensions.length;
while (extensionCount-- && !isValidExtension)
{
var extension = extensions[extensionCount];
if (name.substring(name.length - extension.length - 1) === ("." + extension))
isValidExtension = true;
}
}
else if (name.substring(name.length - extensions.length - 1) === ("." + extensions))
isValidExtension = true;
if (isValidExtension)
matches.push(file);
if (file.isDirectory())
matches = matches.concat(getFiles(file, extensions, exclusions));
}
}
return matches;
}
-131
View File
@@ -1,131 +0,0 @@
function readContentsOfFile(/*File*/ aFile)
{
var reader = new BufferedReader(new FileReader(aFile)),
fileContents = "";
// Get contents of the file
while (reader.ready())
fileContents += reader.readLine() + '\n';
reader.close();
return fileContents;
}
function writeContentsToFile(/*String*/ contents, /*File*/ aFile)
{
var writer = new BufferedWriter(new FileWriter(aFile));
writer.write(contents);
writer.close();
}
function readPlist(/*File*/ aFile)
{
var fileContents = readFile(aFile);
var data = new objj_data();
data.string = fileContents;
return new CPPropertyListCreateFromData(data);
}
function readBundle(/*File*/ aFile, /*Boolean*/ shouldDecompile)
{
var bundlePath = typeof aFile === "string" ? new File(aFile).getCanonicalPath() : aFile.getCanonicalPath(),
infoPath = bundlePath + "/Info.plist";
//err
var bundle = new objj_bundle();
bundle.path = infoPath;
bundle.info = readPlist(infoPath);
bundle._staticFilePaths = dictionary_getValue(bundle.info, "CPBundleReplacedFiles");
if (bundle._staticFilePaths.length)
{
bundle._staticContentPath = staticContentPath = bundlePath + '/' + dictionary_getValue(bundle.info, "CPBundleExecutable");
//err
bundle._staticContent = readFile(staticContentPath);
if (shouldDecompile)
bundle.files = objj_decompile(bundle._staticContent, bundle);
}
else
bundle._staticContent = "";
return bundle;
}
function importFiles(files, aCallback)
{
if (files.length === 0)
aCallback();
else
{
var file = files.shift();
if (typeof file === "string")
file = new File(file);
objj_import(file.getCanonicalPath(), YES, function() { importFiles(files, aCallback) });
}
return;
var context = new objj_context();
if (aCallback)
context.didCompleteCallback = aCallback;
var count = files.length;
while (count--)
{
var file = files[count];
if (typeof file === "string")
file = new File(file);
context.pushFragment(fragment_create_file(file, new objj_bundle(""), YES, NULL));
}
context.evaluate();
}
function loadFrameworks(frameworkPaths, aCallback)
{
if (frameworkPaths.length === 0)
return aCallback();
var frameworkPath = frameworkPaths.shift(),
infoPlist = new File(frameworkPath + "/Info.plist");
if (!infoPlist.exists())
{
java.lang.System.out.println("'" + frameworkPath + "' is not a framework or could not be found.");
java.lang.System.exit(1);
}
var infoDictionary = readPlist(new File(frameworkPath + "/Info.plist"));
if (dictionary_getValue(infoDictionary, "CPBundlePackageType") !== "FMWK")
{
java.lang.System.out.println("'" + frameworkPath + "' is not a framework .");
java.lang.System.exit(1);
}
var files = dictionary_getValue(infoDictionary, "CPBundleReplacedFiles"),
index = 0,
count = files.length;
for (; index < count; ++index)
files[index] = String(frameworkPath + '/' + files[index]);
importFiles(files, function() { loadFrameworks(frameworkPaths, aCallback) });
}
-99
View File
@@ -1,99 +0,0 @@
function readFile(/*File*/ aFile)
{
var reader = new BufferedReader(new FileReader(aFile)),
fileContents = "";
// Get contents of the file
while (reader.ready())
fileContents += reader.readLine() + '\n';
reader.close();
return fileContents;
}
function writeContentsToFile(/*String*/ contents, /*File*/ aFile)
{
}
function readPlist(/*File*/ aFile)
{
var fileContents = readFile(aFile);
var data = new objj_data();
data.string = fileContents;
return new CPPropertyListCreateFromData(data);
}
function importFiles(files, aCallback)
{
if (files.length === 0)
aCallback();
else
{
var file = files.shift();
if (typeof file === "string")
file = new File(file);
objj_import(String(file.getCanonicalPath()), YES, function() { importFiles(files, aCallback) });
}
return;
var context = new objj_context();
if (aCallback)
context.didCompleteCallback = aCallback;
var count = files.length;
while (count--)
{
var file = files[count];
if (typeof file === "string")
file = new File(file);
context.pushFragment(fragment_create_file(file, new objj_bundle(""), YES, NULL));
}
context.evaluate();
}
function loadFrameworks(frameworkPaths, aCallback)
{
if (frameworkPaths.length === 0)
return aCallback();
var frameworkPath = frameworkPaths.shift(),
infoPlist = new File(frameworkPath + "/Info.plist");
if (!infoPlist.exists())
{
java.lang.System.out.println("'" + frameworkPath + "' is not a framework or could not be found.");
java.lang.System.exit(1);
}
var infoDictionary = readPlist(new File(frameworkPath + "/Info.plist"));
if (dictionary_getValue(infoDictionary, "CPBundlePackageType") !== "FMWK")
{
java.lang.System.out.println("'" + frameworkPath + "' is not a framework .");
java.lang.System.exit(1);
}
var files = dictionary_getValue(infoDictionary, "CPBundleReplacedFiles"),
index = 0,
count = files.length;
for (; index < count; ++index)
files[index] = String(frameworkPath + '/' + files[index]);
importFiles(files, function() { loadFrameworks(frameworkPaths, aCallback) });
}
Binary file not shown.
-41
View File
@@ -1,41 +0,0 @@
#!/usr/bin/env ruby
require 'rake'
require '../../common'
require 'objective-j'
require 'objective-j/bundletask'
$PRODUCT = :bake
$BUILD_PATH = File.join($BUILD_DIR, $CONFIGURATION, 'bake')
$ENVIRONMENT_BIN_PRODUCT = File.join($ENVIRONMENT_BIN_DIR, 'bake')
$ENVIRONMENT_LIB_PRODUCT = File.join($ENVIRONMENT_LIB_DIR, 'bake')
# Debug Framework
ObjectiveJ::BundleTask.new(:bake) do |t|
t.name = 'bake'
t.identifier = 'com.280n.bake'
t.version = '0.7.1'
t.author = '280 North, Inc.'
t.email = 'feedback @nospam@ 280north.com'
t.summary = 'Deployment tool for Cappuccino applications'
t.sources = FileList['*.j']
t.resources = FileList['Resources/*']
t.license = ObjectiveJ::License::LGPL_v2_1
t.build_path = $BUILD_PATH
t.flag = '-DDEBUG' if $CONFIGURATION == 'Debug'
t.flag = '-O' if $CONFIGURATION == 'Release'
end
#executable in environment directory
file_d $ENVIRONMENT_BIN_PRODUCT do
make_objj_executable($ENVIRONMENT_BIN_PRODUCT)
end
file_d $ENVIRONMENT_LIB_PRODUCT => [:bake] do
cp_r(File.join($BUILD_PATH, '.'), $ENVIRONMENT_LIB_PRODUCT)
end
task :build => [:bake, $ENVIRONMENT_BIN_PRODUCT, $ENVIRONMENT_LIB_PRODUCT]
CLOBBER.include($ENVIRONMENT_BIN_PRODUCT, $ENVIRONMENT_LIB_PRODUCT)
-57
View File
@@ -1,57 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns = "http://www.w3.org/1999/xhtml" xml:lang = "en" lang = "en">
<!--
//
// index.html
//
// $APPLICATION_NAME
//
// Copyright 2005 - 2008, 280 North, Inc. All rights reserved.
//
-->
<head>
<title>$APPLICATION_NAME</title>
<script type = "text/javascript" charset = "utf-8" >
//create a new timestamp to monitor launch time
_LAUNCH_TIME = new Date();
OBJJ_MAIN_FILE = "main.j";
window.files_total = $FILES_TOTAL;
window.update_progress = function(percent)
{
var value = Math.max(Math.min(Math.round(percent*100), 100), 0);
var progress = document.getElementById("progress");
if (progress)
progress.style.width = value + "%";
window.title = "Loading $APPLICATION_NAME... " + value + "%";
}
var path = document.location.href;
path = path.substr(0, path.lastIndexOf('/') + 1);
document.write("<base href=\"" + path + "$VERSION/" + "\"><!--[if IE]><"+"/base><![endif]-->");
</script>
<script src = "Frameworks/Objective-J/Objective-J.js" type = "text/javascript" charset = "utf-8"></script>
</head>
<body style="background-color: $BACKGROUND_COLOR;">
<div style="position: absolute; top: 50%; left: 50%; min-height: 100px; width: 250px; margin-top: -50px; margin-left: -125px; padding: 10px; background-color: white; text-align: center; -moz-border-radius: 5px; -webkit-border-radius: 5px;">
<img src="Resources/spinner.gif" />
<div style="height: 3px; width: 100%; left: 0px; top: 0px; background-color: lightgrey; overflow: hidden;">
<div id="progress" style="height: 100%; width: 0%; left: 0px; top: 0px; background-color: black; margin-right: auto;"></div>
</div>
<h3 style="font-size: 18px; font-family: 'Lucida Grande', Lucida, Verdana, Helvetica, Arial, sans-serif; color: $TEXT_COLOR;">Loading $APPLICATION_NAME...</h3>
</div>
</body>
</html>
-56
View File
@@ -1,56 +0,0 @@
{
"sources" : [
{
"type" : "git",
"path" : "git://github.com/280north/cappuccino.git",
"parts" : [
{
"src" : "Objective-J",
"dst" : "Frameworks/Objective-J",
"build" : "ant -DBuild=BUILD_PATH",
"copyFrom" : "Release/Objective-J"
},
{
"src" : "Foundation",
"dst" : "Frameworks/Foundation",
"build" : "steam build -c Release -b BUILD_PATH",
"copyFrom" : "Release/Foundation"
},
{
"src" : "AppKit",
"dst" : "Frameworks/AppKit",
"build" : "steam build -c Release -b BUILD_PATH",
"copyFrom" : "Release/AppKit"
}
]
},
{
"type" : "rsync",
"path" : "/Users/username/projects/NewApplication",
"parts" : [
{
"src" : "",
"dst" : "Blah"
}
]
},
{
"type" : "svn",
"path" : "https://svn.youserver.com/Project/trunk",
"parts" : [
{
"src" : "subdirectory",
"dst" : "Something"
}
]
}
],
"deployments" : [
{ "host" : "deploy@myserver.com", "path" : "/var/www/mysite/public" }
],
"templateVars" : {
"APPLICATION_NAME" : "My Application",
"BACKGROUND_COLOR" : "black",
"TEXT_COLOR" : "black"
}
}
-299
View File
@@ -1,299 +0,0 @@
@import <Foundation/Foundation.j>
importPackage(Packages.java.io);
var options = {
base : "trunk",
clean : false,
deploy : false,
deployHost : null,
deployPath : null,
skipUpdate : false,
tag : false,
archive : false,
message : null,
templatePath : OBJJ_HOME + "/lib/bake/Resources/bake_template.html"
}
var targetPath,
checkoutsPath,
buildsPath,
productsPath,
version = ROUND(new Date().getTime() / 1000);
CPLogRegister(CPLogPrint);
function readConfig(configFile)
{
var fileData = String(readFile(configFile));
if (!fileData)
throw new Error("Couldn't read file: " + configFile);
var configs = JSON.parse(fileData);
return configs;
}
function update()
{
for (var i = 0; i < options.sources.length; i++)
{
var source = options.sources[i];
source.localSourcePath = checkoutsPath + "/" + source.path.replace(/\W+/g, "_");
switch (source.type)
{
case "git":
if (new File(source.localSourcePath).isDirectory())
{
CPLog.debug("git pull (" + source.localSourcePath + ")");
exec("git pull", null, new File(source.localSourcePath));
}
else
{
CPLog.debug("git clone (" + source.path + ")");
exec(["git", "clone", source.path, source.localSourcePath]);
}
break;
case "svn":
if (new File(source.localSourcePath).isDirectory())
{
CPLog.debug("svn up (" + source.localSourcePath + ")");
exec("svn up", null, new File(source.localSourcePath));
}
else
{
CPLog.debug("svn co (" + source.path + ")");
exec(["svn", "co", source.path, source.localSourcePath]);
}
break;
case "rsync":
CPLog.debug("rsync (" + source.localSourcePath + ")");
exec(["rsync", "-avz", source.path + "/", source.localSourcePath]);
break;
default :
CPLog.error("Unimplemented: " + source.type);
}
}
}
function build()
{
var versionedPath = productsPath + "/" + version + "/" + version;
for (var i = 0; i < options.sources.length; i++)
{
var source = options.sources[i];
for (var j = 0; j < source.parts.length; j++)
{
var part = source.parts[j];
var fromPath = source.localSourcePath + "/" + part.src;
var toPath = versionedPath + "/" + part.dst;
if (part.build)
{
var buildCommand = part.build.replace("$BUILD_PATH", buildsPath);
CPLog.debug("Building: " + buildCommand);
exec(buildCommand, null, new File(fromPath));
fromPath = buildsPath + "/" + part.copyFrom;
}
mkdirs(toPath);
var rsyncCommand = "rsync -aC " + fromPath + "/. " + toPath;
CPLog.debug("Rsyncing: " + rsyncCommand);
exec(rsyncCommand);
}
}
if (options.press)
{
var tempPath = versionedPath+"-Stripped";
var pressCommand = ["press", versionedPath, tempPath];
if (options.png)
pressCommand.push("--png");
var result = exec(pressCommand);
if (result.code)
throw new Error("press failed");
exec(["rm", "-rf", versionedPath]);
exec(["mv", tempPath, versionedPath]);
}
var results = exec(["bash", "-c", "find "+versionedPath+" \\( -name \"*.sj\" -or -name \"*.j\" \\) -exec cat {} \\; | wc -c | tr -d \" \""]);
var filesTotal = parseInt(results.stdout);
if (isNaN(filesTotal))
filesTotal = 0;
CPLog.debug("FILES_TOTAL=["+filesTotal+"]");
var substitutions = options.templateVars;
substitutions.VERSION = version;
substitutions.FILES_TOTAL = filesTotal;
var template = readFile(options.templatePath);
if (!template)
throw new Error("Couldn't get template");
for (var variable in substitutions)
template = template.replace(new RegExp("\\$" + variable, "g"), substitutions[variable]);
templateBytes = new java.lang.String(template).getBytes();
templateOutput = new FileOutputStream(productsPath + "/" + version + "/index.html");
templateOutput.write(templateBytes, 0, templateBytes.length);
templateOutput.close();
exec(["tar", "czf", version+".tar.gz", version], null, new File(productsPath));
}
function deploy()
{
for (var i = 0; i < options.deployments.length; i++)
{
var dep = options.deployments[i];
exec(["scp", productsPath + "/" + version + ".tar.gz", dep.host + ":~/" + version + ".tar.gz"]);
exec(["ssh", dep.host,
"tar xzf " + version + ".tar.gz; " +
"mkdir -p " + dep.path + "; " +
"mv " + version + "/" + version + "/ " + dep.path + "/" + version + "; " +
"mv " + version + "/index.html " + dep.path + "/index.html; " +
"rm " + version + ".tar.gz; " +
"rmdir " + version + "; " +
"cd " + dep.path + "; " +
"ln -nsf " + version + " Current"]);
}
}
function main()
{
var bakefile = "bakefile",
commandOpts = {};
while (args.length)
{
var arg = args.shift();
switch (arg)
{
case "--base":
commandOpts.base = args.shift();
break;
case "--tag":
commandOpts.tag = true;
break;
case "--archive":
commandOpts.archive = true;
break;
case "--clean":
commandOpts.clean = true;
break;
case "--deploy":
commandOpts.deploy = true;
break;
case "--press":
commandOpts.press = true;
break;
case "--png":
commandOpts.png = true;
break;
case "--host":
commandOpts.deployHost = args.shift();
break;
case "--path":
commandOpts.deployPath = args.shift();
break;
case "--skip-update":
commandOpts.skipUpdate = true
break;
case "--message":
commandOpts.message = args.shift();
break;
default:
bakefile = arg;
}
}
try
{
var configOpts = readConfig(bakefile);
for (var i in configOpts) options[i] = configOpts[i];
for (var i in commandOpts) options[i] = commandOpts[i];
targetPath = pwd() + "/" + bakefile.match(/^[^\.]+/)[0] + ".oven";
mkdirs(targetPath);
checkoutsPath = targetPath + "/Checkouts"
mkdirs(checkoutsPath);
buildsPath = targetPath + "/Build"
mkdirs(buildsPath);
productsPath = targetPath + "/Products"
mkdirs(productsPath);
if (!options.skipUpdate)
{
CPLog.info("Updating");
update();
}
CPLog.info("Building");
build();
if (options.deploy)
{
CPLog.info("Deploying");
deploy();
}
}
catch (e)
{
CPLog.error(e);
}
}
function exec()
{
var runtime = Packages.java.lang.Runtime.getRuntime()
var p = runtime.exec.apply(runtime, arguments);
var stdout = "";
var reader = new Packages.java.io.BufferedReader(new Packages.java.io.InputStreamReader(p.getInputStream()));
while (s = reader.readLine())
{
stdout += s;
CPLog.info("exec: " + s);
}
var stderr = "";
var reader = new Packages.java.io.BufferedReader(new Packages.java.io.InputStreamReader(p.getErrorStream()));
while (s = reader.readLine())
{
stdout += s;
CPLog.warn("exec: " + s);
}
var code = p.waitFor();
return { code : code, stdout : stdout, stderr : stderr };
}
function pwd()
{
return String(new File("").getAbsolutePath());
}
function mkdirs(path)
{
return new File(path).mkdirs();
}
+8 -6
View File
@@ -5,17 +5,19 @@
@import "Generate.j"
function main()
function main(args)
{
if (system.args.length < 1)
args.shift();
if (args.length < 1)
return printUsage();
var index = 0,
count = system.args.length;
count = args.length;
for (; index < count; ++index)
{
var argument = system.args[index];
var argument = args[index];
switch (argument)
{
@@ -25,9 +27,9 @@ function main()
case "-h":
case "--help": return printUsage();
case "config": return config.apply(this, system.args.slice(index + 1));
case "config": return config.apply(this, args.slice(index + 1));
case "gen": return gen.apply(this, system.args.slice(index + 1));
case "gen": return gen.apply(this, args.slice(index + 1));
default: print("unknown command " + argument);
}
+10
View File
@@ -132,6 +132,16 @@
_objectsValues.push(parent);
});
}
var count = _objectsKeys.length;
while (count--)
{
var object = _objectsKeys[count];
if ([object respondsToSelector:@selector(swapCellsForParents:)])
[object swapCellsForParents:parentForCellUIDs];
}
}
@end
+1 -2
View File
@@ -53,8 +53,7 @@ NS_CPMenuNameMap =
if (mappedName)
_name = mappedName;
_showsStateColumn = YES;
//_showsStateColumn = ![aCoder containsValueForKey:@"NSMenuExcludeMarkColumn"] || ![aCoder decodeBoolForKey:@"NSMenuExcludeMarkColumn"];
_showsStateColumn = ![aCoder containsValueForKey:@"NSMenuExcludeMarkColumn"] || ![aCoder decodeBoolForKey:@"NSMenuExcludeMarkColumn"];
}
return self;
+14 -1
View File
@@ -64,7 +64,7 @@
// _mnemonicLocation = [aCoder decodeObjectForKey:"NSMnemonicLoc"];
// _isAlternate = [aCoder decodeBoolForKey:"NSIsAlternate"];
// _indentationLevel = [aCoder decodeBoolForKey:"NSIndent"];
_indentationLevel = [aCoder decodeIntForKey:"NSIndent"];
// _toolTip;
@@ -74,6 +74,19 @@
return self;
}
- (void)swapCellsForParents:(JSObject)parentsForCellUIDs
{
var target = [self target];
if (!target)
return;
var parent = parentsForCellUIDs[[[self target] UID]];
if (parent)
[self setTarget:parent];
}
@end
@implementation NSMenuItem : CPMenuItem

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