Compare commits

..
180 Commits
Author SHA1 Message Date
Scott KyleandRoss Boucher 4c81c9e21e Fixed typo "Janurary" 2010-01-07 12:26:51 -08:00
Francisco Ryan Tolmasky I f4912eb23b Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2010-01-06 22:51:31 -08:00
Francisco Ryan Tolmasky I 7f85b8b33f Tiny bit more support for toolbars in nib2cib.
Reviewed by me.
2010-01-06 21:08:01 -08:00
Tom Robinson 85c68f78da Update for compatibility with latest narwhal. Switch back to 280north/narwhal 2010-01-06 20:00:37 -08:00
Francisco Ryan Tolmasky I af03085d5f Fix for incorrect menu logic.
Reviewed by me.
2010-01-05 19:20:47 -08:00
Francisco Ryan Tolmasky I b7d747ee17 Fixed a bug in CPTreeNode's KVO implementation.
Reviewed by me.
2010-01-05 15:49:16 -08:00
Francisco Ryan Tolmasky I b6f100888a Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2010-01-05 11:15:45 -08:00
Francisco Ryan Tolmasky I 3cfd392e3e Added new automatic undo API to CPUndoManager.
Added archiving support for CPTreeNode.

Reviewd by me.
2010-01-05 11:14:56 -08:00
Ross Boucher 7ed98a8655 Fix a typo pointed out by Bruno on the mailing list. 2010-01-05 09:50:02 -05:00
Ross Boucher d78eb4a4e5 Fix an undefined notification variable 2010-01-04 19:11:10 -05:00
Randall LueckeandRoss Boucher a3d168b646 left unnessisary line... whoops 2010-01-04 10:24:45 -05:00
Randall LueckeandRoss Boucher 5018df511b fix for window overlapping the menu bar if the user dragged it up there. 2010-01-04 10:24:38 -05:00
Ross Boucher 09345a9d53 Use a notificaiton rather than a direct call for windowDidResize:
Closes #393.
2010-01-04 10:21:16 -05:00
Francisco Ryan Tolmasky I 8b17cd3cde Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2009-12-31 01:24:51 -08:00
Francisco Ryan Tolmasky I 403fcd8fff Preparing for options fix in Narhwal.
Reviewed by me.
2009-12-30 23:52:55 -08:00
tlrobinson 409be4020b Temporarily use tlrobinson/narwhal/master in bootstrap. 2009-12-29 13:35:48 -08:00
Nicholas Small 24801a220c Merge branch 'jake' of github.com:280north/cappuccino into jake 2009-12-26 19:12:31 -05:00
Nicholas Small 19b9f4e1c1 Enabling an accordion item will cause it to expand. 2009-12-26 19:11:33 -05:00
Francisco Ryan Tolmasky I 48d584df58 Fixed typo in setSubviews:.
Reviewed by me.
2009-12-26 01:20:16 -08:00
Francisco Ryan Tolmasky I dd999a29fd Added applyChange:toKeyPath: and inverseChangedDictionary to support "automatic" undo with KVO.
Reviewed by me.
2009-12-24 19:15:38 -08:00
Francisco Ryan Tolmasky I 75fdfb5a0b Improved observable arrays to support indexOfObject:, indexOfObjectIdenticalTo:, and removeObjectIdenticalTo:.
Reviewed by me.
2009-12-24 18:45:20 -08:00
Francisco Ryan Tolmasky I 6b4db4e9ae Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2009-12-23 19:32:43 -08:00
Francisco Ryan Tolmasky I 2571b24f22 Removed TextMate and Xcode files since the ones being used now have their own repos. Linked to them in the README.
Reviewed by me.
2009-12-23 19:31:51 -08:00
Nicholas Small 855a9eea44 Merge branch 'jake' of github.com:280north/cappuccino into jake 2009-12-23 16:51:46 -05:00
Nicholas Small 189e299592 Added CPAccordionView -setEnabled:forItemAtIndex: 2009-12-23 16:50:56 -05:00
Ross Boucher 6cbaa35849 Add CPOperation to Foundation 2009-12-23 11:30:10 -05:00
Ross Boucher cb1cfa4d94 Better support for recursing in CPDictionaryWithJSObject: 2009-12-20 20:32:17 -05:00
Ross Boucher 5bbf893a37 Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2009-12-20 20:11:59 -05:00
Ross Boucher 3ddbfb5dea Encode the header clip view in the CPCoder methods.
Closes 363.
2009-12-20 20:11:22 -05:00
Francisco Ryan Tolmasky I 5352d062d5 Fix for boundsOrigin and boundsSize being affected by bounds. Also changed UID to return a string instead of a Number.
Reviewed by me.
2009-12-20 17:02:06 -08:00
Randall LueckeandFrancisco Ryan Tolmasky I e15cbfca33 fix bug in CPPlatformWindow where the visible frame for the platform window would offset itself for the menu bar height, even though no menu bar would be displayed because it's not the primaryPlatformWindow 2009-12-20 15:44:39 -08:00
Francisco Ryan Tolmasky I 51b58f911e Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2009-12-20 13:01:11 -08:00
Francisco Ryan Tolmasky I 7acfbb9eed Added [CPView setSubviews:] which allows you to add multiple subviews, remove multiple subviews, and reorder multple subviews.
Reviewed by me.
2009-12-20 13:00:25 -08:00
Ross Boucher 4bf9853a25 Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2009-12-20 13:13:15 -05:00
Ross Boucher 58c6db0a8f Fix the logic behind CPURLConnection's _isLocalFileConnection 2009-12-20 13:12:29 -05:00
tlrobinson aed52a7829 Improved bootstrap.sh further. Prompt to delete existing installations, etc. 2009-12-19 23:16:37 -08:00
Ross Boucher a1e24a3f95 Fix a bug where keyPaths which had a component evaluating to self would send notifications containing the wrong keypath in the observation.
Includes test case.
2009-12-19 17:47:02 -05:00
Ross Boucher 11cff29916 Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2009-12-19 15:32:52 -05:00
Ross Boucher f184b9bcc4 Add a few KVO tests around arrays 2009-12-19 15:32:23 -05:00
tlrobinson bab0024e0c Cleanup some build scripts 2009-12-19 04:31:11 -08:00
aburkhalterandtlrobinson deed92cff7 Toll-free bridge Error to CPException. Add rhinoException in objj_exception for better error reporting. 2009-12-19 03:49:22 -08:00
Francisco Ryan Tolmasky I a9bc949679 Actual fix for disabled items in CPMenu. Previous fix still selected disabled items and showed submenus for disabled items.
Reviewed by me.
2009-12-18 22:31:12 -08:00
Randall LueckeandRoss Boucher 1411410f4e fixed bug in CPMenu where action would be sent when the user clicked on a disabled menu item. 2009-12-18 18:43:03 -05:00
Ross Boucher 648fbe1b10 Add sendsActionOnEndEditing to the CPCoding methods for CPControl 2009-12-18 15:54:44 -05:00
Ross Boucher 7042f89620 Fix a return type error. Closes #358. 2009-12-17 00:57:09 -05:00
Ross Boucher e235fffb5e Correct HTML escaping and unescaping in Objective-J/plist. Closes 361. 2009-12-17 00:54:00 -05:00
Ross Boucher 6aadd13450 Update CPColorPanel to handle drag and drop correctly, which broke with native drag and drop. Closes 364. 2009-12-17 00:25:49 -05:00
Ross Boucher 349de098af Merge branch 'jake' of git@github.com:280north/cappuccino into jake
Conflicts:
	AppKit/CPMenuItem/CPMenuItem.j
2009-12-16 19:00:48 -05:00
Ross Boucher 5527e585f6 Make Windows handle key equivalents in menus correctly. Make the menu display the string properly on Windows too. 2009-12-16 18:58:21 -05:00
Francisco Ryan Tolmasky I a6e9814dfc Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2009-12-16 15:03:27 -08:00
Francisco Ryan Tolmasky I f01a7d3933 Fix for menu items incorrectly leaving out shift symbol if the key equivalent is uppercase.
Reviewed by me.
2009-12-16 15:02:35 -08:00
Nicholas Small d2cd3b899f Fix CPTabViewItem -tabView. 2009-12-16 00:22:35 -05:00
Francisco Ryan Tolmasky I ac2c0d5d84 Update CPUndoManager to post checkpoint notifications and only create run loop performs if undos actually take place.
Reviewed by me.
2009-12-15 16:37:47 -08:00
Ross Boucher f0d0b512ca Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2009-12-13 18:30:16 -08:00
Ross Boucher c859ffd0f7 Support for copy/paste/cut and selectedRange/setSelectedRange in CPTextField.
Improvements to the Pasteboard integration code from yesterday.
2009-12-13 18:29:25 -08:00
Tom Robinson 4eb57f3cc5 Merge branch 'jake' of github.com:280north/cappuccino into jake 2009-12-13 15:02:38 -08:00
Tom Robinson 6218bfaf9e Rewrite/cleanup of press. Incomplete, but press --flatten "works" for some value of "work". 2009-12-13 15:01:19 -08:00
Ross Boucher 4d5cdcaeae Fix for the pasteboard changes breaking everything. 2009-12-12 18:36:48 -08:00
Ross Boucher 6ad62a6f2f Add support for native pasteboards to webtop 2009-12-12 14:15:45 -08:00
Ross Boucher 37d4b151d7 Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2009-12-11 16:55:36 -08:00
Ross Boucher 37c1d804f6 Fix for text shadows sometimes being the wrong color.
Closes #359.
2009-12-11 16:54:38 -08:00
Francisco Ryan Tolmasky I d200df3e9c Typo in last commit.
Reviewed by me.
2009-12-11 12:03:25 -08:00
Francisco Ryan Tolmasky I eb43e416ae Added CPProxy class to support better undo proxying in CPUndoManager.
Closes #370.
Closes #371.

Reviewed by me.
2009-12-11 11:38:26 -08:00
Francisco Ryan Tolmasky I e6244f71bd Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2009-12-11 11:16:37 -08:00
Francisco Ryan Tolmasky I 403277ed06 Further refined KVO tests.
Reviewed by me.
2009-12-11 11:16:17 -08:00
Ross Boucher dbe8a59c3c Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2009-12-11 10:58:40 -08:00
Ross Boucher a98de54db4 A few additions for pretty printing things and getting better error messages 2009-12-11 10:58:07 -08:00
Francisco Ryan Tolmasky I 7edb7266f2 Added test for old dependent values in KVO.
Reviewed by me.
2009-12-11 10:54:17 -08:00
Nicholas Small d14e077511 Make CPTableView selection notifications behave the same as in Cocoa. 2009-12-10 03:07:22 -05:00
Francisco Ryan Tolmasky I 211c14e316 Merge branch 'jake' of git@github.com:280north/cappuccino into jake 2009-12-07 18:59:57 -08:00
Francisco Ryan Tolmasky I 4fbc140551 Better descriptions for CPArray.
Reviewed by me.
2009-12-07 18:54:01 -08:00
Ross Boucher ee8e65c80d Fix for alt+character key events not propagating correctly.
Closes #354.
2009-12-05 16:58:26 -08:00
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
185 changed files with 8653 additions and 9359 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"
+21 -1
View File
@@ -197,6 +197,20 @@
return indexSet;
}
- (void)setEnabled:(BOOL)isEnabled forItemAtIndex:(CPInteger)anIndex
{
var itemView = _itemViews[anIndex];
if (!itemView)
return;
if (!isEnabled)
[self collapseItemAtIndex:anIndex];
else
[self expandItemAtIndex:anIndex];
[itemView setEnabled:isEnabled];
}
- (void)_invalidateItemsStartingAtIndex:(CPInteger)anIndex
{
if (_dirtyItemIndex === CPNotFound)
@@ -301,6 +315,12 @@
[_headerView setStringValue:aLabel];
}
- (void)setEnabled:(BOOL)isEnabled
{
if ([_headerView respondsToSelector:@selector(setEnabled:)])
[_headerView setEnabled:isEnabled];
}
- (void)setContentView:(CPView)aView
{
if (_contentView === aView)
@@ -312,7 +332,7 @@
_contentView = aView;
[_contentView addObserver:self forKeyPath:@"frame" options:0 context:NULL];
[_contentView addObserver:self forKeyPath:@"frame" options:CPKeyValueObservingOptionOld | CPKeyValueObservingOptionNew context:NULL];
[self addSubview:_contentView];
+6 -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)
+114 -15
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
@@ -607,7 +701,7 @@ CPRunContinuesResponse = -1002;
- (BOOL)sendAction:(SEL)anAction to:(id)aTarget from:(id)aSender
{
var target = [self targetForAction:anAction to:aTarget from:aSender];
if (!target)
return NO;
@@ -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
+1 -1
View File
@@ -321,7 +321,7 @@
*/
- (CPIndexSet)selectionIndexes
{
return _selectionIndexes;
return [_selectionIndexes copy];
}
/* @ignore */
+10 -9
View File
@@ -140,7 +140,7 @@ CPColorPickerViewHeight = 370;
Sets the color of the panel, and updates the picker. Also posts a \c CPColorPanelDidChangeNotification.
*/
- (void)setColor:(CPColor)aColor
{
{
_color = aColor;
[_previewView setBackgroundColor: _color];
@@ -518,9 +518,10 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
- (void)mouseUp:(CPEvent)anEvent
{
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil],
bounds = [self bounds];
if(point.x > [self bounds].size.width - 1 || point.x < 1)
if(!CGRectContainsPoint(bounds, point) || point.x > [self bounds].size.width - 1 || point.x < 1)
return NO;
[_colorPanel setColor: [self colorAtIndex:FLOOR(point.x / 13)] updatePicker: YES];
@@ -563,7 +564,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
{
if(aType == CPColorDragType)
[aPasteboard setData:_dragColor forType:aType];
[aPasteboard setData:[CPKeyedArchiver archivedDataWithRootObject:_dragColor] forType:aType];
}
- (void)performDragOperation:(id <CPDraggingInfo>)aSender
@@ -575,7 +576,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
if(![pasteboard availableTypeFromArray:[CPColorDragType]] || location.x > [self bounds].size.width - 1 || location.x < 1)
return NO;
[self setColor:[pasteboard dataForType:CPColorDragType] atIndex: FLOOR(location.x / 13)];
[self setColor:[CPKeyedUnarchiver unarchiveObjectWithData:[pasteboard dataForType:CPColorDragType]] atIndex: FLOOR(location.x / 13)];
}
@end
@@ -612,8 +613,8 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
if(![pasteboard availableTypeFromArray:[CPColorDragType]])
return NO;
var color = [pasteboard dataForType:CPColorDragType];
[_colorPanel setColor: color updatePicker: YES];
var color = [CPKeyedUnarchiver unarchiveObjectWithData:[pasteboard dataForType:CPColorDragType]];
[_colorPanel setColor:color updatePicker:YES];
}
- (BOOL)isOpaque
@@ -625,7 +626,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
{
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:[CPArray arrayWithObject:CPColorDragType] owner:self];
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:[CPColorDragType] owner:self];
var bounds = CPRectMake(0, 0, 15, 15);
@@ -650,7 +651,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
{
if(aType == CPColorDragType)
[aPasteboard setData:[self backgroundColor] forType:aType];
[aPasteboard setData:[CPKeyedArchiver archivedDataWithRootObject:[self backgroundColor]] forType:aType];
}
@end
+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";
+7 -1
View File
@@ -572,7 +572,9 @@ var CPControlValueKey = "CPControlValueKey",
CPControlTargetKey = "CPControlTargetKey",
CPControlActionKey = "CPControlActionKey",
CPControlSendActionOnKey = "CPControlSendActionOnKey";
CPControlSendActionOnKey = "CPControlSendActionOnKey",
CPControlSendsActionOnEndEditingKey = "CPControlSendsActionOnEndEditingKey";
var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
@@ -595,6 +597,7 @@ var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
[self setAction:[aCoder decodeObjectForKey:CPControlActionKey]];
[self sendActionOn:[aCoder decodeIntForKey:CPControlSendActionOnKey]];
[self setSendsActionOnEndEditing:[aCoder decodeBoolForKey:CPControlSendsActionOnEndEditingKey]];
}
return self;
@@ -608,6 +611,9 @@ var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
{
[super encodeWithCoder:aCoder];
if (_sendsActionOnEndEditing)
[aCoder encodeBool:_sendsActionOnEndEditing forKey:CPControlSendsActionOnEndEditingKey];
if (_value !== nil)
[aCoder encodeObject:_value forKey:CPControlValueKey];
+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];
}
+1 -1
View File
@@ -310,7 +310,7 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
_draggingOffset = _CGSizeMake(mouseDownEventLocation.x - viewLocation.x, mouseDownEventLocation.y - viewLocation.y);
}
else
_draggingOffset = _CGSizeMakerZero();
_draggingOffset = _CGSizeMakeZero();
if ([CPPlatform isBrowser])
[_draggedWindow setPlatformWindow:[aWindow platformWindow]];
+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
+322
View File
@@ -0,0 +1,322 @@
#include "../CoreGraphics/CGGeometry.h"
@import <Foundation/CPObject.j>
_CPMenuManagerScrollingStateUp = -1,
_CPMenuManagerScrollingStateDown = 1,
_CPMenuManagerScrollingStateNone = 0;
var STICKY_TIME_INTERVAL = 500;
var SharedMenuManager = nil;
@implementation _CPMenuManager: CPObject
{
CPTimeInterval _startTime;
int _scrollingState;
CGPoint _lastGlobalLocation;
CPView _lastMouseOverMenuView;
CGRect _constraintRect;
CPMutableArray _menuContainerStack;
Function _trackingCallback;
}
+ (_CPMenuManager)sharedMenuManager
{
if (!SharedMenuManager)
SharedMenuManager = [[_CPMenuManager alloc] init];
return SharedMenuManager;
}
- (id)init
{
if (SharedMenuManager)
return SharedMenuManager;
return [super init];
}
- (id)trackingMenuContainer
{
return _menuContainerStack[0];
}
- (CPMenu)trackingMenu
{
return [[self trackingMenuContainer] menu];
}
- (void)beginTracking:(CPEvent)anEvent
menuContainer:(id)aMenuContainer
constraintRect:(CGRect)aRect
callback:(Function)aCallback
{
CPApp._activeMenu = [aMenuContainer menu];
_startTime = [anEvent timestamp];//new Date();
_scrollingState = _CPMenuManagerScrollingStateNone;
_constraintRect = aRect;
_trackingCallback = aCallback;
_menuContainerStack = [aMenuContainer];
[self trackEvent:anEvent];
}
- (void)trackEvent:(CPEvent)anEvent
{
var type = [anEvent type],
trackingMenu = [self trackingMenu];
// Close Menu Event.
if (type === CPAppKitDefined)
{
// Stop all periodic events at this point.
[CPEvent stopPeriodicEvents];
// Get the highlighted item from the original menu.
var highlightedItem = [trackingMenu highlightedItem];
// Hide all submenus.
[self showMenu:nil fromMenu:trackingMenu atPoint:nil];
var delegate = [trackingMenu delegate];
if ([delegate respondsToSelector:@selector(menuDidClose:)])
[delegate menuDidClose:trackingMenu];
if (_trackingCallback)
_trackingCallback([self trackingMenuContainer], trackingMenu);
[[CPNotificationCenter defaultCenter]
postNotificationName:CPMenuDidEndTrackingNotification
object:trackingMenu];
CPApp._activeMenu = nil;
return;
}
[CPApp setTarget:self selector:@selector(trackEvent:) forNextEventMatchingMask:CPPeriodicMask | CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPAppKitDefinedMask untilDate:nil inMode:nil dequeue:YES];
// Periodic events don't have a valid location.
var globalLocation = type === CPPeriodic ? _lastGlobalLocation : [anEvent globalLocation];
// Remember this for the next periodic event.
_lastGlobalLocation = globalLocation;
// Find which menu window the mouse is currently on top of
var activeMenuContainer = [self menuContainerForPoint:globalLocation],
activeMenu = [activeMenuContainer menu],
menuLocation = [activeMenuContainer convertGlobalToBase:globalLocation];
// Find out the item the mouse is currently on top of
var activeItemIndex = activeMenuContainer ? [activeMenuContainer itemIndexAtPoint:menuLocation] : CPNotFound,
activeItem = activeItemIndex !== CPNotFound ? [activeMenu itemAtIndex:activeItemIndex] : nil;
// If the item isn't enabled its as if we clicked on nothing.
if (![activeItem isEnabled])
{
activeItemIndex = CPNotFound;
activeItem = nil;
}
var mouseOverMenuView = [activeItem view];
if (type === CPPeriodic)
{
if (_scrollingState === _CPMenuManagerScrollingStateUp)
[activeMenuContainer scrollUp];
else if (_scrollingState === _CPMenuManagerScrollingStateDown)
[activeMenuContainer scrollDown];
}
// If we're over a custom menu view...
if (mouseOverMenuView)
{
if (!_lastMouseOverMenuView)
[activeMenu _highlightItemAtIndex:CPNotFound];
if (_lastMouseOverMenuView != mouseOverMenuView)
{
[mouseOverMenuView mouseExited:anEvent];
// FIXME: Possibly multiple of these?
[_lastMouseOverMenuView mouseEntered:anEvent];
_lastMouseOverMenuView = mouseOverMenuView;
}
var menuContainerWindow = activeMenuContainer;
if (![menuContainerWindow isKindOfClass:[CPWindow class]])
menuContainerWindow = [menuContainerWindow window];
[menuContainerWindow
sendEvent:[CPEvent mouseEventWithType:type location:menuLocation modifierFlags:[anEvent modifierFlags]
timestamp:[anEvent timestamp]
windowNumber:menuContainerWindow
context:nil
eventNumber:0
clickCount:[anEvent clickCount]
pressure:[anEvent pressure]]];
}
else
{
if (_lastMouseOverMenuView)
{
[_lastMouseOverMenuView mouseExited:anEvent];
_lastMouseOverMenuView = nil;
}
[activeMenu _highlightItemAtIndex:activeItemIndex];
if (type === CPMouseMoved || type === CPLeftMouseDragged || type === CPLeftMouseDown)
{
var oldScrollingState = _scrollingState;
_scrollingState = [activeMenuContainer scrollingStateForPoint:globalLocation];
if (_scrollingState !== oldScrollingState)
{
if (_scrollingState === _CPMenuManagerScrollingStateNone)
[CPEvent stopPeriodicEvents];
else if (oldScrollingState === _CPMenuManagerScrollingStateNone)
[CPEvent startPeriodicEventsAfterDelay:0.0 withPeriod:0.04];
}
}
else if (type === CPLeftMouseUp && ([anEvent timestamp] - _startTime > STICKY_TIME_INTERVAL))
[trackingMenu cancelTracking];
}
// If the item has a submenu, show it.
if ([activeItem hasSubmenu])// && [activeItem action] === @selector(submenuAction:))
{
var activeItemRect = [activeMenuContainer rectForItemAtIndex:activeItemIndex];
if ([activeMenuContainer isMenuBar])
var newMenuOrigin = CGPointMake(CGRectGetMinX(activeItemRect), CGRectGetMaxY(activeItemRect));
else
var newMenuOrigin = CGPointMake(CGRectGetMaxX(activeItemRect), CGRectGetMinY(activeItemRect));
newMenuOrigin = [activeMenuContainer convertBaseToGlobal:newMenuOrigin];
[self showMenu:[activeItem submenu] fromMenu:[activeItem menu] atPoint:newMenuOrigin];
}
// This handles both the case where we've moved away from the menu, and where
// we've moved to an item without a submenu.
else
[self showMenu:nil fromMenu:activeMenu atPoint:CGPointMakeZero()];
}
- (id)menuContainerForPoint:(float)aGlobalLocation
{
var count = [_menuContainerStack count],
firstMenuContainer = _menuContainerStack[0];
// Trivial case.
if (count === 1)
return firstMenuContainer;
var firstMenuWindowIndex = 0,
lastMenuWindowIndex = count - 1;
// If the first menu container is a bar, then it has to fall strictly within its bounds.
if ([firstMenuContainer isMenuBar])
{
if (CGRectContainsPoint([firstMenuContainer globalFrame], aGlobalLocation))
return firstMenuContainer;
firstMenuWindowIndex = 1;
}
var index = count,
x = aGlobalLocation.x,
closerDeltaX = Infinity,
closerMenuContainer = nil;
while (index-- > firstMenuWindowIndex)
{
var menuContainer = _menuContainerStack[index],
menuContainerFrame = [menuContainer globalFrame],
menuContainerMinX = _CGRectGetMinX(menuContainerFrame),
menuContainerMaxX = _CGRectGetMaxX(menuContainerFrame);
// If within the x bounds of this menu container, return it.
if (x < menuContainerMaxX && x >= menuContainerMinX)
return menuContainer;
// If this is either the first or last menu *window*, check to see how close we are to it.
if (index === firstMenuWindowIndex || index === lastMenuWindowIndex)
{
var deltaX = ABS(x < menuContainerMinX ? menuContainerMinX - x : menuContainerMaxX - x);
if (deltaX < closerDeltaX)
{
closerMenuContainer = menuContainer;
closerDeltaX = deltaX;
}
}
}
return closerMenuContainer;
}
- (void)showMenu:(CPMenu)newMenu fromMenu:(CPMenu)baseMenu atPoint:(CGPoint)aGlobalLocation
{
var count = _menuContainerStack.length,
index = count;
// Hide all menus up to the base menu...
while (index--)
{
var menuContainer = _menuContainerStack[index],
menu = [menuContainer menu];
// If we reach the base menu, or this menu is already being shown, break.
if (menu === baseMenu)
break;
// If this menu is already being shown, unhighlight and return.
if (menu === newMenu)//&& [menu supermenu] === baseMenu)
return [newMenu _highlightItemAtIndex:CPNotFound];
[menuContainer orderOut:self];
[menuContainer setMenu:nil];
[_CPMenuWindow poolMenuWindow:menuContainer];
[_menuContainerStack removeObjectAtIndex:index];
}
if (!newMenu)
return;
// Unhighlight any previously highlighted item.
[newMenu _highlightItemAtIndex:CPNotFound];
var menuWindow = [_CPMenuWindow menuWindowWithMenu:newMenu font:[_menuContainerStack[0] font]];
[_menuContainerStack addObject:menuWindow];
[menuWindow setConstraintRect:_constraintRect];
// If our parent menu is a menu bar...
if (baseMenu === [self trackingMenu] && [[self trackingMenuContainer] isMenuBar])
[menuWindow setBackgroundStyle:_CPMenuWindowMenuBarBackgroundStyle];
else
[menuWindow setBackgroundStyle:_CPMenuWindowPopUpBackgroundStyle];
[menuWindow setFrameOrigin:aGlobalLocation];
[menuWindow orderFront:self];
}
@end
+548
View File
@@ -0,0 +1,548 @@
#include "../CoreGraphics/CGGeometry.h"
var _CPMenuWindowPool = [],
_CPMenuWindowPoolCapacity = 5,
_CPMenuWindowBackgroundColors = [];
_CPMenuWindowMenuBarBackgroundStyle = 0;
_CPMenuWindowPopUpBackgroundStyle = 1;
_CPMenuWindowAttachedMenuBackgroundStyle = 2;
var STICKY_TIME_INTERVAL = 500,
TOP_MARGIN = 5.0,
LEFT_MARGIN = 1.0,
RIGHT_MARGIN = 1.0,
BOTTOM_MARGIN = 5.0,
SCROLL_INDICATOR_HEIGHT = 16.0;
/*
@ignore
*/
@implementation _CPMenuWindow : CPWindow
{
_CPMenuView _menuView;
CPClipView _menuClipView;
CPImageView _moreAboveView;
CPImageView _moreBelowView;
CGRect _unconstrainedFrame;
CGRect _constraintRect;
}
+ (id)menuWindowWithMenu:(CPMenu)aMenu font:(CPFont)aFont
{
var menuWindow = nil;
if (_CPMenuWindowPool.length)
{
menuWindow = _CPMenuWindowPool.pop();
// Do this so that coordinates will be accurate.
[menuWindow setFrameOrigin:CGPointMakeZero()];
}
else
menuWindow = [[_CPMenuWindow alloc] init];
[menuWindow setFont:aFont];
[menuWindow setMenu:aMenu];
[menuWindow setMinWidth:[aMenu minimumWidth]];
return menuWindow;
}
+ (void)poolMenuWindow:(_CPMenuWindow)aMenuWindow
{
if (!aMenuWindow || _CPMenuWindowPool.length >= _CPMenuWindowPoolCapacity)
return;
_CPMenuWindowPool.push(aMenuWindow);
}
+ (void)initialize
{
if (self != [_CPMenuWindow class])
return;
var bundle = [CPBundle bundleForClass:self];
_CPMenuWindowMoreAboveImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowMoreAbove.png"] size:CGSizeMake(38.0, 18.0)];
_CPMenuWindowMoreBelowImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowMoreBelow.png"] size:CGSizeMake(38.0, 18.0)];
}
- (id)initWithContentRect:(CGRect)aRect styleMask:(unsigned)aStyleMask
{
_constraintRect = _CGRectMakeZero();
_unconstrainedFrame = _CGRectMakeZero();
self = [super initWithContentRect:aRect styleMask:CPBorderlessWindowMask];
if (self)
{
[self setLevel:CPPopUpMenuWindowLevel];
[self setHasShadow:YES];
[self setShadowStyle:CPMenuWindowShadowStyle];
[self setAcceptsMouseMovedEvents:YES];
var contentView = [self contentView];
_menuView = [[_CPMenuView alloc] initWithFrame:CGRectMakeZero()];
_menuClipView = [[CPClipView alloc] initWithFrame:CGRectMake(LEFT_MARGIN, TOP_MARGIN, 0.0, 0.0)];
[_menuClipView setDocumentView:_menuView];
[contentView addSubview:_menuClipView];
_moreAboveView = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
[_moreAboveView setImage:_CPMenuWindowMoreAboveImage];
[_moreAboveView setFrameSize:[_CPMenuWindowMoreAboveImage size]];
[contentView addSubview:_moreAboveView];
_moreBelowView = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
[_moreBelowView setImage:_CPMenuWindowMoreBelowImage];
[_moreBelowView setFrameSize:[_CPMenuWindowMoreBelowImage size]];
[contentView addSubview:_moreBelowView];
[self setShadowStyle:CPWindowShadowStyleMenu];
}
return self;
}
+ (float)_standardLeftMargin
{
return LEFT_MARGIN;
}
- (void)setFont:(CPFont)aFont
{
[_menuView setFont:aFont];
}
- (CPFont)font
{
return [_menuView font];
}
+ (CPColor)backgroundColorForBackgroundStyle:(_CPMenuWindowBackgroundStyle)aBackgroundStyle
{
var color = _CPMenuWindowBackgroundColors[aBackgroundStyle];
if (!color)
{
var bundle = [CPBundle bundleForClass:[self class]];
if (aBackgroundStyle == _CPMenuWindowPopUpBackgroundStyle)
color = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded0.png"] size:CGSizeMake(4.0, 4.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow1.png"] size:CGSizeMake(1.0, 4.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded2.png"] size:CGSizeMake(4.0, 4.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow3.png"] size:CGSizeMake(4.0, 1.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow4.png"] size:CGSizeMake(1.0, 1.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow5.png"] size:CGSizeMake(4.0, 1.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded6.png"] size:CGSizeMake(4.0, 4.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow7.png"] size:CGSizeMake(1.0, 4.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded8.png"] size:CGSizeMake(4.0, 4.0)]
]]];
else if (aBackgroundStyle == _CPMenuWindowMenuBarBackgroundStyle)
color = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow3.png"] size:CGSizeMake(4.0, 0.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow4.png"] size:CGSizeMake(1.0, 0.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow5.png"] size:CGSizeMake(4.0, 0.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow3.png"] size:CGSizeMake(4.0, 1.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow4.png"] size:CGSizeMake(1.0, 1.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow5.png"] size:CGSizeMake(4.0, 1.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded6.png"] size:CGSizeMake(4.0, 4.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow7.png"] size:CGSizeMake(1.0, 4.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded8.png"] size:CGSizeMake(4.0, 4.0)]
]]];
_CPMenuWindowBackgroundColors[aBackgroundStyle] = color;
}
return color;
}
- (void)setBackgroundStyle:(_CPMenuWindowBackgroundStyle)aBackgroundStyle
{
[self setBackgroundColor:[[self class] backgroundColorForBackgroundStyle:aBackgroundStyle]];
}
- (void)setMenu:(CPMenu)aMenu
{
[aMenu _setMenuWindow:self];
[_menuView setMenu:aMenu];
var menuViewSize = [_menuView frame].size;
[self setFrameSize:CGSizeMake(LEFT_MARGIN + menuViewSize.width + RIGHT_MARGIN, TOP_MARGIN + menuViewSize.height + BOTTOM_MARGIN)];
[_menuView scrollPoint:CGPointMake(0.0, 0.0)];
[_menuClipView setFrame:CGRectMake(LEFT_MARGIN, TOP_MARGIN, menuViewSize.width, menuViewSize.height)];
}
- (void)setMinWidth:(float)aWidth
{
var size = [self unconstrainedFrame].size;
[self setFrameSize:CGSizeMake(MAX(size.width, aWidth), size.height)];
}
- (CPMenu)menu
{
return [_menuView menu];
}
- (void)orderFront:(id)aSender
{
[self setFrame:_unconstrainedFrame];
[super orderFront:aSender];
}
- (void)setConstraintRect:(CGRect)aRect
{
_constraintRect = aRect;
[self setFrame:_unconstrainedFrame];
}
- (CGRect)unconstrainedFrame
{
return _CGRectMakeCopy(_unconstrainedFrame);
}
// We need this because if not this will call setFrame: with -frame instead of -unconstrainedFrame, turning
// the constrained frame into the unconstrained frame.
- (void)setFrameOrigin:(CGPoint)aPoint
{
[super setFrame:_CGRectMake(aPoint.x, aPoint.y, _CGRectGetWidth(_unconstrainedFrame), _CGRectGetHeight(_unconstrainedFrame))];
}
- (void)setFrameSize:(CGSize)aSize
{
[super setFrame:_CGRectMake(_CGRectGetMinX(_unconstrainedFrame), _CGRectGetMinY(_unconstrainedFrame), aSize.width, aSize.height)];
}
- (void)setFrame:(CGRect)aFrame display:(BOOL)shouldDisplay animate:(BOOL)shouldAnimate
{
// FIXME: There are integral window issues with platform windows.
// FIXME: This gets called far too often.
_unconstrainedFrame = _CGRectMakeCopy(aFrame);
var constrainedFrame = CGRectIntersection(_unconstrainedFrame, _constraintRect);
// We don't want to simply intersect the visible frame and the unconstrained frame.
// We should be allowing as much of the width to fit as possible (pushing back and forward).
constrainedFrame.origin.x = CGRectGetMinX(_unconstrainedFrame);
constrainedFrame.size.width = CGRectGetWidth(_unconstrainedFrame);
if (CGRectGetWidth(constrainedFrame) > CGRectGetWidth(_constraintRect))
constrainedFrame.size.width = CGRectGetWidth(_constraintRect);
if (CGRectGetMaxX(constrainedFrame) > CGRectGetMaxX(_constraintRect))
constrainedFrame.origin.x -= CGRectGetMaxX(constrainedFrame) - CGRectGetMaxX(_constraintRect);
if (CGRectGetMinX(constrainedFrame) < CGRectGetMinX(_constraintRect))
constrainedFrame.origin.x = CGRectGetMinX(_constraintRect);
[super setFrame:constrainedFrame display:shouldDisplay animate:shouldAnimate];
// This needs to happen before changing the frame.
var menuViewOrigin = CGPointMake(CGRectGetMinX(aFrame) + LEFT_MARGIN, CGRectGetMinY(aFrame) + TOP_MARGIN),
moreAbove = menuViewOrigin.y < CGRectGetMinY(constrainedFrame) + TOP_MARGIN,
moreBelow = menuViewOrigin.y + CGRectGetHeight([_menuView frame]) > CGRectGetMaxY(constrainedFrame) - BOTTOM_MARGIN,
topMargin = TOP_MARGIN,
bottomMargin = BOTTOM_MARGIN,
contentView = [self contentView],
bounds = [contentView bounds];
if (moreAbove)
{
topMargin += SCROLL_INDICATOR_HEIGHT;
var frame = [_moreAboveView frame];
[_moreAboveView setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth(frame)) / 2.0, (TOP_MARGIN + SCROLL_INDICATOR_HEIGHT - CGRectGetHeight(frame)) / 2.0)];
}
[_moreAboveView setHidden:!moreAbove];
if (moreBelow)
{
bottomMargin += SCROLL_INDICATOR_HEIGHT;
[_moreBelowView setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth([_moreBelowView frame])) / 2.0, CGRectGetHeight(bounds) - SCROLL_INDICATOR_HEIGHT - BOTTOM_MARGIN)];
}
[_moreBelowView setHidden:!moreBelow];
var clipFrame = CGRectMake(LEFT_MARGIN, topMargin, CGRectGetWidth(constrainedFrame) - LEFT_MARGIN - RIGHT_MARGIN, CGRectGetHeight(constrainedFrame) - topMargin - bottomMargin)
[_menuClipView setFrame:clipFrame];
[_menuView setFrameSize:CGSizeMake(CGRectGetWidth(clipFrame), CGRectGetHeight([_menuView frame]))];
[_menuView scrollPoint:CGPointMake(0.0, [self convertBaseToGlobal:clipFrame.origin].y - menuViewOrigin.y)];
}
- (BOOL)hasMinimumNumberOfVisibleItems
{
var visibleRect = [_menuView visibleRect];
// Clearly if the entire view isn't visible the minimum won't be visible.
if (CGRectIsEmpty(visibleRect))
return NO;
var numberOfUnhiddenItems = [_menuView numberOfUnhiddenItems],
minimumNumberOfVisibleItems = MIN(numberOfUnhiddenItems, 3),
count = 0,
index = [_menuView itemIndexAtPoint:[_menuView convertPoint:[_menuClipView frame].origin fromView:nil]];
for (; index < numberOfUnhiddenItems && count < minimumNumberOfVisibleItems; ++index)
{
var itemRect = [_menuView rectForUnhiddenItemAtIndex:index],
visibleItemRect = CGRectIntersection(visibleRect, itemRect);
// As soon as we get to the first unhidden item that is no longer visible, stop.
if (CGRectIsEmpty(visibleItemRect))
break;
// If the item is *completely* visible, count it.
if (CGRectEqualToRect(visibleItemRect, itemRect))
++count;
}
return count >= minimumNumberOfVisibleItems;
}
- (BOOL)canScrollUp
{
return ![_moreAboveView isHidden];
}
- (BOOL)canScrollDown
{
return ![_moreBelowView isHidden];
}
- (BOOL)canScroll
{
return [self canScrollUp] || [self canScrollDown];
}
- (void)scrollUp
{
if (CGRectGetMinY(_unconstrainedFrame) >= CGRectGetMinY(_constraintRect))
return;
_unconstrainedFrame.origin.y += 10;
[self setFrame:_unconstrainedFrame];
}
- (void)scrollDown
{
if (CGRectGetMaxY(_unconstrainedFrame) <= CGRectGetHeight(_constraintRect))
return;
_unconstrainedFrame.origin.y -= 10;
[self setFrame:_unconstrainedFrame];
}
@end
@implementation _CPMenuWindow (CPMenuContainer)
- (CGRect)globalFrame
{
return [self frame];
}
- (BOOL)isMenuBar
{
return NO;
}
- (_CPManagerScrollingState)scrollingStateForPoint:(CGPoint)aGlobalLocation
{
var frame = [self frame];
if (![self canScroll])
return _CPMenuManagerScrollingStateNone;
// If we're at or above of the top scroll indicator...
if (aGlobalLocation.y < CGRectGetMinY(frame) + TOP_MARGIN + SCROLL_INDICATOR_HEIGHT)
return _CPMenuManagerScrollingStateUp;
// If we're at or below the bottom scroll indicator...
if (aGlobalLocation.y > CGRectGetMaxY(frame) - BOTTOM_MARGIN - SCROLL_INDICATOR_HEIGHT)
return _CPMenuManagerScrollingStateDown;
return _CPMenuManagerScrollingStateNone;
}
- (float)deltaYForItemAtIndex:(int)anIndex
{
return TOP_MARGIN + CGRectGetMinY([_menuView rectForItemAtIndex:anIndex]);
}
- (CGPoint)rectForItemAtIndex:(int)anIndex
{
return [_menuView convertRect:[_menuView rectForItemAtIndex:anIndex] toView:nil];
}
- (int)itemIndexAtPoint:(CGPoint)aPoint
{
// Don't return indexes of items that aren't visible.
if (!CGRectContainsPoint([_menuClipView bounds], [_menuClipView convertPoint:aPoint fromView:nil]))
return NO;
return [_menuView itemIndexAtPoint:[_menuView convertPoint:aPoint fromView:nil]];
}
@end
/*
@ignore
*/
@implementation _CPMenuView : CPView
{
CPArray _menuItemViews;
CPArray _visibleMenuItemInfos;
CPFont _font @accessors(property=font);
}
- (unsigned)numberOfUnhiddenItems
{
return _visibleMenuItemInfos.length;
}
- (CGRect)rectForUnhiddenItemAtIndex:(int)anIndex
{
return [self rectForItemAtIndex:_visibleMenuItemInfos[anIndex].index];
}
- (CGRect)rectForItemAtIndex:(int)anIndex
{
return [_menuItemViews[anIndex === CPNotFound ? 0 : anIndex] frame];
}
- (int)itemIndexAtPoint:(CGPoint)aPoint
{
var x = aPoint.x,
bounds = [self bounds];
if (x < CGRectGetMinX(bounds) || x > CGRectGetMaxX(bounds))
return CPNotFound;
var y = aPoint.y,
low = 0,
high = _visibleMenuItemInfos.length - 1;
while (low <= high)
{
var middle = FLOOR(low + (high - low) / 2),
info = _visibleMenuItemInfos[middle]
frame = [info.view frame];
if (y < CGRectGetMinY(frame))
high = middle - 1;
else if (y > CGRectGetMaxY(frame))
low = middle + 1;
else
return info.index;
}
return CPNotFound;
}
- (void)tile
{
[_menuItemViews makeObjectsPerformSelector:@selector(removeFromSuperview)];
_menuItemViews = [];
_visibleMenuItemInfos = [];
var menu = [self menu];
if (!menu)
return;
var items = [menu itemArray],
index = 0,
count = [items count],
maxWidth = 0,
y = 0,
showsStateColumn = [menu showsStateColumn];
for (; index < count; ++index)
{
var item = items[index],
view = [item _menuItemView];
_menuItemViews.push(view);
if ([item isHidden])
continue;
_visibleMenuItemInfos.push({ view:view, index:index });
[view setFont:_font];
[view setShowsStateColumn:showsStateColumn];
[view synchronizeWithMenuItem];
[view setFrameOrigin:CGPointMake(0.0, y)];
[self addSubview:view];
var size = [view minSize],
width = size.width;
if (maxWidth < width)
maxWidth = width;
y += size.height;
}
for (index = 0; index < count; ++index)
{
var view = _menuItemViews[index];
[view setFrameSize:CGSizeMake(maxWidth, CGRectGetHeight([view frame]))];
}
[self setAutoresizesSubviews:NO];
[self setFrameSize:CGSizeMake(maxWidth, y)];
[self setAutoresizesSubviews:YES];
}
- (void)setMenu:(CPMenu)aMenu
{
[super setMenu:aMenu];
[self tile];
}
@end
@@ -24,9 +24,10 @@
@import <Foundation/CPObject.j>
@import <Foundation/CPString.j>
@import <AppKit/CPImage.j>
@import <AppKit/CPMenu.j>
@import <AppKit/CPView.j>
@import "CPImage.j"
@import "CPMenu.j"
@import "CPView.j"
@import "_CPMenuItemView.j"
/*!
@ingroup appkit
@@ -108,7 +109,9 @@
_keyEquivalent = aKeyEquivalent || @"";
_keyEquivalentModifierMask = CPPlatformActionKeyMask;
_indentationLevel = 0;
_mnemonicLocation = CPNotFound;
}
@@ -448,20 +451,32 @@ CPOffState
*/
- (void)setSubmenu:(CPMenu)aMenu
{
var supermenu = [_submenu supermenu];
if (supermenu == self)
if (_submenu === aMenu)
return;
var supermenu = [_submenu supermenu];
if (supermenu)
return alert("bad");
[_submenu setSupermenu:_menu];
[CPException raise:CPInvalidArgumentException
reason: @"Can't add submenu \"" + [aMenu title] + "\" to item \"" + [self title] + "\", because it is already submenu of \"" + [[aMenu supermenu] title] + "\""];
_submenu = aMenu;
if (_submenu)
{
[_submenu setSupermenu:_menu];
[self setTarget:_menu];
[self setAction:@selector(submenuAction:)];
}
else
{
[self setTarget:nil];
[self setAction:NULL];
}
[_menuItemView setDirty];
[_menu itemChanged:self];
}
@@ -570,6 +585,43 @@ CPControlKeyMask
return _keyEquivalentModifierMask;
}
- (CPString)keyEquivalentStringRepresentation
{
if (![_keyEquivalent length])
return @"";
var string = _keyEquivalent.toUpperCase(),
needsShift = _keyEquivalentModifierMask & CPShiftKeyMask || string === _keyEquivalent;
if (CPBrowserIsOperatingSystem(CPMacOperatingSystem))
{
if (_keyEquivalentModifierMask & CPCommandKeyMask)
string = "⌘" + string;
if (needsShift)
string = "⇧" + string;
if (_keyEquivalentModifierMask & CPAlternateKeyMask)
string = "⌥" + string;
if (_keyEquivalentModifierMask & CPControlKeyMask)
string = "^" + string;
}
else
{
if (needsShift)
string = "Shift-" + string;
if (_keyEquivalentModifierMask & CPAlternateKeyMask)
string = "Alt-" + string;
if (_keyEquivalentModifierMask & CPControlKeyMask || _keyEquivalentModifierMask & CPCommandKeyMask)
string = "Ctrl-" + string;
}
return string;
}
// Managing Mnemonics
/*!
Sets the index of the mnemonic character in the title. The character
@@ -643,7 +695,7 @@ CPControlKeyMask
- (void)setIndentationLevel:(unsigned)aLevel
{
if (aLevel < 0)
[CPException raise:CPInvalidArgumentException reason:"setIndentationLevel: argument must be greater than 0."];
[CPException raise:CPInvalidArgumentException reason:"setIndentationLevel: argument must be greater than or equal to 0."];
_indentationLevel = MIN(15, aLevel);
}
@@ -742,6 +794,11 @@ CPControlKeyMask
return _menuItemView;
}
- (BOOL)_isSelectable
{
return ![self submenu] || [self action] !== @selector(submenuAction:) || [self target] !== [self menu];
}
@end
var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
@@ -765,6 +822,8 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
CPMenuItemKeyEquivalentKey = @"CPMenuItemKeyEquivalentKey",
CPMenuItemKeyEquivalentModifierMaskKey = @"CPMenuItemKeyEquivalentModifierMaskKey",
CPMenuItemIndentationLevelKey = @"CPMenuItemIndentationLevelKey",
CPMenuItemRepresentedObjectKey = @"CPMenuItemRepresentedObjectKey",
CPMenuItemViewKey = @"CPMenuItemViewKey";
@@ -804,8 +863,9 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
// CPImage _offStateImage;
// CPImage _mixedStateImage;
_submenu = DEFAULT_VALUE(CPMenuItemSubmenuKey, nil);
// This order matters because setSubmenu: needs _menu to be around.
_menu = DEFAULT_VALUE(CPMenuItemMenuKey, nil);
[self setSubmenu:DEFAULT_VALUE(CPMenuItemSubmenuKey, nil)];
_keyEquivalent = [aCoder decodeObjectForKey:CPMenuItemKeyEquivalentKey] || @"";
_keyEquivalentModifierMask = [aCoder decodeObjectForKey:CPMenuItemKeyEquivalentModifierMaskKey] || 0;
@@ -813,7 +873,9 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
// int _mnemonicLocation;
// BOOL _isAlternate;
// int _indentationLevel;
// Default is 0.
[self setIndentationLevel:[aCoder decodeIntForKey:CPMenuItemIndentationLevelKey] || 0];
// CPString _toolTip;
@@ -856,423 +918,11 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
if (_keyEquivalentModifierMask)
[aCoder encodeObject:_keyEquivalentModifierMask forKey:CPMenuItemKeyEquivalentModifierMaskKey];
if (_indentationLevel > 0)
[aCoder encodeInt:_indentationLevel forKey:CPMenuItemIndentationLevelKey];
ENCODE_IFNOT(CPMenuItemRepresentedObjectKey, _representedObject, nil);
ENCODE_IFNOT(CPMenuItemViewKey, _view, nil);
}
@end
var LEFT_MARGIN = 3.0,
RIGHT_MARGIN = 16.0,
STATE_COLUMN_WIDTH = 14.0,
INDENTATION_WIDTH = 17.0,
VERTICAL_MARGIN = 4.0;
var _CPMenuItemSelectionColor = nil,
_CPMenuItemTextShadowColor = nil,
_CPMenuItemDefaultStateImages = [],
_CPMenuItemDefaultStateHighlightedImages = [];
/*
@ignore
*/
@implementation _CPMenuItemView : CPView
{
CPMenuItem _menuItem;
CPFont _font;
CPColor _textColor;
CPColor _textShadowColor;
CPColor _activateColor;
CPColor _activateShadowColor;
CGSize _minSize;
BOOL _isDirty;
BOOL _showsStateColumn;
BOOL _belongsToMenuBar;
CPImageView _stateView;
_CPImageAndTextView _imageAndTextView;
CPView _submenuView;
}
+ (void)initialize
{
if (self != [_CPMenuItemView class])
return;
_CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0];
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0]
var bundle = [CPBundle bundleForClass:self];
_CPMenuItemDefaultStateImages[CPOffState] = nil;
_CPMenuItemDefaultStateHighlightedImages[CPOffState] = nil;
_CPMenuItemDefaultStateImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnState.png"] size:CGSizeMake(14.0, 14.0)];
_CPMenuItemDefaultStateHighlightedImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnStateHighlighted.png"] size:CGSizeMake(14.0, 14.0)];
_CPMenuItemDefaultStateImages[CPMixedState] = nil;
_CPMenuItemDefaultStateHighlightedImages[CPMixedState] = nil;
}
+ (float)leftMargin
{
return LEFT_MARGIN + STATE_COLUMN_WIDTH;
}
- (id)initWithFrame:(CGRect)aFrame forMenuItem:(CPMenuItem)aMenuItem
{
self = [super initWithFrame:aFrame];
if (self)
{
_menuItem = aMenuItem;
_showsStateColumn = YES;
_isDirty = YES;
[self setAutoresizingMask:CPViewWidthSizable];
[self synchronizeWithMenuItem];
}
return self;
}
- (CGSize)minSize
{
return _minSize;
}
- (void)setDirty
{
_isDirty = YES;
}
- (void)synchronizeWithMenuItem
{
if (!_isDirty)
return;
_isDirty = NO;
var view = [_menuItem view];
if ([_menuItem isSeparatorItem])
{
var line = [[CPView alloc] initWithFrame:CGRectMake(0.0, 5.0, 10.0, 1.0)];
view = [[CPView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 10.0)];
[view setAutoresizingMask:CPViewWidthSizable];
[line setAutoresizingMask:CPViewWidthSizable];
[line setBackgroundColor:[CPColor lightGrayColor]];
[view addSubview:line];
}
if (view)
{
[_imageAndTextView removeFromSuperview];
_imageAndTextView = nil;
[_stateView removeFromSuperview];
_stateView = nil;
[_submenuView removeFromSuperview];
_submenuView = nil;
_minSize = [view frame].size;
[self setFrameSize:_minSize];
[self addSubview:view];
return;
}
// State Column
var x = _belongsToMenuBar ? 0.0 : (LEFT_MARGIN + [_menuItem indentationLevel] * INDENTATION_WIDTH);
if (_showsStateColumn)
{
if (!_stateView)
{
_stateView = [[CPImageView alloc] initWithFrame:CGRectMake(x, (CGRectGetHeight([self frame]) - STATE_COLUMN_WIDTH) / 2.0, STATE_COLUMN_WIDTH, STATE_COLUMN_WIDTH)];
[_stateView setAutoresizingMask:CPViewMinYMargin | CPViewMaxYMargin];
[self addSubview:_stateView];
}
var state = [_menuItem state];
switch (state)
{
case CPOffState:
case CPOnState:
case CPMixedState: [_stateView setImage:_CPMenuItemDefaultStateImages[state]];
break;
default: [_stateView setImage:nil];
}
x += STATE_COLUMN_WIDTH;
}
else
{
[_stateView removeFromSuperview];
_stateView = nil;
}
// Image and Title
if (!_imageAndTextView)
{
_imageAndTextView = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 0.0)];
[_imageAndTextView setImagePosition:CPImageLeft];
[_imageAndTextView setTextShadowOffset:CGSizeMake(0.0, 1.0)];
[self addSubview:_imageAndTextView];
}
var font = [_menuItem font];
if (!font)
font = _font;
[_imageAndTextView setFont:font];
[_imageAndTextView setVerticalAlignment:CPCenterVerticalTextAlignment];
[_imageAndTextView setImage:[_menuItem image]];
[_imageAndTextView setText:[_menuItem title]];
[_imageAndTextView setTextColor:[self textColor]];
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
[_imageAndTextView setTextShadowOffset:CGSizeMake(0, 1)];
[_imageAndTextView setFrameOrigin:CGPointMake(x, VERTICAL_MARGIN)];
[_imageAndTextView sizeToFit];
var frame = [_imageAndTextView frame];
// frame.size.height += 1.0;
// [_imageAndTextView setFrame:frame];
frame.size.height += 2 * VERTICAL_MARGIN;
x += CGRectGetWidth(frame);
// Submenu Arrow
if ([_menuItem hasSubmenu])
{
x += 3.0;
if (!_submenuView)
{
_submenuView = [[_CPMenuItemArrowView alloc] initWithFrame:CGRectMake(0.0, 0.0, 10.0, 10.0)];
[self addSubview:_submenuView];
}
[_submenuView setHidden:NO];
[_submenuView setColor:_belongsToMenuBar ? [self textColor] : nil];
[_submenuView setFrameOrigin:CGPointMake(x, (CGRectGetHeight(frame) - 10.0) / 2.0)];
x += 10.0;
}
else
[_submenuView setHidden:YES];
_minSize = CGSizeMake(x + (_belongsToMenuBar ? 0.0 : RIGHT_MARGIN) + 3.0, CGRectGetHeight(frame));
[self setFrameSize:_minSize];
}
- (CGFloat)overlapOffsetWidth
{
return LEFT_MARGIN + ([[_menuItem menu] showsStateColumn] ? STATE_COLUMN_WIDTH : 0.0);
}
- (void)setShowsStateColumn:(BOOL)shouldShowStateColumn
{
_showsStateColumn = shouldShowStateColumn;
}
- (void)setBelongsToMenuBar:(BOOL)shouldBelongToMenuBar
{
_belongsToMenuBar = shouldBelongToMenuBar;
}
- (void)highlight:(BOOL)shouldHighlight
{
// ASSERT(![_menuItem view]);
if (_belongsToMenuBar)
[_imageAndTextView setImage:shouldHighlight ? [_menuItem alternateImage] : [_menuItem image]];
else if ([_menuItem isEnabled])
{
if (shouldHighlight)
{
[self setBackgroundColor:_CPMenuItemSelectionColor];
[_imageAndTextView setTextColor:[CPColor whiteColor]];
[_imageAndTextView setTextShadowColor:_CPMenuItemTextShadowColor];
}
else
{
[self setBackgroundColor:nil];
[_imageAndTextView setTextColor:[self textColor]];
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
}
var state = [_menuItem state];
switch (state)
{
case CPOffState:
case CPOnState:
case CPMixedState: [_stateView setImage:shouldHighlight ? _CPMenuItemDefaultStateHighlightedImages[state] : _CPMenuItemDefaultStateImages[state]];
break;
default: [_stateView setImage:nil];
}
}
}
- (void)activate:(BOOL)shouldActivate
{
[_imageAndTextView setImage:[_menuItem image]];
if (shouldActivate)
{
[_imageAndTextView setTextColor:[self activateColor] || [CPColor whiteColor]];
[_imageAndTextView setTextShadowColor:[self activateShadowColor] || [CPColor blackColor]];
[_submenuView setColor:[self activateColor] || [CPColor whiteColor]];
}
else
{
[_imageAndTextView setTextColor:[self textColor]];
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
[_submenuView setColor:[self textColor]];
}
}
- (BOOL)eventOnSubmenu:(CPEvent)anEvent
{
if (![_menuItem hasSubmenu])
return NO;
return CGRectContainsPoint([_submenuView frame], [self convertPoint:[anEvent locationInWindow] fromView:nil]);
}
- (BOOL)isHidden
{
return [_menuItem isHidden];
}
- (CPMenuItem)menuItem
{
return _menuItem;
}
- (void)setFont:(CPFont)aFont
{
if (_font == aFont)
return;
_font = aFont;
[self setDirty];
}
- (void)setTextColor:(CPColor)aColor
{
if (_textColor == aColor)
return;
_textColor = aColor;
[_imageAndTextView setTextColor:[self textColor]];
[_submenuView setColor:[self textColor]];
}
- (CPColor)textColor
{
return [_menuItem isEnabled] ? (_textColor ? _textColor : [CPColor colorWithCalibratedRed:70.0 / 255.0 green:69.0 / 255.0 blue:69.0 / 255.0 alpha:1.0]) : [CPColor lightGrayColor];
}
- (void)setTextShadowColor:(CPColor)aColor
{
if (_textShadowColor == aColor)
return;
_textShadowColor = aColor;
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
//[_submenuView setColor:[self textColor]];
}
- (CPColor)textShadowColor
{
return [_menuItem isEnabled] ? (_textShadowColor ? _textShadowColor : [CPColor colorWithWhite:1.0 alpha:0.8]) : [CPColor colorWithWhite:0.8 alpha:0.8];
}
- (void)setActivateColor:(CPColor)aColor
{
_activateColor = aColor;
}
- (CPColor)activateColor
{
return _activateColor;
}
- (void)setActivateShadowColor:(CPColor)aColor
{
_activateShadowColor = aColor;
}
- (CPColor)activateShadowColor
{
return _activateShadowColor;
}
@end
@implementation _CPMenuItemArrowView : CPView
{
CPColor _color;
}
- (void)setColor:(CPColor)aColor
{
if (_color == aColor)
return;
_color = aColor;
[self setNeedsDisplay:YES];
}
- (void)drawRect:(CGRect)aRect
{
var context = [[CPGraphicsContext currentContext] graphicsPort];
CGContextBeginPath(context);
CGContextMoveToPoint(context, 1.0, 4.0);
CGContextAddLineToPoint(context, 9.0, 4.0);
CGContextAddLineToPoint(context, 5.0, 8.0);
CGContextAddLineToPoint(context, 1.0, 4.0);
CGContextClosePath(context);
CGContextSetFillColor(context, _color);
CGContextFillPath(context);
}
@end
+232
View File
@@ -0,0 +1,232 @@
var HORIZONTAL_MARGIN = 8.0,
SUBMENU_INDICATOR_MARGIN = 3.0,
VERTICAL_MARGIN = 4.0;
var SelectionColor = nil,
SUBMENU_INDICATOR_COLOR = nil,
_CPMenuItemSelectionColor = nil,
_CPMenuItemTextShadowColor = nil,
_CPMenuItemDefaultStateImages = [],
_CPMenuItemDefaultStateHighlightedImages = [];
@implementation _CPMenuItemMenuBarView : CPView
{
CPMenuItem _menuItem @accessors(property=menuItem);
CPFont _font;
CPColor _textColor;
CPColor _textShadowColor;
BOOL _isDirty;
_CPImageAndTextView _imageAndTextView;
CPView _submenuIndicatorView;
}
+ (void)initialize
{
if (self !== [_CPMenuItemMenuBarView class])
return;
var bundle = [CPBundle bundleForClass:self];
SelectionColor = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuBarWindow/_CPMenuBarWindowBackgroundSelected.png"] size:CGSizeMake(1.0, 28.0)]];
SUBMENU_INDICATOR_COLOR = [CPColor grayColor];
_CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0];
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0];
_CPMenuItemDefaultStateImages[CPOffState] = nil;
_CPMenuItemDefaultStateHighlightedImages[CPOffState] = nil;
_CPMenuItemDefaultStateImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnState.png"] size:CGSizeMake(14.0, 14.0)];
_CPMenuItemDefaultStateHighlightedImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnStateHighlighted.png"] size:CGSizeMake(14.0, 14.0)];
_CPMenuItemDefaultStateImages[CPMixedState] = nil;
_CPMenuItemDefaultStateHighlightedImages[CPMixedState] = nil;
}
+ (id)view
{
return [[self alloc] init];
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
_imageAndTextView = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(HORIZONTAL_MARGIN, 0.0, 0.0, 0.0)];
[_imageAndTextView setImagePosition:CPImageLeft];
[_imageAndTextView setTextShadowOffset:CGSizeMake(0.0, 1.0)];
[_imageAndTextView setAutoresizingMask:CPViewMinYMargin | CPViewMaxYMargin];
[self addSubview:_imageAndTextView];
_submenuIndicatorView = [[_CPMenuItemMenuBarSubmenuIndicatorView alloc] initWithFrame:CGRectMake(0.0, 0.0, 9.0, 6.0)];
[_submenuIndicatorView setAutoresizingMask:CPViewMinYMargin | CPViewMaxYMargin];
[self addSubview:_submenuIndicatorView];
[self setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
}
return self;
}
- (CPColor)textColor
{
if (![_menuItem isEnabled])
return [CPColor lightGrayColor];
return _textColor || [CPColor colorWithCalibratedRed:70.0 / 255.0 green:69.0 / 255.0 blue:69.0 / 255.0 alpha:1.0];
}
- (CPColor)textShadowColor
{
if (![_menuItem isEnabled])
return [CPColor colorWithWhite:0.8 alpha:0.8];
return _textShadowColor || [CPColor colorWithWhite:1.0 alpha:0.8];
}
- (void)update
{
var x = HORIZONTAL_MARGIN,
height = 0.0;
[_imageAndTextView setFont:[_menuItem font] || [_CPMenuBarWindow font]];
[_imageAndTextView setVerticalAlignment:CPCenterVerticalTextAlignment];
[_imageAndTextView setImage:[_menuItem image]];
[_imageAndTextView setText:[_menuItem title]];
[_imageAndTextView setTextColor:[self textColor]];
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
[_imageAndTextView setTextShadowOffset:CGSizeMake(0.0, 1.0)];
[_imageAndTextView sizeToFit];
var imageAndTextViewFrame = [_imageAndTextView frame];
imageAndTextViewFrame.origin.x = x;
x += CGRectGetWidth(imageAndTextViewFrame);
height = MAX(height, CGRectGetHeight(imageAndTextViewFrame));
var hasSubmenuIndicator = [_menuItem hasSubmenu] && [_menuItem action];
if (hasSubmenuIndicator)
{
[_submenuIndicatorView setHidden:NO];
[_submenuIndicatorView setColor:[self textColor]];
[_submenuIndicatorView setShadowColor:[self textShadowColor]];
var submenuViewFrame = [_submenuIndicatorView frame];
submenuViewFrame.origin.x = x + SUBMENU_INDICATOR_MARGIN;
x = CGRectGetMaxX(submenuViewFrame);
height = MAX(height, CGRectGetHeight(submenuViewFrame));
}
else
[_submenuIndicatorView setHidden:YES];
height += 2.0 * VERTICAL_MARGIN;
imageAndTextViewFrame.origin.y = FLOOR((height - CGRectGetHeight(imageAndTextViewFrame)) / 2.0);
[_imageAndTextView setFrame:imageAndTextViewFrame];
if (hasSubmenuIndicator)
{
submenuViewFrame.origin.y = FLOOR((height - CGRectGetHeight(submenuViewFrame)) / 2.0) + 1.0;
[_submenuIndicatorView setFrame:submenuViewFrame];
}
_minSize = CGSizeMake(x + HORIZONTAL_MARGIN, height);
[self setAutoresizesSubviews:NO];
[self setFrameSize:_minSize];
[self setAutoresizesSubviews:YES];
}
- (void)highlight:(BOOL)shouldHighlight
{
// FIXME: This should probably be even throw.
if (![_menuItem isEnabled])
return;
if (shouldHighlight)
{
[self setBackgroundColor:SelectionColor];
[_imageAndTextView setTextColor:[CPColor whiteColor]];
[_imageAndTextView setTextShadowColor:_CPMenuItemTextShadowColor];
[_submenuIndicatorView setColor:[CPColor whiteColor]];
[_submenuIndicatorView setShadowColor:[CPColor colorWithWhite:0.1 alpha:0.7]];
}
else
{
[self setBackgroundColor:nil];
[_imageAndTextView setTextColor:[self textColor]];
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
[_submenuIndicatorView setColor:[self textColor]];
[_submenuIndicatorView setShadowColor:[self textShadowColor]];
}
}
@end
@implementation _CPMenuItemMenuBarSubmenuIndicatorView : CPView
{
CPColor _color;
CPColor _shadowColor;
}
- (void)setColor:(CPColor)aColor
{
if (_color === aColor)
return;
_color = aColor;
[self setNeedsDisplay:YES];
}
- (void)setShadowColor:(CPColor)aColor
{
if (_shadowColor === aColor)
return;
_shadowColor = aColor;
[self setNeedsDisplay:YES];
}
- (void)drawRect:(CGRect)aRect
{
var context = [[CPGraphicsContext currentContext] graphicsPort],
bounds = [self bounds];
bounds.size.height -= 1.0;
bounds.size.width -= 2.0;
bounds.origin.x += 1.0;
CGContextBeginPath(context);
CGContextMoveToPoint(context, CGRectGetMinX(bounds), CGRectGetMinY(bounds));
CGContextAddLineToPoint(context, CGRectGetMaxX(bounds), CGRectGetMinY(bounds));
CGContextAddLineToPoint(context, CGRectGetMidX(bounds), CGRectGetMaxY(bounds));
CGContextClosePath(context);
CGContextSetShadowWithColor(context, CGSizeMake(0.0, 1.0), 1.1, _shadowColor);
CGContextSetFillColor(context, _color);
CGContextFillPath(context);
}
@end
@@ -0,0 +1,38 @@
@import <AppKit/CPView.j>
@implementation _CPMenuItemSeparatorView : CPView
{
}
+ (id)view
{
return [[self alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 10.0)];
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
[self setAutoresizingMask:CPViewWidthSizable];
return self;
}
- (void)drawRect:(CGRect)aRect
{
var context = [[CPGraphicsContext currentContext] graphicsPort],
bounds = [self bounds];
CGContextBeginPath(context);
CGContextMoveToPoint(context, CGRectGetMinX(bounds), FLOOR(CGRectGetMidY(bounds)) - 0.5);
CGContextAddLineToPoint(context, CGRectGetMaxX(bounds), FLOOR(CGRectGetMidY(bounds)) - 0.5);
CGContextSetStrokeColor(context, [CPColor lightGrayColor]);
CGContextStrokePath(context);
}
@end
+298
View File
@@ -0,0 +1,298 @@
var LEFT_MARGIN = 3.0,
RIGHT_MARGIN = 14.0 + 3.0,
STATE_COLUMN_WIDTH = 14.0,
INDENTATION_WIDTH = 17.0,
VERTICAL_MARGIN = 4.0,
RIGHT_COLUMNS_MARGIN = 30.0,
KEY_EQUIVALENT_MARGIN = 10.0;
var SUBMENU_INDICATOR_COLOR = nil,
_CPMenuItemSelectionColor = nil,
_CPMenuItemTextShadowColor = nil,
_CPMenuItemDefaultStateImages = [],
_CPMenuItemDefaultStateHighlightedImages = [];
@implementation _CPMenuItemStandardView : CPView
{
CPMenuItem _menuItem @accessors(property=menuItem);
CPFont _font;
CPColor _textColor;
CPColor _textShadowColor;
CGSize _minSize @accessors(readonly, property=minSize);
BOOL _isDirty;
CPImageView _stateView;
_CPImageAndTextView _imageAndTextView;
_CPImageAndTextView _keyEquivalentView;
CPView _submenuIndicatorView;
}
+ (void)initialize
{
if (self !== [_CPMenuItemStandardView class])
return;
SUBMENU_INDICATOR_COLOR = [CPColor grayColor];
_CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0];
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0]
var bundle = [CPBundle bundleForClass:self];
_CPMenuItemDefaultStateImages[CPOffState] = nil;
_CPMenuItemDefaultStateHighlightedImages[CPOffState] = nil;
_CPMenuItemDefaultStateImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnState.png"] size:CGSizeMake(14.0, 14.0)];
_CPMenuItemDefaultStateHighlightedImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnStateHighlighted.png"] size:CGSizeMake(14.0, 14.0)];
_CPMenuItemDefaultStateImages[CPMixedState] = nil;
_CPMenuItemDefaultStateHighlightedImages[CPMixedState] = nil;
}
+ (id)view
{
return [[self alloc] init];
}
+ (float)_standardLeftMargin
{
return LEFT_MARGIN + STATE_COLUMN_WIDTH;
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
_stateView = [[CPImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 0.0)];
[_stateView setImageScaling:CPScaleNone];
[self addSubview:_stateView];
_imageAndTextView = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 0.0)];
[_imageAndTextView setImagePosition:CPImageLeft];
[_imageAndTextView setTextShadowOffset:CGSizeMake(0.0, 1.0)];
[self addSubview:_imageAndTextView];
_keyEquivalentView = [[_CPImageAndTextView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 0.0)];
[_keyEquivalentView setImagePosition:CPNoImage];
[_keyEquivalentView setTextShadowOffset:CGSizeMake(0.0, 1.0)];
[_keyEquivalentView setAutoresizingMask:CPViewMinXMargin];
[self addSubview:_keyEquivalentView];
_submenuIndicatorView = [[_CPMenuItemSubmenuIndicatorView alloc] initWithFrame:CGRectMake(0.0, 0.0, 8.0, 10.0)];
[_submenuIndicatorView setColor:SUBMENU_INDICATOR_COLOR];
[_submenuIndicatorView setAutoresizingMask:CPViewMinXMargin];
[self addSubview:_submenuIndicatorView];
[self setAutoresizingMask:CPViewWidthSizable];
}
return self;
}
- (CPColor)textColor
{
if (![_menuItem isEnabled])
return [CPColor lightGrayColor];
return _textColor || [CPColor colorWithCalibratedRed:70.0 / 255.0 green:69.0 / 255.0 blue:69.0 / 255.0 alpha:1.0];
}
- (CPColor)textShadowColor
{
if (![_menuItem isEnabled])
return nil;
return _textShadowColor || [CPColor colorWithWhite:1.0 alpha:0.8];
}
- (void)setFont:(CPFont)aFont
{
_font = aFont;
}
- (void)update
{
var x = LEFT_MARGIN + [_menuItem indentationLevel] * INDENTATION_WIDTH,
height = 0.0,
hasStateColumn = [[_menuItem menu] showsStateColumn];
if (hasStateColumn)
{
[_stateView setHidden:NO];
[_stateView setImage:_CPMenuItemDefaultStateImages[[_menuItem state]] || nil];
x += STATE_COLUMN_WIDTH;
}
else
[_stateView setHidden:YES];
[_imageAndTextView setFont:[_menuItem font] || _font];
[_imageAndTextView setVerticalAlignment:CPCenterVerticalTextAlignment];
[_imageAndTextView setImage:[_menuItem image]];
[_imageAndTextView setText:[_menuItem title]];
[_imageAndTextView setTextColor:[self textColor]];
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
[_imageAndTextView setTextShadowOffset:CGSizeMake(0.0, 1.0)];
[_imageAndTextView sizeToFit];
var imageAndTextViewFrame = [_imageAndTextView frame];
imageAndTextViewFrame.origin.x = x;
x += CGRectGetWidth(imageAndTextViewFrame);
height = MAX(height, CGRectGetHeight(imageAndTextViewFrame));
var hasKeyEquivalent = !![_menuItem keyEquivalent],
hasSubmenu = [_menuItem hasSubmenu];
if (hasKeyEquivalent || hasSubmenu)
x += RIGHT_COLUMNS_MARGIN;
if (hasKeyEquivalent)
{
[_keyEquivalentView setFont:[_menuItem font] || _font];
[_keyEquivalentView setVerticalAlignment:CPCenterVerticalTextAlignment];
[_keyEquivalentView setImage:[_menuItem image]];
[_keyEquivalentView setText:[_menuItem keyEquivalentStringRepresentation]];
[_keyEquivalentView setTextColor:[self textColor]];
[_keyEquivalentView setTextShadowColor:[self textShadowColor]];
[_keyEquivalentView setTextShadowOffset:CGSizeMake(0, 1)];
[_keyEquivalentView setFrameOrigin:CGPointMake(x, VERTICAL_MARGIN)];
[_keyEquivalentView sizeToFit];
var keyEquivalentViewFrame = [_keyEquivalentView frame];
keyEquivalentViewFrame.origin.x = x;
x += CGRectGetWidth(keyEquivalentViewFrame);
height = MAX(height, CGRectGetHeight(keyEquivalentViewFrame));
if (hasSubmenu)
x += RIGHT_COLUMNS_MARGIN;
}
else
[_keyEquivalentView setHidden:YES];
if (hasSubmenu)
{
[_submenuIndicatorView setHidden:NO];
var submenuViewFrame = [_submenuIndicatorView frame];
submenuViewFrame.origin.x = x;
x += CGRectGetWidth(submenuViewFrame);
height = MAX(height, CGRectGetHeight(submenuViewFrame));
}
else
[_submenuIndicatorView setHidden:YES];
height += 2.0 * VERTICAL_MARGIN;
imageAndTextViewFrame.origin.y = FLOOR((height - CGRectGetHeight(imageAndTextViewFrame)) / 2.0);
[_imageAndTextView setFrame:imageAndTextViewFrame];
if (hasStateColumn)
[_stateView setFrameSize:CGSizeMake(STATE_COLUMN_WIDTH, height)];
if (hasKeyEquivalent)
{
keyEquivalentViewFrame.origin.y = FLOOR((height - CGRectGetHeight(keyEquivalentViewFrame)) / 2.0);
[_keyEquivalentView setFrame:keyEquivalentViewFrame];
}
if (hasSubmenu)
{
submenuViewFrame.origin.y = FLOOR((height - CGRectGetHeight(submenuViewFrame)) / 2.0);
[_submenuIndicatorView setFrame:submenuViewFrame];
}
_minSize = CGSizeMake(x + RIGHT_MARGIN, height);
[self setAutoresizesSubviews:NO];
[self setFrameSize:_minSize];
[self setAutoresizesSubviews:YES];
}
- (void)highlight:(BOOL)shouldHighlight
{
// FIXME: This should probably be even throw.
if (![_menuItem isEnabled])
return;
if (shouldHighlight)
{
[self setBackgroundColor:_CPMenuItemSelectionColor];
[_imageAndTextView setTextColor:[CPColor whiteColor]];
[_keyEquivalentView setTextColor:[CPColor whiteColor]];
[_submenuIndicatorView setColor:[CPColor whiteColor]];
[_imageAndTextView setTextShadowColor:_CPMenuItemTextShadowColor];
[_keyEquivalentView setTextShadowColor:_CPMenuItemTextShadowColor];
}
else
{
[self setBackgroundColor:nil];
[_imageAndTextView setTextColor:[self textColor]];
[_keyEquivalentView setTextColor:[self textColor]];
[_submenuIndicatorView setColor:SUBMENU_INDICATOR_COLOR];
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
[_keyEquivalentView setTextShadowColor:[self textShadowColor]];
}
if (shouldHighlight)
[_stateView setImage:_CPMenuItemDefaultStateHighlightedImages[[_menuItem state]] || nil];
else
[_stateView setImage:_CPMenuItemDefaultStateImages[[_menuItem state]] || nil];
}
@end
@implementation _CPMenuItemSubmenuIndicatorView : CPView
{
CPColor _color;
}
- (void)setColor:(CPColor)aColor
{
if (_color === aColor)
return;
_color = aColor;
[self setNeedsDisplay:YES];
}
- (void)drawRect:(CGRect)aRect
{
var context = [[CPGraphicsContext currentContext] graphicsPort],
bounds = [self bounds];
CGContextBeginPath(context);
CGContextMoveToPoint(context, CGRectGetMinX(bounds), CGRectGetMinY(bounds));
CGContextAddLineToPoint(context, CGRectGetMaxX(bounds), CGRectGetMidY(bounds));
CGContextAddLineToPoint(context, CGRectGetMinX(bounds), CGRectGetMaxY(bounds));
CGContextClosePath(context);
CGContextSetFillColor(context, _color);
CGContextFillPath(context);
}
@end
+273
View File
@@ -0,0 +1,273 @@
@import "_CPMenuItemSeparatorView.j"
@import "_CPMenuItemStandardView.j"
@import "_CPMenuItemMenuBarView.j"
var LEFT_MARGIN = 3.0,
RIGHT_MARGIN = 16.0,
STATE_COLUMN_WIDTH = 14.0,
INDENTATION_WIDTH = 17.0,
VERTICAL_MARGIN = 4.0;
var _CPMenuItemSelectionColor = nil,
_CPMenuItemTextShadowColor = nil,
_CPMenuItemDefaultStateImages = [],
_CPMenuItemDefaultStateHighlightedImages = [];
/*
@ignore
*/
@implementation _CPMenuItemView : CPView
{
CPMenuItem _menuItem;
CPView _view;
CPFont _font;
CPColor _textColor;
CPColor _textShadowColor;
CGSize _minSize;
BOOL _isDirty;
BOOL _showsStateColumn;
CPImageView _stateView;
_CPImageAndTextView _imageAndTextView;
CPView _submenuView;
}
+ (void)initialize
{
if (self != [_CPMenuItemView class])
return;
_CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0];
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0]
var bundle = [CPBundle bundleForClass:self];
_CPMenuItemDefaultStateImages[CPOffState] = nil;
_CPMenuItemDefaultStateHighlightedImages[CPOffState] = nil;
_CPMenuItemDefaultStateImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnState.png"] size:CGSizeMake(14.0, 14.0)];
_CPMenuItemDefaultStateHighlightedImages[CPOnState] = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPMenuItem/CPMenuItemOnStateHighlighted.png"] size:CGSizeMake(14.0, 14.0)];
_CPMenuItemDefaultStateImages[CPMixedState] = nil;
_CPMenuItemDefaultStateHighlightedImages[CPMixedState] = nil;
}
+ (float)leftMargin
{
return LEFT_MARGIN + STATE_COLUMN_WIDTH;
}
- (id)initWithFrame:(CGRect)aFrame forMenuItem:(CPMenuItem)aMenuItem
{
self = [super initWithFrame:aFrame];
if (self)
{
_menuItem = aMenuItem;
_showsStateColumn = YES;
_isDirty = YES;
[self setAutoresizingMask:CPViewWidthSizable];
[self synchronizeWithMenuItem];
}
return self;
}
- (CGSize)minSize
{
return _minSize;
}
- (void)setDirty
{
_isDirty = YES;
}
- (void)synchronizeWithMenuItem
{
var menuItemView = [_menuItem view];
if ([_menuItem isSeparatorItem])
{
if (![_view isKindOfClass:[_CPMenuItemSeparatorView class]])
{
[_view removeFromSuperview];
_view = [_CPMenuItemSeparatorView view];
}
}
else if (menuItemView)
{
if (_view !== menuItemView)
{
[_view removeFromSuperview];
_view = menuItemView;
}
}
else if ([_menuItem menu] == [CPApp mainMenu])
{
if (![_view isKindOfClass:[_CPMenuItemMenuBarView class]])
{
[_view removeFromSuperview];
_view = [_CPMenuItemMenuBarView view];
}
[_view setMenuItem:_menuItem];
}
else
{
if (![_view isKindOfClass:[_CPMenuItemStandardView class]])
{
[_view removeFromSuperview];
_view = [_CPMenuItemStandardView view];
}
[_view setMenuItem:_menuItem];
}
if ([_view superview] !== self)
[self addSubview:_view];
if ([_view respondsToSelector:@selector(update)])
[_view update];
_minSize = [_view frame].size;
[self setAutoresizesSubviews:NO];
[self setFrameSize:_minSize];
[self setAutoresizesSubviews:YES];
}
- (void)setShowsStateColumn:(BOOL)shouldShowStateColumn
{
_showsStateColumn = shouldShowStateColumn;
}
- (void)highlight:(BOOL)shouldHighlight
{
if ([_view respondsToSelector:@selector(highlight:)])
[_view highlight:shouldHighlight];
}
- (void)activate:(BOOL)shouldActivate
{
[_imageAndTextView setImage:[_menuItem image]];
if (shouldActivate)
{
[_imageAndTextView setTextColor:[self activateColor] || [CPColor whiteColor]];
[_imageAndTextView setTextShadowColor:[self activateShadowColor] || [CPColor blackColor]];
[_submenuView setColor:[self activateColor] || [CPColor whiteColor]];
}
else
{
[_imageAndTextView setTextColor:[self textColor]];
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
[_submenuView setColor:[self textColor]];
}
}
- (BOOL)eventOnSubmenu:(CPEvent)anEvent
{
if (![_menuItem hasSubmenu])
return NO;
return CGRectContainsPoint([_submenuView frame], [self convertPoint:[anEvent locationInWindow] fromView:nil]);
}
- (BOOL)isHidden
{
return [_menuItem isHidden];
}
- (CPMenuItem)menuItem
{
return _menuItem;
}
- (void)setFont:(CPFont)aFont
{
if (_font === aFont)
return;
_font = aFont;
if ([_view respondsToSelector:@selector(setFont:)])
[_view setFont:aFont];
[self setDirty];
}
- (void)setTextColor:(CPColor)aColor
{
if (_textColor == aColor)
return;
_textColor = aColor;
[_imageAndTextView setTextColor:[self textColor]];
[_submenuView setColor:[self textColor]];
}
- (CPColor)textColor
{
return nil;
}
- (void)setTextShadowColor:(CPColor)aColor
{
if (_textShadowColor == aColor)
return;
_textShadowColor = aColor;
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
//[_submenuView setColor:[self textColor]];
}
- (CPColor)textShadowColor
{
return [_menuItem isEnabled] ? (_textShadowColor ? _textShadowColor : [CPColor colorWithWhite:1.0 alpha:0.8]) : [CPColor colorWithWhite:0.8 alpha:0.8];
}
@end
@implementation _CPMenuItemArrowView : CPView
{
CPColor _color;
}
- (void)setColor:(CPColor)aColor
{
if (_color == aColor)
return;
_color = aColor;
[self setNeedsDisplay:YES];
}
- (void)drawRect:(CGRect)aRect
{
var context = [[CPGraphicsContext currentContext] graphicsPort];
CGContextBeginPath(context);
CGContextMoveToPoint(context, 1.0, 4.0);
CGContextAddLineToPoint(context, 9.0, 4.0);
CGContextAddLineToPoint(context, 5.0, 8.0);
CGContextAddLineToPoint(context, 1.0, 4.0);
CGContextClosePath(context);
CGContextSetFillColor(context, _color);
CGContextFillPath(context);
}
@end
+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;
+82 -10
View File
@@ -43,11 +43,14 @@ CPURLPboardType = @"CPURLPboardType";
CPImagesPboardType = @"CPImagesPboardType";
CPVideosPboardType = @"CPVideosPboardType";
UTF8PboardType = @"public.utf8-plain-text";
// Deprecated
CPImagePboardType = @"CPImagePboardType";
var CPPasteboards = nil;
var CPPasteboards = nil,
supportsNativePasteboard = NO;
/*!
@ingroup appkit
@@ -63,6 +66,8 @@ var CPPasteboards = nil;
unsigned _changeCount;
CPString _stateUID;
WebScriptObject _nativePasteboard;
}
/*
@@ -76,6 +81,9 @@ var CPPasteboards = nil;
[self setVersion:1.0];
CPPasteboards = [CPDictionary dictionary];
if (typeof window.cpPasteboardWithName !== "undefined")
supportsNativePasteboard = YES;
}
/*!
@@ -94,7 +102,7 @@ var CPPasteboards = nil;
+ (id)pasteboardWithName:(CPString)aName
{
var pasteboard = [CPPasteboards objectForKey:aName];
if (pasteboard)
return pasteboard;
@@ -118,6 +126,12 @@ var CPPasteboards = nil;
_provided = [CPDictionary dictionary];
_changeCount = 0;
if (supportsNativePasteboard)
{
_nativePasteboard = window.cpPasteboardWithName(aName);
[self _synchronizePasteboard];
}
}
return self;
@@ -146,7 +160,16 @@ var CPPasteboards = nil;
[_owners setObject:anOwner forKey:type];
}
if (_nativePasteboard)
{
var nativeTypes = [types copy];
if ([types containsObject:CPStringPboardType])
nativeTypes.push(UTF8PboardType);
_nativePasteboard.addTypes_(nativeTypes);
}
return ++_changeCount;
}
@@ -157,6 +180,12 @@ var CPPasteboards = nil;
@return the pasteboard's change count
*/
- (unsigned)declareTypes:(CPArray)types owner:(id)anOwner
{
[self _declareTypes:types owner:anOwner updateNativePasteboard:YES];
}
/*! @ignore */
- (unsigned)_declareTypes:(CPArray)types owner:(id)anOwner updateNativePasteboard:(BOOL)shouldUpdate
{
[_types setArray:types];
@@ -167,7 +196,16 @@ var CPPasteboards = nil;
while (count--)
[_owners setObject:anOwner forKey:_types[count]];
if (_nativePasteboard && shouldUpdate)
{
var nativeTypes = [types copy];
if ([types containsObject:CPStringPboardType])
nativeTypes.push(UTF8PboardType);
_nativePasteboard.declareTypes_(nativeTypes);
_changeCount = _nativePasteboard.changeCount();
}
return ++_changeCount;
}
@@ -180,7 +218,10 @@ var CPPasteboards = nil;
- (BOOL)setData:(CPData)aData forType:(CPString)aType
{
[_provided setObject:aData forKey:aType];
if (aType === CPStringPboardType)
[self setData:aData forType:UTF8PboardType];
return YES;
}
@@ -203,7 +244,7 @@ var CPPasteboards = nil;
*/
- (void)setString:(CPString)aString forType:(CPString)aType
{
return [self setPropertyList:aString forType:aType];
[self setPropertyList:aString forType:aType];
}
// Determining Types
@@ -223,6 +264,7 @@ var CPPasteboards = nil;
*/
- (CPArray)types
{
[self _synchronizePasteboard];
return _types;
}
@@ -251,16 +293,46 @@ var CPPasteboards = nil;
if (owner)
{
[owner pasteboard:self provideDataForType:aType];
++_changeCount;
[owner pasteboard:self provideDataForType:aType];
return [_provided objectForKey:aType];
}
if (aType === CPStringPboardType)
return [self dataForType:UTF8PboardType];
return nil;
}
- (void)_synchronizePasteboard
{
if (_nativePasteboard && _nativePasteboard.changeCount() > _changeCount)
{
var nativeTypes = [_nativePasteboard.types() copy];
if ([nativeTypes containsObject:UTF8PboardType])
nativeTypes.push(CPStringPboardType);
[self _declareTypes:nativeTypes owner:self updateNativePasteboard:NO];
_changeCount = _nativePasteboard.changeCount();
}
}
/*! @ignore
method provided for integration with native pasteboard
*/
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
{
if (aType === CPStringPboardType)
{
var string = _nativePasteboard.stringForType_(UTF8PboardType);
[self setString:string forType:CPStringPboardType];
[self setString:string forType:UTF8PboardType];
}
else
[self setString:_nativePasteboard.stringForType_(aType) forType:aType];
}
/*!
Returns the property list for the specified data type
@param aType the requested data type
+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
+13 -10
View File
@@ -716,15 +716,16 @@
@end
var CPScrollViewContentViewKey = "CPScrollViewContentView",
CPScrollViewVLineScrollKey = "CPScrollViewVLineScroll",
CPScrollViewHLineScrollKey = "CPScrollViewHLineScroll",
CPScrollViewVPageScrollKey = "CPScrollViewVPageScroll",
CPScrollViewHPageScrollKey = "CPScrollViewHPageScroll",
CPScrollViewHasVScrollerKey = "CPScrollViewHasVScroller",
CPScrollViewHasHScrollerKey = "CPScrollViewHasHScroller",
CPScrollViewVScrollerKey = "CPScrollViewVScroller",
CPScrollViewHScrollerKey = "CPScrollViewHScroller",
var CPScrollViewContentViewKey = "CPScrollViewContentView",
CPScrollViewHeaderClipViewKey = "CPScrollViewHeaderClipViewKey",
CPScrollViewVLineScrollKey = "CPScrollViewVLineScroll",
CPScrollViewHLineScrollKey = "CPScrollViewHLineScroll",
CPScrollViewVPageScrollKey = "CPScrollViewVPageScroll",
CPScrollViewHPageScrollKey = "CPScrollViewHPageScroll",
CPScrollViewHasVScrollerKey = "CPScrollViewHasVScroller",
CPScrollViewHasHScrollerKey = "CPScrollViewHasHScroller",
CPScrollViewVScrollerKey = "CPScrollViewVScroller",
CPScrollViewHScrollerKey = "CPScrollViewHScroller",
CPScrollViewAutohidesScrollerKey = "CPScrollViewAutohidesScroller";
@implementation CPScrollView (CPCoding)
@@ -740,6 +741,7 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView",
_horizontalPageScroll = [aCoder decodeFloatForKey:CPScrollViewHPageScrollKey];
_contentView = [aCoder decodeObjectForKey:CPScrollViewContentViewKey];
_headerClipView = [aCoder decodeObjectForKey:CPScrollViewHeaderClipViewKey];
_verticalScroller = [aCoder decodeObjectForKey:CPScrollViewVScrollerKey];
_horizontalScroller = [aCoder decodeObjectForKey:CPScrollViewHScrollerKey];
@@ -760,7 +762,8 @@ var CPScrollViewContentViewKey = "CPScrollViewContentView",
[super encodeWithCoder:aCoder];
[aCoder encodeObject:_contentView forKey:CPScrollViewContentViewKey];
[aCoder encodeObject:_headerClipView forKey:CPScrollViewHeaderClipViewKey];
[aCoder encodeObject:_verticalScroller forKey:CPScrollViewVScrollerKey];
[aCoder encodeObject:_horizontalScroller forKey:CPScrollViewHScrollerKey];
+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];
}
+5 -1
View File
@@ -247,6 +247,8 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
[_labelsView tabView:self didAddTabViewItem:aTabViewItem];
[aTabViewItem _setTabView:self];
if ([_tabViewItems count] == 1)
[self selectFirstTabViewItem:self];
@@ -263,9 +265,11 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
var index = [self indexOfTabViewItem:aTabViewItem];
[_tabViewItems removeObjectIdenticalTo:aTabViewItem];
[_labelsView tabView:self didRemoveTabViewItemAtIndex:index];
[aTabViewItem _setTabView:nil];
if (_delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
[_delegate tabViewDidChangeNumberOfTabViewItems:self];
}
+10
View File
@@ -58,6 +58,8 @@ CPPressedTab = 2;
CPView _view;
CPView _auxiliaryView;
CPTabView _tabView;
}
- (id)init
@@ -168,6 +170,14 @@ CPPressedTab = 2;
return _tabView;
}
/*!
@ignore
*/
- (void)_setTabView:(CPTabView)aView
{
_tabView = aView;
}
@end
var CPTabViewItemIdentifierKey = "CPTabViewItemIdentifierKey",
+9 -8
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:)])
@@ -577,7 +577,9 @@ CPTableViewSolidHorizontalGridLineMask = 1 << 1;
[_selectedRowIndexes addIndexes:rows];
else
_selectedRowIndexes = [rows copy];
[self _noteSelectionDidChange];
[self setNeedsLayout];
}
@@ -586,7 +588,7 @@ CPTableViewSolidHorizontalGridLineMask = 1 << 1;
return _selectedColumnIndexes;
}
- (void)selectedRowIndexes
- (CPIndexSet)selectedRowIndexes
{
return _selectedRowIndexes;
}
@@ -1637,8 +1639,7 @@ CPTableViewSolidHorizontalGridLineMask = 1 << 1;
- (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp
{
if (![_previouslySelectedRowIndexes isEqualToIndexSet:_selectedRowIndexes])
[self _noteSelectionDidChange];
}
- (void)_updateSelectionWithMouseAtRow:(CPInteger)aRow
@@ -1709,10 +1710,10 @@ CPTableViewSolidHorizontalGridLineMask = 1 << 1;
if (!_previouslySelectedRowIndexes)
_previouslySelectedRowIndexes = [_selectedRowIndexes copy];
[self selectRowIndexes:newSelection byExtendingSelection:NO];
[self _noteSelectionIsChanging];
[self selectRowIndexes:newSelection byExtendingSelection:NO];
}
- (void)_noteSelectionIsChanging
+137 -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,142 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
#if PLATFORM(DOM)
var element = [self _inputElement];
if (element.parentNode === _DOMElement && ([self isEditable] || [self isSelectable]))
window.setTimeout(function() { element.select(); }, 0);
if (([self isEditable] || [self isSelectable]))
{
if ([[self window] firstResponder] === self)
window.setTimeout(function() { element.select(); }, 0);
else
{
[[self window] makeFirstResponder:self];
window.setTimeout(function() {[self selectText:sender];}, 0);
}
}
#endif
}
- (void)copy:(id)sender
{
var selectedRange = [self selectedRange];
if (selectedRange.length < 1)
return;
var pasteboard = [CPPasteboard generalPasteboard],
stringValue = [self stringValue],
stringForPasting = [stringValue substringWithRange:selectedRange];
[pasteboard declareTypes:[CPStringPboardType] owner:nil];
[pasteboard setString:stringForPasting forType:CPStringPboardType];
}
- (void)cut:(id)sender
{
[self copy:sender];
[self deleteBackwards:sender];
}
- (void)paste:(id)sender
{
var pasteboard = [CPPasteboard generalPasteboard];
if (![[pasteboard types] containsObject:CPStringPboardType])
return;
[self deleteBackwards:sender];
var selectedRange = [self selectedRange],
stringValue = [self stringValue],
pasteString = [pasteboard stringForType:CPStringPboardType],
newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:pasteString];
[self setStringValue:newValue];
[self setSelectedRange:CPMakeRange(selectedRange.location+pasteString.length, 0)];
}
- (CPRange)selectedRange
{
if ([[self window] firstResponder] !== self)
return CPMakeRange(0, 0);
// we wrap this in try catch because firefox will throw an exception in certain instances
try
{
var inputElement = [self _inputElement],
selectionStart = inputElement.selectionStart,
selectionEnd = inputElement.selectionEnd;
if ([selectionStart isKindOfClass:CPNumber])
return CPMakeRange(selectionStart, selectionEnd - selectionStart);
// browsers which don't support selectionStart/selectionEnd (aka IE).
var theDocument = inputElement.ownerDocument || inputElement.document,
selectionRange = theDocument.selection.createRange(),
range = inputElement.createTextRange();
if (range.inRange(selectionRange))
{
range.setEndPoint('EndToStart', selectionRange);
return CPMakeRange(range.text.length, selectionRange.text.length);
}
}
catch (e)
{
// fall through to the return
}
return CGMakeRange(0, 0);
}
- (void)setSelectedRange:(CPRange)aRange
{
if (![[self window] firstResponder] === self)
return;
var inputElement = [self _inputElement];
try
{
if ([inputElement.selectionStart isKindOfClass:CPNumber])
{
inputElement.selectionStart = aRange.location;
inputElement.selectionEnd = CPMaxRange(aRange);
}
else
{
// browsers which don't support selectionStart/selectionEnd (aka IE).
var theDocument = inputElement.ownerDocument || inputElement.document,
existingRange = theDocument.selection.createRange(),
range = inputElement.createTextRange();
if (range.inRange(existingRange))
{
range.collapse(true);
range.move('character', aRange.location);
range.moveEnd('character', aRange.length);
range.select();
}
}
}
catch (e)
{
}
}
- (void)selectAll:(id)sender
{
[self selectText:sender];
}
- (void)deleteBackwards:(id)sender
{
var selectedRange = [self selectedRange],
stringValue = [self stringValue],
newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:""];
[self setStringValue:newValue];
[self setSelectedRange:CPMakeRange(selectedRange.location, 0)];
}
#pragma mark Setting the Delegate
- (void)setDelegate:(id)aDelegate
+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];
}
+77
View File
@@ -495,6 +495,83 @@ CPToolbarItemVisibilityPriorityUser
@end
var CPToolbarItemIdentifierKey = @"CPToolbarItemIdentifierKey",
CPToolbarItemLabelKey = @"CPToolbarItemLabelKey",
CPToolbarItemPaletteLabelKey = @"CPToolbarItemPaletteLabelKey",
CPToolbarItemToolTipKey = @"CPToolbarItemToolTipKey",
CPToolbarItemTagKey = @"CPToolbarItemTagKey",
CPToolbarItemTargetKey = @"CPToolbarItemTargetKey",
CPToolbarItemActionKey = @"CPToolbarItemActionKey",
CPToolbarItemEnabledKey = @"CPToolbarItemEnabledKey",
CPToolbarItemImageKey = @"CPToolbarItemImageKey",
CPToolbarItemAlternateImageKey = @"CPToolbarItemAlternateImageKey",
CPToolbarItemViewKey = @"CPToolbarItemViewKey",
CPToolbarItemMinSizeKey = @"CPToolbarItemMinSizeKey",
CPToolbarItemMaxSizeKey = @"CPToolbarItemMaxSizeKey",
CPToolbarItemVisibilityPriorityKey = @"CPToolbarItemVisibilityPriorityKey";
@implementation CPToolbarItem (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
if (self)
{
_itemIdentifier = [aCoder decodeObjectForKey:CPToolbarItemIdentifierKey];
[self setLabel:[aCoder decodeObjectForKey:CPToolbarItemLabelKey]];
[self setPaletteLabel:[aCoder decodeObjectForKey:CPToolbarItemPaletteLabelKey]];
[self setToolTip:[aCoder decodeObjectForKey:CPToolbarItemToolTipKey]];
[self setTag:[aCoder decodeObjectForKey:CPToolbarItemTagKey]];
[self setTarget:[aCoder decodeObjectForKey:CPToolbarItemTargetKey]];
[self setAction:[aCoder decodeObjectForKey:CPToolbarItemActionKey]];
[self setEnabled:[aCoder decodeBoolForKey:CPToolbarItemEnabledKey]];
[self setImage:[aCoder decodeBoolForKey:CPToolbarItemImageKey]];
[self setAlternateImage:[aCoder decodeBoolForKey:CPToolbarItemAlternateImageKey]];
[self setView:[aCoder decodeObjectForKey:CPToolbarItemViewKey]];
[self setMinSize:[aCoder decodeSizeForKey:CPToolbarItemMinSizeKey]];
[self setMaxSize:[aCoder decodeSizeForKey:CPToolbarItemMaxSizeKey]];
[self setVisibilityPriority:[aCoder decodeIntForKey:CPToolbarItemVisibilityPriorityKey]];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[aCoder encodeObject:_itemIdentifier forKey:CPToolbarItemItemIdentifierKey];
[aCoder encodeObject:[self label] forKey:CPToolbarItemLabelKey];
[aCoder encodeObject:[self paletteLabel] forKey:CPToolbarItemPaletteLabelKey];
[aCoder encodeObject:[self toolTip] forKey:CPToolbarItemToolTipKey];
[aCoder encodeObject:[self tag] forKey:CPToolbarItemTagKey];
[aCoder encodeObject:[self target] forKey:CPToolbarItemTargetKey];
[aCoder encodeObject:[self action] forKey:CPToolbarItemActionKey];
[aCoder encodeObject:[self isEnabled] forKey:CPToolbarItemEnabledKey];
[aCoder encodeObject:[self image] forKey:CPToolbarItemImageKey];
[aCoder encodeObject:[self alternateImage] forKey:CPToolbarItemAlternateImageKey];
[aCoder encodeObject:[self view] forKey:CPToolbarItemViewKey];
[aCoder encodeSize:[self minSize] forKey:CPToolbarItemMinSizeKey];
[aCoder encodeSize:[self maxSize] forKey:CPToolbarItemMaxSizeKey];
[aCoder encodeObject:[self visibilityPriority] forKey:CPToolbarItemVisibilityPriorityKey];
}
@end
@implementation CPToolbarItem (CPCopying)
- (id)copy
+45 -8
View File
@@ -7,7 +7,7 @@
id _representedObject @accessors(readonly, property=representedObject);
CPTreeNode _parentNode @accessors(readonly, property=parentNode);
CPMutableArray _childNodes @accessors(readonly, property=childNodes);
CPMutableArray _childNodes;
}
+ (id)treeNodeWithRepresentedObject:(id)anObject
@@ -33,16 +33,23 @@
return [_childNodes count] <= 0;
}
- (CPArray)childNodes
{
return [_childNodes copy];
}
- (CPMutableArray)mutableChildNodes
{
return [self mutableArrayValueForKey:@"childNodes"];
}
- (void)insertObject:(id)anObject inChildNodesAtIndex:(CPInteger)anIndex
- (void)insertObject:(id)aTreeNode inChildNodesAtIndex:(CPInteger)anIndex
{
anObject._parentNode = self;
[[aTreeNode._parentNode mutableChildNodes] removeObjectIdenticalTo:aTreeNode];
[_childNodes addObject:anObject];
aTreeNode._parentNode = self;
[_childNodes insertObject:aTreeNode atIndex:anIndex];
}
- (void)removeObjectFromChildNodesAtIndex:(CPInteger)anIndex
@@ -52,13 +59,14 @@
[_childNodes removeObjectAtIndex:anIndex];
}
- (void)replaceObjectFromChildNodesAtIndex:(CPInteger)anIndex withObject:(id)anObject
- (void)replaceObjectFromChildNodesAtIndex:(CPInteger)anIndex withObject:(id)aTreeNode
{
var oldObject = [_childNodes objectAtIndex:anIndex];
var oldTreeNode = [_childNodes objectAtIndex:anIndex];
oldObject._parentNode = nil;
oldTreeNode._parentNode = nil;
aTreeNode._parentNode = self;
[_childNodes replaceObjectAtIndex:anIndex withObject:anObject];
[_childNodes replaceObjectAtIndex:anIndex withObject:aTreeNode];
}
- (id)objectInChildNodesAtIndex:(CPInteger)anIndex
@@ -80,3 +88,32 @@
}
@end
var CPTreeNodeRepresentedObjectKey = @"CPTreeNodeRepresentedObjectKey",
CPTreeNodeParentNodeKey = @"CPTreeNodeParentNodeKey",
CPTreeNodeChildNodesKey = @"CPTreeNodeChildNodesKey";
@implementation CPTreeNode (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
if (self)
{
_representedObject = [aCoder decodeObjectForKey:CPTreeNodeRepresentedObjectKey];
_parentNode = [aCoder decodeObjectForKey:CPTreeNodeParentNodeKey];
_childNodes = [aCoder decodeObjectForKey:CPTreeNodeChildNodesKey];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[aCoder encodeObject:_representedObject forKey:CPTreeNodeRepresentedObjectKey];
[aCoder encodeConditionalObject:_parentNode forKey:CPTreeNodeParentNodeKey];
[aCoder encodeObject:_childNodes forKey:CPTreeNodeChildNodesKey];
}
@end
+87 -6
View File
@@ -238,6 +238,11 @@ var CPViewFlags = { },
return [CPSet setWithObjects:@"frameOrigin", @"frameSize"];
}
+ (CPSet)keyPathsForValuesAffectingBounds
{
return [CPSet setWithObjects:@"boundsOrigin", @"boundsSize"];
}
- (id)init
{
return [self initWithFrame:CGRectMakeZero()];
@@ -308,7 +313,7 @@ var CPViewFlags = { },
*/
- (CPArray)subviews
{
return _subviews;
return [_subviews copy];
}
/*!
@@ -441,7 +446,7 @@ var CPViewFlags = { },
[_superview willRemoveSubview:self];
[[_superview subviews] removeObject:self];
[_superview._subviews removeObject:self];
#if PLATFORM(DOM)
CPDOMDisplayServerRemoveChild(_superview._DOMElement, _DOMElement);
@@ -468,6 +473,73 @@ var CPViewFlags = { },
[self _insertSubview:aView atIndex:index];
}
- (void)setSubviews:(CPArray)newSubviews
{
if (!newSubviews)
[CPException raise:CPInvalidArgumentException reason:"newSubviews cannot be nil in -[CPView setSubviews:]"];
// Trivial Case 0: Same array somehow
if ([_subviews isEqual:newSubviews])
return;
// Trivial Case 1: No current subviews, simply add all new subviews.
if ([_subviews count] === 0)
{
var index = 0,
count = [newSubviews count];
for (; index < count; ++index)
[self addSubview:newSubviews[index]];
return;
}
// Trivial Case 2: No new subviews, simply remove all current subviews.
if ([newSubviews count] === 0)
{
var count = [_subviews count];
while (count--)
[_subviews[count] removeFromSuperview];
return;
}
// Find out the views that were removed.
var removedSubviews = [CPMutableSet setWithArray:_subviews];
[removedSubviews removeObjectsInArray:newSubviews];
[removedSubviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
// Find out which views need to be added.
var addedSubviews = [CPMutableSet setWithArray:newSubviews];
[addedSubviews removeObjectsInArray:_subviews];
var addedSubview = nil,
addedSubviewEnumerator = [addedSubviews objectEnumerator];
while (addedSubview = [addedSubviewEnumerator nextObject])
[self addSubview:addedSubview];
// If the order is fine, no need to reorder.
if ([_subviews isEqual:newSubviews])
return;
_subviews = [newSubviews copy];
var index = 0,
count = [_subviews count];
for (; index < count; ++index)
{
var subview = _subviews[index];
CPDOMDisplayServerRemoveChild(_DOMElement, subview._DOMElement);
CPDOMDisplayServerAppendChild(_DOMElement, subview._DOMElement);
}
}
/* @ignore */
- (void)_setWindow:(CPWindow)aWindow
{
@@ -596,7 +668,7 @@ var CPViewFlags = { },
- (void)viewWithTag:(CPInteger)aTag
{
if ([self tag] === aTag)
if ([self tag] == aTag)
return self;
var index = 0,
@@ -816,6 +888,16 @@ var CPViewFlags = { },
return _CGRectMakeCopy(_bounds);
}
- (CGPoint)boundsOrigin
{
return _CGPointMakeCopy(_bounds.origin);
}
- (CGSize)boundsSize
{
return _CGSizeMakeCopy(_bounds.size);
}
/*!
Sets the location of the receiver inside its frame. The method
posts a CPViewBoundsDidChangeNotification to the
@@ -1863,12 +1945,11 @@ setBoundsOrigin:
- (BOOL)performKeyEquivalent:(CPEvent)anEvent
{
var subviews = [self subviews],
count = [subviews count];
var count = [_subviews count];
// Is reverse iteration correct here? It matches the other (correct) code like hit testing.
while (count--)
if ([subviews[count] performKeyEquivalent:anEvent])
if ([_subviews[count] performKeyEquivalent:anEvent])
return YES;
return NO;
+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;
+45 -5
View File
@@ -175,6 +175,7 @@ CPWindowBelow = 2;
CPWindowWillCloseNotification = @"CPWindowWillCloseNotification";
CPWindowDidBecomeMainNotification = @"CPWindowDidBecomeMainNotification";
CPWindowDidResignMainNotification = @"CPWindowDidResignMainNotification";
CPWindowDidResizeNotification = @"CPWindowDidResizeNotification";
CPWindowDidMoveNotification = @"CPWindowDidMoveNotification";
CPWindowWillBeginSheetNotification = @"CPWindowWillBeginSheetNotification";
CPWindowDidEndSheetNotification = @"CPWindowDidEndSheetNotification";
@@ -333,6 +334,11 @@ var CPWindowSaveImage = nil,
CPWindowSavingImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPProgressIndicator/CPProgressIndicatorSpinningStyleRegular.gif"] size:CGSizeMake(16.0, 16.0)]
}
- (id)init
{
return [self initWithContentRect:_CGRectMakeZero() styleMask:CPTitledWindowMask];
}
/*!
Initializes the window. The method also takes a style bit mask made up
of any of the following values:
@@ -610,6 +616,8 @@ CPTexturedBackgroundWindowMask
*/
- (void)setFrame:(CGRect)aFrame display:(BOOL)shouldDisplay animate:(BOOL)shouldAnimate
{
aFrame = _CGRectMakeCopy(aFrame);
var value = aFrame.origin.x,
delta = value - FLOOR(value);
@@ -673,8 +681,8 @@ CPTexturedBackgroundWindowMask
if (_hasShadow)
[_shadowView setFrameSize:_CGSizeMake(SHADOW_MARGIN_LEFT + size.width + SHADOW_MARGIN_RIGHT, SHADOW_MARGIN_BOTTOM + size.height + SHADOW_MARGIN_TOP + SHADOW_DISTANCE)];
if (!_isAnimating && [_delegate respondsToSelector:@selector(windowDidResize:)])
[_delegate windowDidResize:self];
if (!_isAnimating)
[[CPNotificationCenter defaultCenter] postNotificationName:CPWindowDidResizeNotification object:self];
}
if ([self _sharesChromeWithPlatformWindow])
@@ -1079,6 +1087,13 @@ CPTexturedBackgroundWindowMask
selector:@selector(windowDidMove:)
name:CPWindowDidMoveNotification
object:self];
if ([_delegate respondsToSelector:@selector(windowDidResize:)])
[defaultCenter
addObserver:_delegate
selector:@selector(windowDidResize:)
name:CPWindowDidResizeNotification
object:self];
}
/*!
@@ -1678,6 +1693,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:)])
{
@@ -1981,7 +2007,8 @@ CPTexturedBackgroundWindowMask
- (void)_setUpMasksForView:(CPView)aView
{
var views = [CPArray arrayWithArray:[aView subviews]];
var views = [aView subviews];
[views addObject:aView];
for (var i = 0, count = [views count]; i < count; i++)
@@ -1996,7 +2023,8 @@ CPTexturedBackgroundWindowMask
- (void)_restoreMasksForView:(CPView)aView
{
var views = [CPArray arrayWithArray:[aView subviews]];
var views = [aView subviews];
[views addObject:aView];
for (var i = 0, count = [views count]; i < count; i++)
@@ -2351,9 +2379,21 @@ var keyViewComparator = function(a, b, context)
*/
- (CPUndoManager)undoManager
{
// If we've ever created an undo manager, return it.
if (_undoManager)
return _undoManager;
// If not, check to see if the document has one.
var documentUndoManager = [[_windowController document] undoManager];
if (documentUndoManager)
return documentUndoManager;
// If not, check to see if the delegate has one.
if (_delegateRespondsToWindowWillReturnUndoManagerSelector)
return [_delegate windowWillReturnUndoManager:self];
// If not, create one.
if (!_undoManager)
_undoManager = [[CPUndoManager alloc] init];
+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)],
+7 -1
View File
@@ -37,6 +37,7 @@ var _CPWindowViewResizeIndicatorImage = nil;
CPView _toolbarView;
// BOOL _isAnimatingToolbar;
CGRect _resizeFrame;
CGPoint _mouseDraggedPoint;
@@ -160,10 +161,15 @@ var _CPWindowViewResizeIndicatorImage = nil;
if (!visibleFrame)
visibleFrame = [[CPPlatformWindow primaryPlatformWindow] visibleFrame];
var minPointY = 0;
if([CPMenu menuBarVisible])
minPointY = [[CPApp mainMenu] menuBarHeight];
var restrictedPoint = CGPointMake(0, 0);
restrictedPoint.x = MIN(MAX(aPoint.x, -_frame.size.width + 4.0), CGRectGetMaxX(visibleFrame) - 4.0);
restrictedPoint.y = MIN(MAX(aPoint.y, 0.0), CGRectGetMaxY(visibleFrame) - 8.0);
restrictedPoint.y = MIN(MAX(aPoint.y, minPointY), CGRectGetMaxY(visibleFrame) - 8.0);
return restrictedPoint;
}
+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];
+7 -3
View File
@@ -37,7 +37,13 @@
- (void)setCustomClassName:(CPString)aClassName
{
if (_className === aClassName)
return;
_className = aClassName;
[self setNeedsDisplay:YES];
[self setNeedsLayout];
}
@end
@@ -97,9 +103,7 @@ var _CPCibCustomViewClassNameKey = @"_CPCibCustomViewClassNameKey";
[view setBounds:[self bounds]];
// Since the object replacement logic hasn't had a chance to kick in yet, we need to do it manually:
// we need to copy subviews since each time we add a subview to a different view its removed from the original subviews array
var subviews = [[self subviews] copy],
var subviews = [self subviews],
index = 0,
count = subviews.length;
+2 -3
View File
@@ -14,7 +14,7 @@ var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinS
_CPCibWindowTemplateWindowViewKey = @"_CPCibWindowTemplateWindowViewKey",
_CPCibWindowTemplateWindowAutorecalculatesKeyViewLoop = @"_CPCibWindowTemplateWindowAutorecalculatesKeyViewLoop";
_CPCibWindowTemplateWindowIsFullPlatformWindowKey = @"_CPCibWindowTemplateWindowIsFullPlatformWindowKey";
_CPCibWindowTemplateWindowIsFullPlatformWindowKey = @"_CPCibWindowTemplateWindowIsFullPlatformWindowKey";
@implementation _CPCibWindowTemplate : CPObject
{
@@ -134,9 +134,8 @@ var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinS
[theWindow setMinSize:_minSize];
if (_maxSize)
[theWindow setMaxSize:_maxSize];
[theWindow setLevel:CPFloatingWindowLevel];
//[result setHidesOnDeactivate:(_wtFlags&0x80000000)?YES:NO];
//[result setHidesOnDeactivate:(_wtFlags&0x80000000)?YES:NO];
[theWindow setTitle:_windowTitle];
// FIXME: we can't autoresize yet...
+10 -1
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;
@@ -95,7 +104,7 @@ var PrimaryPlatformWindow = NULL;
frame.origin = CGPointMakeZero();
if ([CPMenu menuBarVisible])
if ([CPMenu menuBarVisible] && [CPPlatformWindow primaryPlatformWindow] === self)
{
var menuBarHeight = [[CPApp mainMenu] menuBarHeight];
+232 -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))
{
_DOMPasteboardElement.select();
_DOMPasteboardElement.value = "";
isNativePasteEvent = YES;
//we are simply going to skip all keypress events that use cmd/ctrl key
//this lets us be consistent in all browsers and send on the keydown
//which means we can cancel the event early enough, but only if sendEvent needs to
var eligibleForCopyPaste = [self _validateCopyCutOrPasteEvent:aDOMEvent flags:modifierFlags];
// If this could be a native PASTE event, then we need to further examine it before
// sending a CPEvent. Select our element to see if anything gets pasted in it.
if (characters === "v" && eligibleForCopyPaste)
{
if (!_ignoreNativePastePreparation)
{
_DOMPasteboardElement.select();
_DOMPasteboardElement.value = "";
}
isNativePasteEvent = YES;
}
// However, of this could be a native COPY event, we need to let the normal event-process take place so it
// can capture our internal Cappuccino pasteboard.
else if ((characters == "c" || characters == "x") && eligibleForCopyPaste)
{
isNativeCopyOrCutEvent = YES;
if (_ignoreNativeCopyOrCutEvent)
break;
}
}
else if (CPKeyCodes.firesKeyPressEvent(_keyCode, _lastKey, aDOMEvent.shiftKey, aDOMEvent.ctrlKey, aDOMEvent.altKey))
{
// this branch is taken by events which fire keydown, keypress, and keyup.
// this is the only time we'll ALLOW character keys to propagate (needed for text fields)
StopDOMEventPropagation = NO;
break;
}
else
{
//this branch is taken by "remedial" key events
// In this state we continue to keypress and send the CPEvent
}
// Normally we return now because we let keypress send the actual CPEvent keyDown event, since we don't have
// a complete set of information yet.
// However, of this could be a native COPY event, we need to let the normal event-process take place so it
// can capture our internal Cappuccino pasteboard.
else if ((characters == "c" || characters == "x") && (modifierFlags & CPPlatformActionKeyMask))
isNativeCopyOrCutEvent = YES;
case "keypress":
// we unconditionally break on keypress events with modifiers,
// because we forced the event to be sent on the keydown
if (aDOMEvent.type === "keypress" && (modifierFlags & (CPControlKeyMask | CPCommandKeyMask)))
break;
// Also, certain browsers (IE and Safari), have broken keyboard supportwhere they don't send keypresses for certain events.
// So, allow the keypress event to handle the event if we are not a browser with broken (remedial) key support...
else if (!CPFeatureIsCompatible(CPJavascriptRemedialKeySupport))
return;
// Or, if this is not one of those special keycodes, and also not a ctrl+event
else if (!KeyCodesWithoutKeyPressEvents[_keyCode] && (_keyCode == CTRL_KEY_CODE || !(modifierFlags & CPControlKeyMask)))
return;
// If this is in fact our broke state, continue to keypress and send the keydown.
case "keypress": // If the source of this event is our pasteboard element, then simply let it continue
// as normal, so that the paste event can successfully complete.
if ((aDOMEvent.target || aDOMEvent.srcElement) == _DOMPasteboardElement)
return;
var keyCode = _keyCode,
charCode = aDOMEvent.keyCode || aDOMEvent.charCode,
isARepeat = (_charCodes[keyCode] != nil);
_lastKey = keyCode;
_charCodes[keyCode] = charCode;
var characters = overrideCharacters || String.fromCharCode(charCode),
charactersIgnoringModifiers = characters.toLowerCase();
// Safari won't send proper capitalization during cmd-key events
if (!overrideCharacters && (modifierFlags & CPCommandKeyMask) && (modifierFlags & CPShiftKeyMask))
if (!overrideCharacters && (modifierFlags & CPCommandKeyMask) && ((modifierFlags & CPShiftKeyMask) || _capsLockActive))
characters = characters.toUpperCase();
event = [CPEvent keyEventWithType:CPKeyDown location:location modifierFlags:modifierFlags
@@ -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,9 @@ var supportsNativeDragAndDrop = [CPPlatform supportsDragAndDrop];
// We should pay attention to mouse down and mouse up in conjunction with this.
//window.liveResize = YES;
if ([CPPlatform isBrowser])
[CPApp._activeMenu cancelTracking];
var oldSize = [self contentRect].size;
[self updateFromNativeContentRect];
@@ -1077,8 +1216,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 +1248,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;
+3 -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,8 @@ 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.color = [_textShadowColor cssString];
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
+48
View File
@@ -181,6 +181,45 @@
return [[self _representedObject] count];
}
- (int)indexOfObject:(CPObject)anObject inRange:(CPRange)aRange
{
var index = aRange.location,
count = aRange.length,
shouldIsEqual = !!anObject.isa;
for (; index < count; ++index)
{
var object = [self objectAtIndex:index];
if (anObject === object || shouldIsEqual && !!object.isa && [anObject isEqual:object])
return index;
}
return CPNotFound;
}
- (int)indexOfObject:(CPObject)anObject
{
return [self indexOfObject:anObject range:CPMakeRange(0, [self count])];
}
- (int)indexOfObjectIdenticalTo:(CPObject)anObject inRange:(CPRange)aRange
{
var index = aRange.location,
count = aRange.length;
for (; index < count; ++index)
if (anObject === [self objectAtIndex:index])
return index;
return CPNotFound;
}
- (int)indexOfObjectIdenticalTo:(CPObject)anObject
{
return [self indexOfObjectIdenticalTo:anObject inRange:CPMakeRange(0, [self count])];
}
- (id)objectAtIndex:(unsigned)anIndex
{
if(_objectAtIndex)
@@ -200,6 +239,15 @@
[self _setRepresentedObject:target];
}
- (void)addObjectsFromArray:(CPArray)anArray
{
var index = 0,
count = [anArray count];
for (; index < count; ++index)
[self addObject:[anArray objectAtIndex:index]];
}
- (void)insertObject:(id)anObject atIndex:(unsigned)anIndex
{
if (_insert)
+19 -18
View File
@@ -365,7 +365,7 @@
count = length;
for(; index < count; ++index)
if(self[index] == anObject)
if(self[index] === anObject)
return index;
}
@@ -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];
}
@@ -534,14 +534,11 @@
*/
- (CPArray)objectsAtIndexes:(CPIndexSet)indexes
{
var index = [indexes firstIndex],
var index = CPNotFound,
objects = [];
while(index != CPNotFound)
{
[objects addObject:self[index]];
index = [indexes indexGreaterThanIndex:index];
}
while((index = [indexes indexGreaterThanIndex:index]) !== CPNotFound)
[objects addObject:[self objectAtIndex:index]];
return objects;
}
@@ -816,15 +813,18 @@
for(; index < count; ++index)
{
var object = self[index];
if (index === 0)
description += '\n';
if (object && object.isa)
description += [object description];
else
description += object;
var object = self[index],
objectDescription = object && object.isa ? [object description] : object + "";
description += "\t" + objectDescription.split('\n').join("\n\t");
if (index !== count - 1)
description += ", ";
description += '\n';
}
return description + ')';
@@ -1112,7 +1112,7 @@
*/
- (void)removeObjectIdenticalTo:(id)anObject
{
[self removeObjectIdenticalTo:anObject inRange:CPMakeRange(0, length)];
[self removeObjectIdenticalTo:anObject inRange:CPMakeRange(0, [self count])];
}
/*!
@@ -1124,12 +1124,13 @@
*/
- (void)removeObjectIdenticalTo:(id)anObject inRange:(CPRange)aRange
{
var index;
var index,
count = [self count];
while ((index = [self indexOfObjectIdenticalTo:anObject inRange:aRange]) != CPNotFound)
while ((index = [self indexOfObjectIdenticalTo:anObject inRange:aRange]) !== CPNotFound)
{
[self removeObjectAtIndex:index];
aRange = CPIntersectionRange(CPMakeRange(index, length - index), aRange);
aRange = CPIntersectionRange(CPMakeRange(index, (--count) - index), aRange);
}
}
+17 -1
View File
@@ -33,6 +33,10 @@
@implementation CPBundle : CPObject
{
//properties set up in file.js
//this.path = NULL;
//this.info = NULL;
//this._URIMap = { };
}
+ (id)alloc
@@ -185,13 +189,25 @@
- (void)connection:(CPURLConnection)aConnection didFailWithError:(CPError)anError
{
alert("Couldnot find bundle:" + anError)
if ([_delegate respondsToSelector:@selector(bundle:didFailWithError:)])
[_delegate bundle:self didFailWithError:anError];
CPLog.error("Could not find bundle: " + self);
}
- (void)connectionDidFinishLoading:(CPURLConnection)aConnection
{
}
- (CPString)description
{
return [super description] + "(" + path + ")";
}
@end
objj_bundle.prototype.isa = CPBundle;
objj_bundle.prototype.toString = function()
{
return [this description];
}
+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
+28 -3
View File
@@ -148,11 +148,32 @@
for (var key in object)
{
if (!object.hasOwnProperty(key))
continue;
var value = object[key];
if (recursively && value.constructor === Object)
value = [CPDictionary dictionaryWithJSObject:value recursively:YES];
if (recursively)
{
if (value.constructor === Object)
value = [CPDictionary dictionaryWithJSObject:value recursively:YES];
else if ([value isKindOfClass:CPArray])
{
var newValue = [];
for (var i = 0, count = value.length; i < count; i++)
{
var thisValue = value[i];
if (thisValue.constructor === Object)
newValue.push([CPDictionary dictionaryWithJSObject:thisValue recursively:YES]);
else
newValue.push(thisValue);
}
value = newValue;
}
}
[dictionary setObject:value forKey:key];
}
@@ -609,3 +630,7 @@
@end
objj_dictionary.prototype.isa = CPDictionary;
objj_dictionary.prototype.toString = function()
{
return [this description];
}
+10 -7
View File
@@ -92,7 +92,7 @@ if (input == nil)
if (self)
{
name = aName;
reason = aReason;
message = aReason;
userInfo = aUserInfo;
}
@@ -112,7 +112,7 @@ if (input == nil)
*/
- (CPString)reason
{
return reason;
return message;
}
/*!
@@ -128,7 +128,7 @@ if (input == nil)
*/
- (CPString)description
{
return reason;
return message;
}
/*!
@@ -145,7 +145,7 @@ if (input == nil)
- (id)copy
{
return [[self class] exceptionWithName:name reason:reason userInfo:userInfo];
return [[self class] exceptionWithName:name reason:message userInfo:userInfo];
}
@end
@@ -168,7 +168,7 @@ var CPExceptionNameKey = "CPExceptionNameKey",
if (self)
{
name = [aCoder decodeObjectForKey:CPExceptionNameKey];
reason = [aCoder decodeObjectForKey:CPExceptionReasonKey];
message = [aCoder decodeObjectForKey:CPExceptionReasonKey];
userInfo = [aCoder decodeObjectForKey:CPExceptionUserInfoKey];
}
@@ -182,13 +182,16 @@ var CPExceptionNameKey = "CPExceptionNameKey",
- (void)encodeWithCoder:(CPCoder)aCoder
{
[aCoder encodeObject:name forKey:CPExceptionNameKey];
[aCoder encodeObject:reason forKey:CPExceptionReasonKey];
[aCoder encodeObject:message forKey:CPExceptionReasonKey];
[aCoder encodeObject:userInfo forKey:CPExceptionUserInfoKey];
}
@end
objj_exception.prototype.isa = CPException;
// toll-free bridge Error to CPException
// [CPException alloc] uses an objj_exception, which is a subclass of Error
Error.prototype.isa = CPException;
[CPException initialize];
function _CPRaiseInvalidAbstractInvocation(anObject, aSelector)
+85
View File
@@ -0,0 +1,85 @@
/*
* CPFunctionOperation.j
*
* Created by Johannes Fahrenkrug.
* Copyright 2009, Springenwerk.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPObject.j>
@import "CPOperation.j"
/*!
@class CPFunctionOperation
@brief Represents an operation using a JavaScript function that can be run in an CPOperationQueue
*/
@implementation CPFunctionOperation : CPOperation
{
CPArray _functions;
}
- (void)main
{
if (_functions && [_functions count] > 0)
{
var i = 0;
for (i = 0; i < [_functions count]; i++)
{
var func = [_functions objectAtIndex:i];
func();
}
}
}
- (id)init
{
if (self = [super init])
{
_functions = [];
}
return self;
}
/*!
Adds the specified JS function to the receivers list of functions to perform.
*/
- (void)addExecutionFunction:(JSObject)jsFunction
{
[_functions addObject:jsFunction];
}
/*!
Returns an array containing the functions associated with the receiver.
*/
- (CPArray)executionFunctions
{
return _functions;
}
/*!
Creates and returns an NSFunctionOperation object and adds the specified function to it.
*/
+ (id)functionOperationWithFunction:(JSObject)jsFunction
{
functionOp = [[CPFunctionOperation alloc] init];
[functionOp addExecutionFunction:jsFunction];
return functionOp;
}
@end
+107
View File
@@ -0,0 +1,107 @@
/*
* CPInvocationOperation.j
*
* Created by Johannes Fahrenkrug.
* Copyright 2009, Springenwerk.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPObject.j>
@import <Foundation/CPInvocation.j>
@import "CPOperation.j"
/*!
@class CPInvocationOperation
@brief Represents an operation using an invocation that can be run in an CPOperationQueue
*/
@implementation CPInvocationOperation : CPOperation
{
CPInvocation _invocation;
}
- (void)main
{
if (_invocation)
{
[_invocation invoke];
}
}
- (id)init
{
if (self = [super init])
{
_invocation = nil;
}
return self;
}
/*!
Returns a CPInvocationOperation object initialized with the specified invocation object.
@param inv the invocation
*/
- (id)initWithInvocation:(CPInvocation)inv
{
if (self = [self init])
{
_invocation = inv;
}
return self;
}
/*!
Returns an NSInvocationOperation object initialized with the specified target and selector.
@param target the target
@param sel the selector that should be called on the target
@param arg the arguments
*/
- (id)initWithTarget:(id)target selector:(SEL)sel object:(id)arg
{
var inv = [[CPInvocation alloc] initWithMethodSignature:nil];
[inv setTarget:target];
[inv setSelector:sel];
[inv setArgument:arg atIndex:2];
return [self initWithInvocation:inv];
}
/*!
Returns the receivers invocation object.
*/
- (CPInvocation)invocation
{
return _invocation;
}
/*!
Returns the result of the invocation or method.
*/
- (id)result
{
if ([self isFinished] && _invocation)
{
return [_invocation returnValue];
}
return nil;
}
@end
+95 -11
View File
@@ -77,6 +77,81 @@
return [CPSet set];
}
- (void)applyChange:(CPDictionary)aChange toKeyPath:(CPString)aKeyPath
{
var changeKind = [aChange objectForKey:CPKeyValueChangeKindKey];
if (changeKind === CPKeyValueChangeSetting)
{
var value = [aChange objectForKey:CPKeyValueChangeNewKey];
[self setValue:value === [CPNull null] ? nil : value forKeyPath:aKeyPath];
}
else if (changeKind === CPKeyValueChangeInsertion)
[[self mutableArrayValueForKeyPath:aKeyPath]
insertObjects:[aChange objectForKey:CPKeyValueChangeNewKey]
atIndexes:[aChange objectForKey:CPKeyValueChangeIndexesKey]];
else if (changeKind === CPKeyValueChangeRemoval)
[[self mutableArrayValueForKeyPath:aKeyPath]
removeObjectsAtIndexes:[aChange objectForKey:CPKeyValueChangeIndexesKey]];
else if (changeKind === CPKeyValueChangeReplacement)
[[self mutableArrayValueForKeyPath:aKeyPath]
replaceObjectAtIndexes:[aChange objectForKey:CPKeyValueChangeIndexesKey]
withObjects:[aChange objectForKey:CPKeyValueChangeNewKey]];
}
@end
@implementation CPDictionary (KeyValueObserving)
- (CPDictionary)inverseChangeDictionary
{
var inverseChangeDictionary = [self mutableCopy],
changeKind = [self objectForKey:CPKeyValueChangeKindKey];
if (changeKind === CPKeyValueChangeSetting || changeKind === CPKeyValueChangeReplacement)
{
[inverseChangeDictionary
setObject:[self objectForKey:CPKeyValueChangeOldKey]
forKey:CPKeyValueChangeNewKey];
[inverseChangeDictionary
setObject:[self objectForKey:CPKeyValueChangeNewKey]
forKey:CPKeyValueChangeOldKey];
}
else if (changeKind === CPKeyValueChangeInsertion)
{
[inverseChangeDictionary
setObject:CPKeyValueChangeRemoval
forKey:CPKeyValueChangeKindKey];
[inverseChangeDictionary
setObject:[self objectForKey:CPKeyValueChangeNewKey]
forKey:CPKeyValueChangeOldKey];
[inverseChangeDictionary removeObjectForKey:CPKeyValueChangeNewKey];
}
else if (changeKind === CPKeyValueChangeRemoval)
{
[inverseChangeDictionary
setObject:CPKeyValueChangeInsertion
forKey:CPKeyValueChangeKindKey];
[inverseChangeDictionary
setObject:[self objectForKey:CPKeyValueChangeOldKey]
forKey:CPKeyValueChangeNewKey];
[inverseChangeDictionary removeObjectForKey:CPKeyValueChangeOldKey];
}
return inverseChangeDictionary;
}
@end
// KVO Options
@@ -311,11 +386,11 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld,
var type = [changes objectForKey:CPKeyValueChangeKindKey];
// for to-many relationships, oldvalue is only sensible for replace and remove
if (type == CPKeyValueChangeReplacement || type == CPKeyValueChangeRemoval)
if (type === CPKeyValueChangeReplacement || type === CPKeyValueChangeRemoval)
{
//FIXME: do we need to go through and replace "" with CPNull?
var oldValues = [[_targetObject mutableArrayValueForKeyPath:aKey] objectsAtIndexes:indexes];
[changes setValue:oldValues forKey:CPKeyValueChangeOldKey];
var newValues = [[_targetObject mutableArrayValueForKeyPath:aKey] objectsAtIndexes:indexes];
[changes setValue:newValues forKey:CPKeyValueChangeOldKey];
}
}
else
@@ -373,19 +448,28 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld,
else if (!isBefore)
[observerInfo.observer observeValueForKeyPath:aKey ofObject:_targetObject change:changes context:observerInfo.context];
}
var dependentKeysMap = _nativeClass[DependentKeysKey];
if (!dependentKeysMap)
return;
var keysComposedOfKey = [dependentKeysMap[aKey] allObjects];
if (!keysComposedOfKey)
var dependentKeyPaths = [dependentKeysMap[aKey] allObjects];
if (!dependentKeyPaths)
return;
for (var i=0, count=keysComposedOfKey.length; i<count; i++)
[self _sendNotificationsForKey:keysComposedOfKey[i] changeOptions:changeOptions isBefore:isBefore];
var index = 0,
count = [dependentKeyPaths count];
for (; index < count; ++index)
{
var keyPath = dependentKeyPaths[index];
[self _sendNotificationsForKey:keyPath
changeOptions:isBefore ? [changeOptions copy] : _changesForKey[keyPath]
isBefore:isBefore];
}
}
@end
@@ -501,7 +585,7 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld,
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)changes context:(id)aContext
{
if (anObject == _object)
if (aKeyPath === _firstPart)
{
[_observer observeValueForKeyPath:_firstPart ofObject:_object change:changes context:_context];
@@ -514,7 +598,7 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld,
if (_value)
[_value addObserver:self forKeyPath:_secondPart options:kvoNewAndOld context:nil];
}
else /* if (anObject == _value || !_value) */
else
{
//a is the same, but a.b has changed -- nothing to do but forward this message along
[_observer observeValueForKeyPath:_firstPart+"."+aKeyPath ofObject:_object change:changes context:_context];
+5 -3
View File
@@ -227,6 +227,7 @@ CPLog(@"Got some class: %@", inst);
*/
- (BOOL)respondsToSelector:(SEL)aSelector
{
// isa is isa.isa in class case.
return !!class_getInstanceMethod(isa, aSelector);
}
@@ -269,7 +270,7 @@ CPLog(@"Got some class: %@", inst);
*/
- (CPString)description
{
return "<" + isa.name + " 0x" + [CPString stringWithHash:[self UID]] + ">";
return "<" + class_getName(isa) + " 0x" + [CPString stringWithHash:[self UID]] + ">";
}
// Sending Messages
@@ -322,6 +323,7 @@ CPLog(@"Got some class: %@", inst);
Used for forwarding of messages to other objects.
@ignore
*/
// FIXME: This should be moved to the runtime?
- (void)forward:(SEL)aSelector :(marg_list)args
{
var signature = [self methodSignatureForSelector:aSelector];
@@ -468,12 +470,12 @@ CPLog(@"Got some class: %@", inst);
return [self UID];
}
- (unsigned)UID
- (CPString)UID
{
if (typeof self.__address === "undefined")
self.__address = _objj_generateObjectHash();
return __address;
return __address + "";
}
/*!
+293
View File
@@ -0,0 +1,293 @@
/*
* CPOperation.j
*
* Created by Johannes Fahrenkrug.
* Copyright 2009, Springenwerk.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPObject.j>
/*!
Operations receive very low priority for execution.
@global
@group CPOperationQueuePriority
*/
CPOperationQueuePriorityVeryLow = -8;
/*!
Operations receive low priority for execution.
@global
@group CPOperationQueuePriority
*/
CPOperationQueuePriorityLow = -4;
/*!
Operations receive normal priority for execution.
@global
@group CPOperationQueuePriority
*/
CPOperationQueuePriorityNormal = 0;
/*!
Operations receive high priority for execution.
@global
@group CPOperationQueuePriority
*/
CPOperationQueuePriorityHigh = 4;
/*!
Operations receive very high priority for execution.
@global
@group CPOperationQueuePriority
*/
CPOperationQueuePriorityVeryHigh = 8;
/*!
@class CPOperation
@brief Represents an operation that can be run in an CPOperationQueue
It should be subclassed an the subclass should implement its own main method to do the actual work.
*/
@implementation CPOperation : CPObject
{
CPArray operations;
BOOL _cancelled;
BOOL _executing;
BOOL _finished;
BOOL _ready;
int _queuePriority;
JSObject _completionFunction;
CPArray _dependencies;
}
- (void)main
{
// should be overridden in child class
}
- (id)init
{
if (self = [super init])
{
_cancelled = NO;
_executing = NO;
_finished = NO;
_ready = YES;
_dependencies = [[CPArray alloc] init];
_queuePriority = CPOperationQueuePriorityNormal;
}
return self;
}
/*!
Starts the operation (runs the main method), sets all the status flags and runs the completion function if it's set
*/
- (void)start
{
if (!_cancelled)
{
[self willChangeValueForKey:@"isExecuting"];
_executing = YES;
[self didChangeValueForKey:@"isExecuting"];
[self main];
if (_completionFunction)
{
_completionFunction();
}
[self willChangeValueForKey:@"isExecuting"];
_executing = NO;
[self didChangeValueForKey:@"isExecuting"];
[self willChangeValueForKey:@"isFinished"];
_finished = YES;
[self didChangeValueForKey:@"isFinished"];
}
}
/*!
Indicates if this operation has been cancelled
@return if this operation has been cancelled
*/
- (BOOL)isCancelled
{
return _cancelled;
}
/*!
Indicates if this operation is currently executing
@return if this operation is currently executing
*/
- (BOOL)isExecuting
{
return _executing;
}
/*!
Indicates if this operation has finished running
@return if this operation has finished running
*/
- (BOOL)isFinished
{
return _finished;
}
/*!
Just added for Cocoa compatibility
@return always false
*/
- (BOOL)isConcurrent
{
return NO;
}
/*!
Indicates if this operation is ready to be executed. Takes the "isFinished" state of dependent operations into account
@return if this operation is ready to run
*/
- (BOOL)isReady
{
return _ready;
}
/*!
The JS function that should be run after the main method
@return JS function
*/
(JSObject)completionFunction
{
return _completionFunction;
}
/*!
Sets the JS function that should be run after the main method
*/
- (void)setCompletionFunction:(JSObject)aJavaScriptFunction
{
_completionFunction = aJavaScriptFunction;
}
/*!
Makes the receiver dependent on the completion of the specified operation.
@param anOperation the operation that the receiver should depend on
*/
- (void)addDependency:(CPOperation)anOperation
{
[self willChangeValueForKey:@"dependencies"];
[anOperation addObserver:self
forKeyPath:@"isFinished"
options:(CPKeyValueObservingOptionNew)
context:NULL];
[_dependencies addObject:anOperation];
[self didChangeValueForKey:@"dependencies"];
[self _updateIsReadyState];
}
/*!
Removes the receivers dependence on the specified operation.
@param anOperation the operation that the receiver should no longer depend on
*/
- (void)removeDependency:(CPOperation)anOperation
{
[self willChangeValueForKey:@"dependencies"];
[_dependencies removeObject:anOperation];
[anOperation removeObserver:self
forKeyPath:@"isFinished"];
[self didChangeValueForKey:@"dependencies"];
[self _updateIsReadyState];
}
/*!
The operations that the receiver depends on
@return array of operations
*/
- (CPArray)dependencies
{
return _dependencies;
}
/*!
Just added for Cocoa compatibility, doesn't do anything
*/
- (void)waitUntilFinished
{
}
/*!
Advises the operation object that it should stop executing its task.
*/
- (void)cancel
{
[self willChangeValueForKey:@"isCancelled"];
_cancelled = YES;
[self didChangeValueForKey:@"isCancelled"];
}
/*!
Sets the priority of the operation when used in an operation queue.
@param priority the priority
*/
- (void)setQueuePriority:(int)priority
{
_queuePriority = priority;
}
/*!
The priority of the operation when used in an operation queue.
@return the priority
*/
- (int)queuePriority
{
return _queuePriority;
}
// We need to observe the "isFinished" key of our dependent operations so we can update our own "isReady" state
- (void)observeValueForKeyPath:(CPString)keyPath
ofObject:(id)object
change:(CPDictionary)change
context:(void)context
{
if (keyPath == @"isFinished")
{
[self _updateIsReadyState];
}
}
- (void)_updateIsReadyState
{
var newReady = YES;
if (_dependencies && [_dependencies count] > 0)
{
var i = 0;
for (i = 0; i < [_dependencies count]; i++)
{
if (![[_dependencies objectAtIndex:i] isFinished])
{
newReady = NO;
}
}
}
if (newReady != _ready)
{
[self willChangeValueForKey:@"isReady"];
_ready = newReady;
[self didChangeValueForKey:@"isReady"];
}
}
@end
+293
View File
@@ -0,0 +1,293 @@
/*
* CPOperationQueue.j
*
* Created by Johannes Fahrenkrug.
* Copyright 2009, Springenwerk.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPObject.j>
@import "CPOperation.j"
@import "CPInvocationOperation.j"
@import "CPFunctionOperation.j"
// the global queue (mainQueue)
var cpOperationMainQueue = nil;
/*!
@class CPOperationQueue
@brief Represents an operation queue that can run CPOperations
*/
@implementation CPOperationQueue : CPObject
{
CPArray _operations;
BOOL _suspended;
CPString _name @accessors(property=name);
CPTimer _timer;
}
- (id)init
{
if (self = [super init])
{
_operations = [[CPArray alloc] init];
_suspended = NO;
_currentlyModifyingOps = NO;
_timer = [CPTimer scheduledTimerWithTimeInterval:0.01
target:self
selector:@selector(_runNextOpsInQueue)
userInfo:nil
repeats:YES];
}
return self;
}
- (void)_runNextOpsInQueue
{
if (!_suspended && [self operationCount] > 0)
{
var i = 0;
for (i = 0; i < [_operations count]; i++)
{
var op = [_operations objectAtIndex:i];
if ([op isReady] && ![op isCancelled] && ![op isFinished] && ![op isExecuting])
{
[op start];
}
}
}
}
- (void)_enableTimer:(BOOL)enable
{
if (!enable)
{
if (_timer)
{
[_timer invalidate];
_timer = nil;
}
}
else
{
if (!_timer)
{
_timer = [CPTimer scheduledTimerWithTimeInterval:0.01
target:self
selector:@selector(_runNextOpsInQueue)
userInfo:nil
repeats:YES];
}
}
}
/*!
Adds the specified operation object to the receiver.
@param anOperation the operation that should be scheduled for execution
*/
- (void)addOperation:(CPOperation)anOperation
{
[self willChangeValueForKey:@"operations"];
[self willChangeValueForKey:@"operationCount"];
[_operations addObject:anOperation];
[self _sortOpsByPriority:_operations];
[self didChangeValueForKey:@"operations"];
[self didChangeValueForKey:@"operationCount"];
}
/*!
Adds the specified array of operations to the queue.
@param ops The array of CPOperation objects that you want to add to the receiver.
@param wait If YES, the method only returns once all of the specified operations finish executing. If NO, the operations are added to the queue and control returns immediately to the caller.
*/
- (void)addOperations:(CPArray)ops waitUntilFinished:(BOOL)wait
{
if (ops)
{
if (wait)
{
[self _sortOpsByPriority:ops];
[self _runOpsSynchronously:ops];
}
[_operations addObjectsFromArray:ops];
[self _sortOpsByPriority:_operations];
}
}
/*!
Wraps the given js function in a CPOperation and adds it to the queue
@param aFunction the JS function to add
*/
- (void)addOperationWithFunction:(JSObject)aFunction
{
[self addOperation:[CPFunctionOperation functionOperationWithFunction:aFunction]];
}
- (CPArray)operations
{
return _operations;
}
- (int)operationCount
{
if (_operations)
{
return [_operations count];
}
return 0;
}
/*!
Cancels all queued and executing operations.
*/
- (void)cancelAllOperations
{
if (_operations)
{
var i = 0;
for (i = 0; i < [_operations count]; i++)
{
[[_operations objectAtIndex:i] cancel];
}
}
}
/*!
Blocks until all of the receivers queued and executing operations finish executing.
*/
- (void)waitUntilAllOperationsAreFinished
{
// lets first stop the timer so it won't interfere
[self _enableTimer:NO];
[self _runOpsSynchronously:_operations];
if (!_suspended)
{
[self _enableTimer:YES];
}
}
/*!
Returns the maximum number of concurrent operations that the receiver can execute.
Always returns 1 because JS doesn't have threads
*/
- (int)maxConcurrentOperationCount
{
return 1;
}
/*!
Modifies the execution of pending operations
@param suspend if YES, queue execution is suspended. If NO, it is resumed
*/
- (void)setSuspended:(BOOL)suspend
{
_suspended = suspend;
[self _enableTimer:!suspend];
}
/*!
Returns a Boolean value indicating whether the receiver is scheduling queued operations for execution.
*/
- (BOOL)isSuspended
{
return _suspended;
}
- (void)_sortOpsByPriority:(CPArray)someOps
{
if (someOps)
{
[someOps sortUsingFunction:function(lhs, rhs)
{
if ([lhs queuePriority] < [rhs queuePriority])
{
return 1;
}
else
{
if ([lhs queuePriority] > [rhs queuePriority])
{
return -1;
}
else
{
return 0;
}
}
}
context:nil];
}
}
- (void)_runOpsSynchronously:(CPArray)ops
{
if (ops)
{
var keepGoing = YES;
while (keepGoing)
{
var i = 0;
keepGoing = NO;
// start the ones that are ready
for (i = 0; i < [ops count]; i++)
{
var op = [ops objectAtIndex:i];
if ([op isReady] && ![op isCancelled] && ![op isFinished] && ![op isExecuting])
{
[op start];
}
}
// make sure they are all done
for (i = 0; i < [ops count]; i++)
{
var op = [ops objectAtIndex:i];
if (![op isFinished] && ![op isCancelled])
{
keepGoing = YES;
}
}
}
}
}
/*!
Convenience method for one system wide singelton queue. Returns the same queue as currentQueue.
*/
+ (CPOperationQueue)mainQueue
{
if (!cpOperationMainQueue)
{
cpOperationMainQueue = [[CPOperationQueue alloc] init];
[cpOperationMainQueue setName:@"main"];
}
return cpOperationMainQueue;
}
/*!
Convenience method for one system wide singelton queue. Returns the same queue as mainQueue.
*/
+ (CPOperationQueue)currentQueue
{
return [CPOperationQueue mainQueue];
}
@end
+161
View File
@@ -0,0 +1,161 @@
/*
* CPProxy.j
* Foundation
*
* Created by Francisco Tolmasky.
* Copyright 2009, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPException.j"
@import "CPInvocation.j"
@import "CPString.j"
@implementation CPProxy
{
}
+ (void)load
{
}
+ (void)initialize
{
}
+ (Class)class
{
return self;
}
+ (id)alloc
{
return class_createInstance(self);
}
+ (BOOL)respondsToSelector:(SEL)selector
{
return !!class_getInstanceMethod(isa, aSelector);
}
- (CPMethodSignature)methodSignatureForSelector:(SEL)aSelector
{
[CPException raise:CPInvalidArgumentException
reason:@"-methodSignatureForSelector: called on abstract CPProxy class."];
}
- (void)forwardInvocation:(CPInvocation)anInvocation
{
[CPException raise:CPInvalidArgumentException
reason:@"-methodSignatureForSelector: called on abstract CPProxy class."];
}
// FIXME: This should be moved to the runtime?
- (void)forward:(SEL)aSelector :(marg_list)args
{
[CPObject methodForSelector:_cmd](self, _cmd, aSelector, args);
}
- (unsigned)hash
{
return [self UID];
}
- (unsigned)UID
{
if (typeof self.__address === "undefined")
self.__address = _objj_generateObjectHash();
return __address;
}
- (BOOL)isEqual:(id)anObject
{
return self === object;
}
- (id)self
{
return self;
}
- (Class)class
{
return isa;
}
- (Class)superclass
{
return class_getSuperclass(isa);
}
- (id)performSelector:(SEL)aSelector
{
return objj_msgSend(self, aSelector);
}
- (id)performSelector:(SEL)aSelector withObject:(id)anObject
{
return objj_msgSend(self, aSelector, anObject);
}
- (id)performSelector:(SEL)aSelector withObject:(id)anObject withObject:(id)anotherObject
{
return objj_msgSend(self, aSelector, anObject, anotherObject);
}
- (BOOL)isProxy
{
return YES;
}
- (BOOL)isKindOfClass:(Class)aClass
{
var signature = [self methodSignatureForSelector:_cmd],
invocation = [CPInvocation invocationWithMethodSignature:signature];
[self forwardInvocation:invocation];
return [invocation returnValue];
}
-(BOOL)isMemberOfClass:(Class)aClass
{
var signature = [self methodSignatureForSelector:_cmd],
invocation = [CPInvocation invocationWithMethodSignature:signature];
[self forwardInvocation:invocation];
return [invocation returnValue];
}
- (BOOL)respondsToSelector:(SEL)aSelector
{
var signature = [self methodSignatureForSelector:_cmd],
invocation = [CPInvocation invocationWithMethodSignature:signature];
[self forwardInvocation:invocation];
return [invocation returnValue];
}
- (CPString)description
{
return "<" + class_getName(isa) + " 0x" + [CPString stringWithHash:[self UID]] + ">";
}
@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.
*/
+1 -1
View File
@@ -159,7 +159,7 @@ var CPURLConnectionDelegate = nil;
// Browsers use "file:", Titanium uses "app:"
_isLocalFileConnection = scheme === "file" ||
((scheme !== "http" || scheme !== "https:") &&
((scheme === "http" || scheme === "https:") &&
window.location &&
(window.location.protocol === "file:" || window.location.protocol === "app:"));
+159 -78
View File
@@ -22,6 +22,7 @@
@import "CPObject.j"
@import "CPInvocation.j"
@import "CPProxy.j"
var CPUndoManagerNormal = 0,
@@ -170,15 +171,17 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
{
CPMutableArray _redoStack;
CPMutableArray _undoStack;
BOOL _groupsByEvent;
int _disableCount;
int _levelsOfUndo;
id _currentGrouping;
int _state;
CPString _actionName;
id _preparedTarget;
id _undoManagerProxy;
CPArray _runLoopModes;
BOOL _registeredWithRunLoop;
}
@@ -200,12 +203,29 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
[self setRunLoopModes:[CPDefaultRunLoopMode]];
[self setGroupsByEvent:YES];
_performRegistered = NO;
_undoManagerProxy = [_CPUndoManagerProxy alloc];
_undoManagerProxy._undoManager = self;
}
return self;
}
- (void)_addUndoInvocation:(CPInvocation)anInvocation
{
if (!_currentGrouping)
// Remember that we create these lazily...
if ([self groupsByEvent])
[self _beginUndoGroupingForEvent];
else
[CPException raise:CPInternalInconsistencyException reason:"No undo group is currently open"];
[_currentGrouping addInvocation:anInvocation];
if (_state === CPUndoManagerNormal)
[_redoStack removeAllObjects];
}
// Registering Undo Operations
/*!
Registers an undo operation. You invoke this method with the target of the undo action providing the selector which can perform the undo with the provided object. The object is often a dictionary of the identifying the attribute and their values before the change. The invocation will be added to the current grouping. If the registrations have been disabled through \c -disableUndoRegistration, this method does nothing.
@@ -216,9 +236,7 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
*/
- (void)registerUndoWithTarget:(id)aTarget selector:(SEL)aSelector object:(id)anObject
{
if (!_currentGrouping)
[CPException raise:CPInternalInconsistencyException reason:"No undo group is currently open"];
// Don't do anything if we're disabled.
if (_disableCount > 0)
return;
@@ -230,10 +248,7 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
[invocation setSelector:aSelector];
[invocation setArgument:anObject atIndex:2];
[_currentGrouping addInvocation:invocation];
if (_state == CPUndoManagerNormal)
[_redoStack removeAllObjects];
[self _addUndoInvocation:invocation];
}
/*!
Prepares the specified target for the undo action.
@@ -244,14 +259,14 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
{
_preparedTarget = aTarget;
return self;
return _undoManagerProxy;
}
/*
FIXME This method doesn't seem to do anything right
@ignore
*/
-(CPMethodSignature)methodSignatureForSelector:(SEL)aSelector
- (CPMethodSignature)_methodSignatureOfPreparedTargetForSelector:(SEL)aSelector
{
if ([_preparedTarget respondsToSelector:aSelector])
return 1;
@@ -264,23 +279,20 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
target on the invocation, and adds it to the current grouping.
@param anInvocation the message to record
*/
- (void)forwardInvocation:(CPInvocation)anInvocation
- (void)_forwardInvocationToPreparedTarget:(CPInvocation)anInvocation
{
// Don't do anything if we're disabled.
if (_disableCount > 0)
return;
/* if (_preparedTarget == nil)
[NSException raise:NSInternalInconsistencyException
format:@"forwardInvocation called without first preparing a target"];
if (_currentGroup == nil)
/*
if (_currentGroup == nil)
[NSException raise:NSInternalInconsistencyException
format:@"forwardInvocation called without first opening an undo group"];
*/
[anInvocation setTarget:_preparedTarget];
[_currentGrouping addInvocation:anInvocation];
if (_state == CPUndoManagerNormal)
[_redoStack removeAllObjects];
[self _addUndoInvocation:anInvocation];
_preparedTarget = nil;
}
@@ -291,7 +303,11 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
*/
- (BOOL)canRedo
{
return _redoStack.length > 0;
[[CPNotificationCenter defaultCenter]
postNotificationName:CPUndoManagerCheckpointNotification
object:self];
return [_redoStack count] > 0;
}
/*!
@@ -311,9 +327,9 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
*/
- (void)undo
{
if ([self groupingLevel] == 1)
if ([self groupingLevel] === 1)
[self endUndoGrouping];
[self undoNestedGroup];
}
@@ -322,28 +338,31 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
*/
- (void)undoNestedGroup
{
if (_undoStack.length == 0)
if ([_undoStack count] <= 0)
return;
var defaultCenter = [CPNotificationCenter defaultCenter];
/* [[NSNotificationCenter defaultCenter] postNotificationName:NSUndoManagerCheckpointNotification
object:self];
*/
[defaultCenter postNotificationName:CPUndoManagerWillUndoChangeNotification object:self];
[defaultCenter postNotificationName:CPUndoManagerCheckpointNotification
object:self];
[defaultCenter postNotificationName:CPUndoManagerWillUndoChangeNotification
object:self];
var undoGrouping = _undoStack.pop();
_state = CPUndoManagerUndoing;
[self beginUndoGrouping];
[self _beginUndoGrouping];
[undoGrouping invoke];
[self endUndoGrouping];
[_CPUndoGrouping _poolUndoGrouping:undoGrouping];
_state = CPUndoManagerNormal;
[defaultCenter postNotificationName:CPUndoManagerDidUndoChangeNotification object:self];
[defaultCenter postNotificationName:CPUndoManagerDidUndoChangeNotification
object:self];
}
/*!
@@ -352,19 +371,21 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
- (void)redo
{
// Don't do anything if we have no redos.
if (_redoStack.length == 0)
if ([_redoStack count] <= 0)
return;
/* if (_state == NSUndoManagerUndoing)
[NSException raise:NSInternalInconsistencyException
format:@"redo called while undoing"];
[[NSNotificationCenter defaultCenter] postNotificationName:NSUndoManagerCheckpointNotification
object:self];
*/
var defaultCenter = [CPNotificationCenter defaultCenter];
[defaultCenter postNotificationName:CPUndoManagerWillRedoChangeNotification object:self];
[defaultCenter postNotificationName:CPUndoManagerCheckpointNotification
object:self];
[defaultCenter postNotificationName:CPUndoManagerWillRedoChangeNotification
object:self];
var oldUndoGrouping = _currentGrouping,
undoGrouping = _redoStack.pop();
@@ -372,7 +393,7 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
_currentGrouping = nil;
_state = CPUndoManagerRedoing;
[self beginUndoGrouping];
[self _beginUndoGrouping];
[undoGrouping invoke];
[self endUndoGrouping];
@@ -389,6 +410,29 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
Starts a new grouping of undo tasks, and makes it the current grouping.
*/
- (void)beginUndoGrouping
{
// It doesn't matter that the user is creating a group themselves, we are
// pretending to have opened the group at the beginning of the run loop,
// so create an implicit one here.
if (!_currentGrouping && [self groupsByEvent])
[self _beginUndoGroupingForEvent];
[[CPNotificationCenter defaultCenter]
postNotificationName:CPUndoManagerCheckpointNotification
object:self];
[self _beginUndoGrouping];
}
/* @ignore */
- (void)_beginUndoGroupingForEvent
{
[self _beginUndoGrouping];
[self _registerWithRunLoop];
}
/* @ignore */
- (void)_beginUndoGrouping
{
_currentGrouping = [_CPUndoGrouping undoGroupingWithParent:_currentGrouping];
}
@@ -402,17 +446,22 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
if (!_currentGrouping)
[CPException raise:CPInternalInconsistencyException reason:"endUndoGrouping. No undo group is currently open."];
var defaultCenter = [CPNotificationCenter defaultCenter];
[defaultCenter postNotificationName:CPUndoManagerCheckpointNotification
object:self];
var parent = [_currentGrouping parent];
if (!parent && [_currentGrouping invocations].length > 0)
{
[[CPNotificationCenter defaultCenter]
[defaultCenter
postNotificationName:CPUndoManagerWillCloseUndoGroupNotification
object:self];
// Put this group on the redo stack if we are currently undoing, otherwise
// Put this group on the redo stack if we are currently undoing, otherwise
// put it on the undo stack. That way, "undos" become "redos".
var stack = _state == CPUndoManagerUndoing ? _redoStack : _undoStack;
var stack = _state === CPUndoManagerUndoing ? _redoStack : _undoStack;
stack.push(_currentGrouping);
@@ -460,21 +509,14 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
*/
- (void)setGroupsByEvent:(BOOL)aFlag
{
if (_groupsByEvent == aFlag)
aFlag = !!aFlag;
if (_groupsByEvent === aFlag)
return;
_groupsByEvent = aFlag;
if (_groupsByEvent)
{
[self _registerWithRunLoop];
// There is a chance that the event loop selector won't fire before our first register,
// so kick it off here.
if (!_currentGrouping)
[self beginUndoGrouping];
}
else
if (![self groupsByEvent])
[self _unregisterWithRunLoop];
}
@@ -515,7 +557,7 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
*/
- (BOOL)isUndoing
{
return _state == CPUndoManagerUndoing;
return _state === CPUndoManagerUndoing;
}
/*!
@@ -523,7 +565,7 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
*/
- (BOOL)isRedoing
{
return _state == CPUndoManagerRedoing;
return _state === CPUndoManagerRedoing;
}
// Clearing Undo Operations
@@ -623,27 +665,19 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
*/
- (void)setRunLoopModes:(CPArray)modes
{
_runLoopModes = modes;
[self _unregisterWithRunLoop];
if (_groupsByEvent)
_runLoopModes = [modes copy];
if (_registeredWithRunLoop)
{
[self _unregisterWithRunLoop];
[self _registerWithRunLoop];
}
}
/* @ignore */
- (void)beginUndoGroupingForEvent
- (void)_runLoopEndUndoGrouping
{
if (!_groupsByEvent)
return;
if (_currentGrouping != nil)
[self endUndoGrouping];
[self beginUndoGrouping];
[[CPRunLoop currentRunLoop] performSelector:@selector(beginUndoGroupingForEvent)
target:self argument:nil order:CPUndoCloseGroupingRunLoopOrdering modes:_runLoopModes];
[self endUndoGrouping];
_registeredWithRunLoop = NO;
}
/* @ignore */
@@ -653,8 +687,12 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
return;
_registeredWithRunLoop = YES;
[[CPRunLoop currentRunLoop] performSelector:@selector(beginUndoGroupingForEvent)
target:self argument:nil order:CPUndoCloseGroupingRunLoopOrdering modes:_runLoopModes];
[[CPRunLoop currentRunLoop]
performSelector:@selector(_runLoopEndUndoGrouping)
target:self
argument:nil
order:CPUndoCloseGroupingRunLoopOrdering
modes:_runLoopModes];
}
/* @ignore */
@@ -664,7 +702,33 @@ var _CPUndoGroupingParentKey = @"_CPUndoGroupingParentKey",
return;
_registeredWithRunLoop = NO;
[[CPRunLoop currentRunLoop] cancelPerformSelector:@selector(beginUndoGroupingForEvent) target:self argument:nil];
[[CPRunLoop currentRunLoop]
cancelPerformSelector:@selector(_runLoopEndUndoGrouping)
target:self
argument:nil];
}
- (void)observeChangesForKeyPath:(CPString)aKeyPath ofObject:(id)anObject
{
[anObject addObserver:self
forKeyPath:aKeyPath
options:CPKeyValueObservingOptionOld | CPKeyValueObservingOptionNew
context:NULL];
}
- (void)stopObservingChangesForKeyPath:(CPString)aKeyPath ofObject:(id)anObject
{
[anObject removeObserver:self forKeyPath:aKeyPath];
}
- (void)observeValueForKeyPath:(CPString)aKeyPath
ofObject:(id)anObject
change:(CPDictionary)aChange
context:(id)aContext
{
[[self prepareWithInvocationTarget:anObject]
applyChange:[aChange inverseChangeDictionary]
toKeyPath:aKeyPath];
}
@end
@@ -718,3 +782,20 @@ var CPUndoManagerRedoStackKey = @"CPUndoManagerRedoStackKey",
}
@end
@implementation _CPUndoManagerProxy : CPProxy
{
CPUndoManager _undoManager;
}
- (CPMethodSignature)methodSignatureForSelector:(SEL)aSelector
{
return [_undoManager _methodSignatureOfPreparedTargetForSelector:aSelector];
}
- (void)forwardInvocation:(CPInvocation)anInvocation
{
[_undoManager _forwardInvocationToPreparedTarget:anInvocation];
}
@end
+2
View File
@@ -42,6 +42,8 @@
@import "CPNumber.j"
@import "CPObject.j"
@import "CPObjJRuntime.j"
@import "CPOperation.j"
@import "CPOperationQueue.j"
@import "CPPropertyListSerialization.j"
@import "CPRange.j"
@import "CPRunLoop.j"
+8 -8
View File
@@ -48,7 +48,7 @@ task ("install", ["CommonJS"], function()
{
// FIXME: require("narwhal/tusk/install").install({}, $COMMONJS);
// Doesn't work due to some weird this.print business.
OS.system("sudo tusk install --force " + $BUILD_CJS_OBJECTIVE_J + " " + $BUILD_CJS_CAPPUCCINO);
OS.system(["sudo", "tusk", "install", "--force", $BUILD_CJS_OBJECTIVE_J, $BUILD_CJS_CAPPUCCINO]);
});
// Documentation
@@ -61,7 +61,7 @@ task ("documentation", function()
{
if (executableExists("doxygen"))
{
if (OS.system("doxygen " + FILE.join("Tools", "Documentation", "Cappuccino.doxygen")))
if (OS.system(["doxygen", FILE.join("Tools", "Documentation", "Cappuccino.doxygen")]))
OS.exit(1); //rake abort if ($? != 0)
rm_rf($DOCUMENTATION_BUILD);
@@ -95,7 +95,7 @@ filedir ($STARTER_DOWNLOAD_APPLICATION, ["CommonJS"], function()
rm_rf($STARTER_DOWNLOAD_APPLICATION);
FILE.mkdirs($STARTER_DOWNLOAD);
if (OS.system("capp gen " + $STARTER_DOWNLOAD_APPLICATION + " -t Application --noconfig"))
if (OS.system(["capp", "gen", $STARTER_DOWNLOAD_APPLICATION, "-t", "Application", "--noconfig"]))
// FIXME: uncomment this: we get conversion errors
//OS.exit(1); // rake abort if ($? != 0)
{}
@@ -161,13 +161,14 @@ task ("deploy", ["downloads"], function()
// Testing
task ("test", ["build"], function()
task("test", ["build", "test-only"]);
task("test-only", function()
{
var tests = new FileList('Tests/**/*Test.j');
var cmd = ["ojtest"].concat(tests.items());
var cmdString = cmd.map(OS.enquote).join(" ");
var code = OS.system(cmdString);
var code = OS.system(cmd);
if (code !== 0)
OS.exit(code);
});
@@ -198,8 +199,7 @@ function pushPackage(path, remote)
["git", "push", "origin", "master"]
];
var cmdString = cmds.map(function(cmd)
{
var cmdString = cmds.map(function(cmd) {
return cmd.map(OS.enquote).join(" ");
}).join(" && ");
+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);
+21 -34
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")
{
@@ -63,12 +62,14 @@ if (system.env["OBJJ_INCLUDE_PATHS"])
// TODO: somehow make window object the top scope?
with (window)
{
var objectivejSource = FILE.read(objectivejPath, { charset:"UTF-8" });
// read and eval Objective-J.js with the module's scope
if (system.engine === "rhino")
Packages.org.mozilla.javascript.Context.getCurrentContext().evaluateString(window, FILE.read(objectivejPath, { charset:"UTF-8" }), "Objective-J.js", 0, null);
Packages.org.mozilla.javascript.Context.getCurrentContext().evaluateString(window, objectivejSource, objectivejPath, 0, null);
else
eval(FILE.read(objectivejPath, { charset:"UTF-8" }));
eval(objectivejSource);
// export desired variables. must eval variable name to obtain a reference.
[
"objj_preprocess",
@@ -105,37 +106,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 +134,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 +146,6 @@ exports.run = function(args)
require("browser/timeout").serviceTimeouts();
}
}
require("browser/timeout").serviceTimeouts();
}
// synchronously evals Objective-J code
@@ -27,7 +27,7 @@ var compressor = null;
function sharedCompressor()
{
if (!compressor)
compressor = OS.popen("java -server -Dfile.encoding=UTF-8 -classpath " + RHINO_PATH + ":" + SHRINKSAFE_PATH + " org.dojotoolkit.shrinksafe.Main");
compressor = OS.popen("java -server -Dfile.encoding=UTF-8 -classpath " + RHINO_PATH + ":" + SHRINKSAFE_PATH + " org.dojotoolkit.shrinksafe.Main", { charset:"UTF-8" });
return compressor;
}
@@ -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;
@@ -64,7 +65,7 @@ function compileWithResolvedFlags(aFilePath, objjcFlags, gccFlags)
else
{
// GCC preprocess the file.
var gcc = OS.popen("gcc -E -x c -P " + (gccFlags ? gccFlags.join(" ") : "") + " " + OS.enquote(aFilePath)),
var gcc = OS.popen("gcc -E -x c -P " + (gccFlags ? gccFlags.join(" ") : "") + " " + OS.enquote(aFilePath), { charset:"UTF-8" }),
chunk = "";
while (chunk = gcc.stdout.read())
@@ -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);
+51 -18
View File
@@ -28,20 +28,32 @@ require("../common.jake");
$BUILD_OBJECTIVE_J = FILE.join($BUILD_CONFIGURATION_DIR, "Objective-J");
Files = new FileList("Runtime/constants.js", "Runtime/utilities.js", "Runtime/json2.js", "Runtime/runtime.js", "Runtime/dictionary.js", "Runtime/plist.js", "Runtime/file.js", "Runtime/exception.js", "Runtime/preprocess.js", "Runtime/evaluate.js", "Runtime/bootstrap.js");
var OBJECTIVE_J_FILES = new FileList(
"Runtime/constants.js",
"Runtime/utilities.js",
"Runtime/json2.js",
"Runtime/runtime.js",
"Runtime/dictionary.js",
"Runtime/plist.js",
"Runtime/file.js",
"Runtime/exception.js",
"Runtime/preprocess.js",
"Runtime/evaluate.js",
"Runtime/bootstrap.js"
);
if ($CONFIGURATION === "Debug")
Files.include("Runtime/debug.js");
OBJECTIVE_J_FILES.include("Runtime/debug.js");
$BUILD_BROWSER_FILE = FILE.join($BUILD_OBJECTIVE_J, "Objective-J.js");
$BUILD_CJS_FILE = FILE.join($BUILD_OBJECTIVE_J, "CommonJS.environment", "Objective-J.js");
filedir ($BUILD_BROWSER_FILE, Files, function(aTask)
filedir($BUILD_BROWSER_FILE, OBJECTIVE_J_FILES, function(aTask)
{
build_product(aTask.name(), environmentFlags("ObjJ") + " -DPLATFORM_USERAGENT");
});
filedir ($BUILD_CJS_FILE, Files, function(aTask)
filedir($BUILD_CJS_FILE, OBJECTIVE_J_FILES, function(aTask)
{
flags = environmentFlags("CommonJS", "ObjJ");
flags += ' -DRHINO'
@@ -52,7 +64,7 @@ filedir ($BUILD_CJS_FILE, Files, function(aTask)
$LICENSE = FILE.join("CommonJS", "lib", "objective-j", "jake", "LICENSES", "LGPL-v2.1");
$BUILD_LICENSE = FILE.join($BUILD_OBJECTIVE_J, "LICENSE");
filedir ($BUILD_LICENSE, [$LICENSE], function()
filedir($BUILD_LICENSE, [$LICENSE], function()
{
FILE.copy($LICENSE, $BUILD_LICENSE);
});
@@ -83,7 +95,7 @@ new FileList("CommonJS/**/*").forEach(function(aFilename)
$BUILD_CJS_OBJECTIVE_J_FRAMEWORK = FILE.join($BUILD_CJS_OBJECTIVE_J, "Frameworks", "Objective-J");
filedir ($BUILD_CJS_OBJECTIVE_J_FRAMEWORK, function()
filedir($BUILD_CJS_OBJECTIVE_J_FRAMEWORK, function()
{
cp_r($BUILD_OBJECTIVE_J, $BUILD_CJS_OBJECTIVE_J_FRAMEWORK);
});
@@ -92,24 +104,45 @@ CLOBBER.include($BUILD_OBJECTIVE_J);
function environmentFlags()
{
return "-DENVIRONMENTS=\"[" + Array.prototype.map.apply(arguments, [function(anEnvironment)
{
return "-DENVIRONMENTS=\"[" + Array.prototype.map.apply(arguments, [function(anEnvironment) {
return "\\\"" + anEnvironment + "\\\"";
}]).join(", ") + "]\"";
}
function build_product(path, flags)
{
OS.system("cat Runtime/header.txt > " + OS.enquote(path));
OS.system("cat " +
Files.filter(function(aName)
{
return !!aName.match(/\.js$/);
}).map(function(aName)
{
return OS.enquote(aName);
}).join(' ') + " | gcc " + flags + " -E -x c -P - >> " + OS.enquote(path));
var sources = OBJECTIVE_J_FILES.filter(function(aName) { return !!aName.match(/\.js$/); });
var productOut = FILE.open(path, "w", { charset : "UTF-8" });
FILE.open("Runtime/header.txt", "r", { charset : "UTF-8" })
.copy(productOut)
.close();
var preprocessor = OS.popen("gcc " + flags + " -E -x c -P -");
sources.forEach(function(source) {
FILE.open(source, "r", { charset : "UTF-8" })
.copy(preprocessor.stdin)
.close();
});
preprocessor.stdin.close();
preprocessor.stdout.copy(productOut);
productOut.close();
var code = preprocessor.wait();
// this is equivalent to the above, but less cross platform:
//OS.system(["cp", "Runtime/header.txt", path]);
//var code = OS.system("cat " + sources.map(OS.enquote).join(' ') + " | gcc " + flags + " -E -x c -P - >> " + OS.enquote(path));
if (code !== 0) {
FILE.remove(path);
OS.exit(1);
}
// rake abort if ($? != 0)
}
task ("build", [$BUILD_BROWSER_FILE, $BUILD_CJS_FILE, $BUILD_LICENSE, $BUILD_CJS_OBJECTIVE_J_FRAMEWORK]);
task("build", [$BUILD_BROWSER_FILE, $BUILD_CJS_FILE, $BUILD_LICENSE, $BUILD_CJS_OBJECTIVE_J_FRAMEWORK]);

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