Compare commits

...
1018 Commits
Author SHA1 Message Date
Antoine Mercadal 4ec7cea6c4 update doxygen displayed Cappuccini version to 0.9.5 2011-11-16 15:12:22 +01:00
Alexander Ljungberg 0036f329f5 Fixed: in recent builds, WithBindingsTest failed with a "CPScroller does not contain theme attribute 'scroller-width'" error. 2011-11-16 12:57:01 +00:00
Alexander Ljungberg 15af54efda Fixed with CPTokenField: quickly entered tokens would be ignored.
If the autocomplete state had not been set yet, tokens could not be finished using the token separator, return or tab. Instead the user typed text remained in its 'non token' state.
2011-11-16 12:52:27 +00:00
Alexander Ljungberg 07966bb7fe Fixed with CPTokenField: crash if added to a window in a unit test. 2011-11-16 12:50:05 +00:00
Alexander Ljungberg e7d9b0503b Fixes #1398. Fixed with CPTokenField: deleting tokens in front of selected tokens would shift the selection to the right. 2011-11-16 12:04:03 +00:00
Alexander Ljungberg 072b43d178 Fixes #1397. Fixed with CPTokenField: make sure selection is initialised when loading from cib. 2011-11-16 11:55:38 +00:00
Alexander Ljungberg 281d2295ae Code formatting. 2011-11-15 23:47:56 +00:00
Alexander Ljungberg 79cf4370b4 Update bootstrap to 0.9.5 as well. 2011-11-14 18:49:30 +00:00
Alexander Ljungberg 6217fc8459 Given the large number of changes, this will be Cappuccino 0.9.5 instead. 2011-11-14 18:37:00 +00:00
Alexander Ljungberg f1fd3d170a Merge branch '0.9.2b' of github.com:cappuccino/cappuccino into 0.9.2b 2011-11-14 18:27:08 +00:00
Antoine Mercadal 4e410f8a81 Merge remote-tracking branch 'upstream/0.9.2b' into 0.9.2b 2011-11-14 16:46:36 +01:00
Antoine Mercadal 7a1b273d8d simplify the ignored path matching 2011-11-13 23:34:49 +01:00
Antoine Mercadal 820531342d fix during tidying shadow files 2011-11-13 21:58:45 +01:00
Antoine Mercadal 353db3277a fix file level mode deactivated, fix auto ignore not working 2011-11-13 21:36:52 +01:00
Antoine Mercadal 82f37549ae reactivate 10.7 file level API 2011-11-13 20:28:11 +01:00
Alexander Ljungberg 09e1bd6bf1 The 0.9.2 GM will be tagged v0.9.2 simply. 2011-11-11 16:52:48 +00:00
Alexander Ljungberg 44f3abf262 Don't mention "steam" in TOOLS-README. 2011-11-11 16:45:43 +00:00
Antoine Mercadal 8c09af5013 Merge remote-tracking branch 'upstream/master' 2011-11-10 14:11:12 +01:00
Antoine Mercadal 0781e932c6 Merge branch 'xcc-improvments' 2011-11-10 14:10:45 +01:00
Alexander Ljungberg 3cee00323c Don't separate statements by commas. 2011-11-10 12:31:16 +00:00
Alexander Ljungberg b1f6f3ddfa Missing semicolons. 2011-11-10 12:30:05 +00:00
Alexander Ljungberg 7147266ddf objjc option to compile to plain JavaScript (suitable for linting). 2011-11-10 11:59:26 +00:00
Alexander Ljungberg 357212bff7 Missing semicolons. 2011-11-10 11:34:26 +00:00
Alexander Ljungberg ed4fc3b20f objjc compile to stdout, argument parsing, --help. 2011-11-10 10:37:46 +00:00
Alexander Ljungberg 7e8b71dd52 Semicolons. 2011-11-10 10:36:47 +00:00
Alexander Ljungberg 267f00bfe1 Put spaces around = in [name] = function... generated JS to reduce lint warnings. 2011-11-10 09:41:21 +00:00
Alexander Ljungberg 8f90dbce99 Allow almost anything as a key equivalent unless a text field is the first responder.
After testing in Cocoa, even unexpected keys such as tab can be used when a text field isn't selected. Some keys such as the arrow keys and escape act like key equivalents even with a text field active.
2011-11-10 00:52:38 +00:00
Alexander Ljungberg 00485dba89 Refs #1019. Clean up. 2011-11-10 00:12:48 +00:00
Alexander Ljungberg 8fd4f5e4b6 Merge branch 'master' of github.com:cappuccino/cappuccino 2011-11-09 23:36:47 +00:00
Scott RiceandAlexander Ljungberg e7e69b3fd4 Fixed issue #1019 in IE 2011-11-10 07:35:50 +08:00
Alexander Ljungberg 2463c1dc05 IE compatibility. 2011-11-09 23:02:31 +00:00
Alexander Ljungberg bc590286f2 Missing semicolons. 2011-11-09 22:55:11 +00:00
Aparajita Fishman 8c83816ec8 Made [CPMenu -removeAllItems] KVO compliant
Fixes https://github.com/cappuccino/cappuccino/issues/1395
2011-11-09 14:50:52 -08:00
Alexander Ljungberg 699069ce8f Typo fix. 2011-11-09 20:48:01 +00:00
Alexander Ljungberg ec0cd22c1d Merge pull request #1382 from kjamieson/cappuccino
---

Currently CPTextField only updates its internal string value from the actual HTML input element on a keyUp event. If the CPTextField loses focus before the keyUp event is received, the internal value does not get updated and any text entered since the last keyUp event is lost.

This is easily reproduced when editing a text field by quickly entering text and hitting the enter/return key to insert a new line (before the keyUp event has fired), or when holding down a key (to repeatedly enter the same character), and then tabbing out of the text field -- the value gets reset to whatever the value was before the key was held down.

This fix changes CPTextField#insertNewLine and CPTextField#resignFirstResponder to reload the string value from the input element if it has changed (in the same way as if a keyUp event had been triggered)
2011-11-09 20:43:13 +00:00
Antoine Mercadal 8da3a8866d remove white space 2011-11-08 23:07:41 +01:00
Antoine Mercadal 21f6fdff48 synchronize support folder if missing shadow files 2011-11-08 23:05:51 +01:00
Antoine Mercadal ed82a1fc87 remove useless argument 2011-11-08 22:45:00 +01:00
Antoine Mercadal 1fa143453d Merge branch 'xcc-improvments' of github.com:primalmotion/cappuccino into xcc-improvments 2011-11-08 22:37:32 +01:00
Antoine Mercadal 1240bab7ed typo in help (ref to xcodecapp-cocoa) 2011-11-08 22:35:11 +01:00
Aparajita Fishman 4af29d83d7 Merge branch 'xcc-improvments' of github.com:primalmotion/cappuccino into xcc-improvments 2011-11-08 13:32:23 -08:00
Aparajita Fishman 6aed29af91 Fixed ignore paths to be safe, new help file 2011-11-08 13:30:21 -08:00
Aparajita Fishman 37f1f50000 Fixed ignore paths to be safe, new help file 2011-11-08 13:25:48 -08:00
Aparajita Fishman a93654c66b Cleaned up event handling, fixed bug with shadow paths 2011-11-08 11:36:41 -08:00
Alexander Ljungberg 0d2dd94c81 Refs #1394. Don't attempt MacPorts autoreconf fix if the right autoconf isn't available. 2011-11-08 14:21:28 +00:00
Alexander Ljungberg c2f97e9aa3 Make 80 character line wrap more consistent throughout bootstrap. 2011-11-08 12:35:26 +00:00
Alexander Ljungberg e04bf6de95 Merge pull request #1394 from anddam/cappuccino
---

adding autoreconf to fix issues reported at [1]

[1] http://groups.google.com/group/objectivej/browse_thread/thread/b0cddeb1046bfcf4/3f0b0cbbe57ed64b

Conflicts:
	bootstrap.sh
2011-11-08 11:55:47 +00:00
Alexander Ljungberg 38499c006a Merge branch '0.9.2a' 2011-11-07 23:06:04 +00:00
Alexander Ljungberg 80cac38682 0.9.2 installation instructions. 2011-11-07 22:58:43 +00:00
Alexander Ljungberg 2b16d36aa2 Same as previous commit but for real. 2011-11-07 21:41:22 +00:00
Alexander Ljungberg dc9d49a12c GCC is not required to merely install Cappuccino. 2011-11-07 21:39:11 +00:00
Alexander Ljungberg 03c81dfa9c Merge branch 'master' of github.com:cappuccino/cappuccino 2011-11-07 21:18:00 +00:00
Alexander Ljungberg b096e5dd0a Talk even less about Narwhal. Give the logo some space. 2011-11-07 21:12:06 +00:00
Antoine Mercadal 7ae519145f some processing optimizations 2011-11-07 22:03:48 +01:00
Antoine Mercadal 592c3c1652 try to deactivated the kFSEventStreamCreateFlagNoDefer flag in FSEventStream 2011-11-07 21:36:43 +01:00
Antoine Mercadal e940f294a6 store the last eventID before processing anything to avoid mutliple events 2011-11-07 21:20:39 +01:00
Antoine Mercadal 759de8f45f remove debug print 2011-11-07 21:11:27 +01:00
Antoine Mercadal c92c6c37f7 if we were not able to know what event file it is, just consider it's a modification 2011-11-07 21:08:08 +01:00
Antoine Mercadal f425601043 fix bug with undescores in project path. Readd the project.pbx (not so useless) :) 2011-11-07 20:12:23 +01:00
Aparajita Fishman 68ba089a26 Cleanup Debug dialog, insert Debug… item below Help 2011-11-07 11:08:37 -08:00
Alexander Ljungberg 5ff7169546 Don't suggest changing NARWHAL_ENGINE to jsc if it's already jsc. 2011-11-07 19:00:20 +00:00
Alexander Ljungberg 7365a95b4d Friendly welcome screen.
Thanks to primalmotion.
2011-11-07 18:57:10 +00:00
Antoine Mercadal 788427ec09 Preference is now Debug, and is only active when XCC is launch while holding Option key 2011-11-07 19:52:02 +01:00
Alexander Ljungberg 01ed8ad583 Bootstrap without tusk. Reduce visibility of narwhal.
The tusk ecosystem is not maintained anymore within the Cappuccino community. The new installation system is not very elegant but it makes it very easy to release new versions of Cappuccino, while taking the first step on the road towards node.js.
2011-11-07 18:35:29 +00:00
Alexander Ljungberg f516ba7a7d This is Cappuccino 0.9.2. 2011-11-07 18:33:17 +00:00
Andrea D'Amore ab5603bd5a adding autoreconf to JSC's builtin libedit 2011-11-07 17:31:22 +01:00
Antoine Mercadal 5c560e82b3 ensure attached window is not nil when positioning or instanciate it 2011-11-07 15:05:34 +01:00
Antoine Mercadal 263a94af18 remove useless pbxproj that was provoking a warning at build 2011-11-06 10:58:43 +01:00
Antoine Mercadal 9d1cf360b6 rename folder to XcodeCapp and update Jakefiles 2011-11-06 10:54:19 +01:00
Antoine Mercadal 60f664a5c2 rename project to XcodeCapp 2011-11-06 10:48:32 +01:00
Antoine Mercadal a1c7aa7790 Merge remote-tracking branch 'upstream/master' 2011-11-05 16:55:22 +01:00
Antoine Mercadal a29096ca5c Some other improvments
- Add preferences window
- Allow user to choose to use the 10.6 mode on 10.7
- Allow user to choose if he wants to resume listening at startup
- Allow use to choose if XCC should react to inode modification (file level API)
- Support for clean mirrored path when origin files has some _ in their names
- Other various fixes
2011-11-05 16:46:34 +01:00
Antoine Mercadal 0ef64f4091 support for NSProgressIndicator. close #1385 2011-11-05 13:41:16 +01:00
Johannes FahrenkrugandAntoine Mercadal 945deeba60 added a missing @ for the divider-color theme attribute of _CPCornerView. It broke jake (sudo-)install 2011-11-05 07:41:01 +08:00
Antoine Mercadal aa775675b5 add manual test for zombie group rows (#1376) 2011-11-05 00:25:23 +01:00
Antoine Mercadal db76044880 fix zombie group rows style. closes #1376 2011-11-05 00:24:54 +01:00
Antoine Mercadal edc58e358b handle moving files when using file level API (10.7) 2011-11-04 23:23:16 +01:00
Aparajita Fishman 1133efb3f1 Merge branch 'refs/heads/cppopover-fix-transient-delegate-calls' into cappuccino 2011-11-04 12:50:30 -07:00
Aparajita Fishman d524accc98 Fix typo, unintended globals, use constants for CPCoding keys 2011-11-04 12:50:00 -07:00
Aparajita Fishman 543f91dd6e Fixed typos and error message 2011-11-04 12:09:07 -07:00
Randall LueckeandAparajita Fishman 9848dabfa8 Fix typo in popover error. 2011-11-04 12:03:00 -07:00
Antoine Mercadal bc59efc3ba cleanup plist and shadow files under 10.6 2011-11-04 19:48:48 +01:00
Aparajita Fishman 9af63ca32f Fixed compile warning 2011-11-04 10:53:23 -07:00
Aparajita Fishman eb8a566ae8 Fixed support for 10.6 2011-11-04 10:44:01 -07:00
Aparajita Fishman 38eb3e489e Merge branch 'xcc-improvments' of github.com:primalmotion/cappuccino into xcc-improvments
Conflicts:
	Tools/xcodecapp-cocoa/AppController.m
	Tools/xcodecapp-cocoa/TNXCodeCapp.m
	Tools/xcodecapp-cocoa/defines.h
2011-11-04 09:16:52 -07:00
Aparajita Fishman 97f7eaf499 UI overhaul, first attempt at 10.6 compatibility. 2011-11-04 09:15:07 -07:00
Aparajita Fishman d3356eea5c Merge branch 'master' of github.com:cappuccino/cappuccino into cappuccino
Conflicts:
	AppKit/CPPopover.j
2011-11-03 22:32:38 -07:00
Aparajita Fishman 7a57bd73c3 Fixed typos and error message 2011-11-03 22:30:54 -07:00
Randall Luecke b517c93190 Fix typo in popover error. 2011-11-04 01:28:43 -04:00
Antoine Mercadal 7a9fded2e4 fallback into date mode in 10.6 2011-11-04 01:13:16 +01:00
Antoine Mercadal 8ed2096de7 update weird delegate name 2011-11-03 23:14:44 +01:00
Antoine Mercadal 791a1eb130 reactive support for 10.6 EXPERIMENTAL, this support may be removed very soon 2011-11-03 22:10:46 +01:00
Antoine Mercadal 9dab10ce19 Fixes
- Fixes all logic error
- Add sanity checks
- Drop useless and buggy chunck of code
2011-11-03 22:02:48 +01:00
Antoine Mercadal fd95c2ced6 fix About window released when close 2011-11-03 20:19:53 +01:00
Antoine Mercadal c32fef0eb9 forget to add hg and Build folders 2011-11-03 17:54:15 +01:00
Antoine Mercadal c77b35c07b Major XCC improvments
This patch contains the following:

 - FSEvent is now at files level instead of folders level. This allows to drop the registry in plist and improve the performances
 - When you remove a J file, the mirrored H file is removed too
 - .xcodecapp-ignore has been added to the FSEvent stream. ignored token are updated in live
 - By default XCC ignores all .git, .svn, .hg .xCodeSupport, Frameworks and Build folders
 - When you quit XCC without stop listening of the project, at next launch it will resume on the same project
 - Help has been added
 - Help is displayed at first user launch
 - The Error & Warning table doesn't pop ups automatically, instead it displays Growl (you can then open the panel for more informations)
 - The code has been refactored into several classes, one for UI thing, another one for XCC worker
 - Several bugs has been fixed
 - The about window now displays the version number
 - The main window has been removed
 - Several other small enhancements.

This is XCC 2.0.
2011-11-03 17:47:33 +01:00
Antoine Mercadal 4303ea3584 cache delegates methods for _CPAttachedView 2011-11-02 16:59:34 +01:00
Antoine Mercadal ddb6f63ea7 use coherent delegate name 2011-11-02 15:55:58 +01:00
Antoine Mercadal 06985a5b6c fix test 2011-11-02 12:06:05 +01:00
Antoine Mercadal 4841f209b3 fix delegate methods not sent in transient mode when closing 2011-11-02 11:59:20 +01:00
Aparajita Fishman 7e6ed01dd2 Merge branch 'refs/heads/cpwindow-setmovable' into cappuccino 2011-10-31 12:41:32 -07:00
Aparajita Fishman b7e41894af fixed up the test app ui 2011-10-31 12:39:53 -07:00
Alexander Ljungberg 5dfcfc32e7 Fixes #1388. Fixes #1389. Make bootstrap.sh work again. 2011-10-29 11:59:18 +01:00
aparajita fb74541796 Merge pull request #1388 from Ch00rD/master
A few simple updates to the install script and docs.
2011-10-28 20:51:56 -07:00
Sjoerd van Geffen 2f7b29593e replaced "280north" by "cappuccino" for github install script and docs references.
Replaced "280north" by "cappuccino" for github username and all github
URL references in the install script and documentation.
2011-10-29 02:09:18 +02:00
Aparajita Fishman 7ce6b1cfda CPBundleName and CPBundleVersion have to get set in the Jakefile 2011-10-28 16:56:47 -07:00
Aparajita Fishman 7ad1d14d15 Added CPBundleName to Info.plist 2011-10-28 11:30:13 -07:00
Antoine Mercadal 444c30e389 add manual test case 2011-10-28 17:56:37 +02:00
aparajita 06fc31c33b Merge pull request #1322 from aparajita/framework-template
Framework capp template
2011-10-27 15:55:48 -07:00
aparajita 4c58077cee Merge pull request #1321 from aparajita/capp-postinstall
Support for capp postinstall scripts
2011-10-27 15:55:13 -07:00
Aparajita Fishman 25253942a6 replace tab with spaces 2011-10-27 15:53:32 -07:00
Aparajita Fishman 4d75b47713 Added default version 2011-10-27 15:51:22 -07:00
Alexander Ljungberg 63c500c444 Fixed: overlay scroll knobs never quite reached the edge.
The calculation of the number of pixels outside of the clip view assumed fixed, space consuming scrollbars even when overlay scrollbars were used, leading CPScrollView to always think a few more pixels could be revealed.
2011-10-27 15:57:29 +01:00
Alexander Ljungberg 208c3fea35 Fix scroller gap for hidden overlay scrollers.
If there is no vertical scroller, or there is no horizontal scroller, due to autohiding or scroll view settings, a single visible overlay scroller should extend all the way to the edge of its dimension.
2011-10-27 14:44:19 +01:00
Alexander Ljungberg 3201b5921c Fix unterminated var block. 2011-10-27 13:43:02 +01:00
Alexander Ljungberg e92a7825bf Optimise bottom corner view in overlay scrolling mode.
In particular, there is no need to update nor even draw the bottom corner view when in overlay mode.
2011-10-27 13:35:55 +01:00
Alexander Ljungberg 65b1fb2bae Use the scroll view test 1 background in test 2.
The background makes it easier to see the scrolling in action.
2011-10-27 12:52:12 +01:00
Alexander Ljungberg 98df7e1eb8 Refs #1373. Improve documentation. 2011-10-27 11:51:10 +01:00
Antoine Mercadal 86079af3b1 implement CPWindow setMovable: API. close #1358 2011-10-26 11:05:07 +02:00
Alexander Ljungberg eeab0cf1b2 Merge remote-tracking branch 'primalmotion/lionscrollview' 2011-10-25 17:05:03 +01:00
Antoine Mercadal ac16b7ad0b fix a wrong autoresizing mask in manual test of CPScrollView2 2011-10-25 17:18:08 +02:00
Antoine Mercadal e9b87d7acc update the CPScrollView2 manual test to use the new API 2011-10-25 17:14:32 +02:00
Antoine Mercadal b37893d9bb change names of class methods to [set]GlobalScrollerStyle 2011-10-25 17:14:14 +02:00
Alexander Ljungberg 6f4ecdfbd9 Merge remote-tracking branch 'primalmotion/lionscrollview'
Conflicts:
	AppKit/CPScrollView.j
2011-10-25 15:54:16 +01:00
Antoine Mercadal 697921b486 autodetect is user computer is using legacy or overlay mode 2011-10-25 14:35:46 +02:00
Antoine Mercadal 3c01d4aa8b do not put scroller mode here 2011-10-25 14:33:47 +02:00
Antoine Mercadal a1eafdfbd8 update manual test for CPScrollView2 2011-10-25 12:45:18 +02:00
Antoine Mercadal 2cfb171b38 support for system wide scroller style. Set default to legacy mode in info.plist 2011-10-25 12:39:51 +02:00
Antoine Mercadal 2742e3d77b fix flashScrollers doesn't work 2011-10-25 12:11:11 +02:00
Alexander Ljungberg 5488d8f633 Refs #1373. Use self in some class methods to make subclassing easier. 2011-10-24 23:54:50 +01:00
Alexander Ljungberg 35c7155983 Refs #1373. Use legacy style scrollbars by default.
The Lion style scrollbars are inconvenient for users without a touch scrolling device, and we do not have a way to detect whether the user has such a device yet.
2011-10-24 23:51:18 +01:00
Alexander Ljungberg b90a8a58fd Fix some comments. 2011-10-24 23:42:44 +01:00
Alexander Ljungberg 85fa2011b2 Merge pull request #1373 from primalmotion/cappuccino
---

This patch makes CPScrollView acts like Lions NSScrollView.

A online demo can be found here: http://nightlies.archipelproject.org/CPScrollView2/
2011-10-24 20:45:58 +01:00
Alexander Ljungberg 063b05d964 Fixes #1384. Avoid user defaults QUOTA_EXCEEDED_ERR crash.
Switch to cookie based user defaults if HTML 5 local storage exists but is disabled, as is the case when Safari is in 'private browsing' mode.

Don't crash if the local storage quota is reached. Instead log a warning and silently fail to store the new user default.
2011-10-24 01:12:02 +01:00
Alexander Ljungberg ac90a0c0fb Remember multiple split view pre-collapse positions. Autosave.
If more than one subview is collapsed, remember the pre-collapse divider position for each subview separately.

Autosave pre-collapse positions to restore positions when uncollapsing after a reload.
2011-10-23 13:30:37 +01:00
Alexander Ljungberg 3efe33d2fb Split view resize cursors for rightwards collapse.
If the right/lower subview is collapsible and the divider is at its uncollapsed maximum position, continue showing the two way resize cursor to indicate additional movement is actually possible. Also show the shrink cursor when the mouse is over the divider to the left/above of a collapsed subview.
2011-10-23 12:51:51 +01:00
Alexander Ljungberg 3e5ea97768 Eliminate excessive splitViewDidResizeSubviews: messages.
Merely clicking a divider without moving it should not result in a splitViewDidResizeSubviews: message. Fixed errors with setPosition:ofDividerAtIndex:'s no change detection.
2011-10-23 12:28:46 +01:00
Alexander Ljungberg a970657312 Fix split view splitViewDidResizeSubviews: delegate method.
Only call splitViewDidResizeSubviews: after the subviews have actually finished being resized. Make sure to call splitViewDidResizeSubviews: when views are collapsed, even if _adjustSubviewsWithCalculatedSize performed no work.
2011-10-23 11:25:25 +01:00
Alexander Ljungberg 240615c71b Fixed split view right collapse size restore.
When a collapsed split view subview was restored, e.g. by double clicking the divider, and the collapsed subview was on the right hand side of the divider, the pre-collapse split view position was not restored.
2011-10-23 00:09:47 +01:00
Alexander Ljungberg d3f4e205af Support split view collapse rightwards.
When a divider is dragged to the right past half of the minimum width of a collapsible subview, or the divider is double clicked and the delegate returns YES for shouldCollapseSubview:forDoubleClickOnDividerAtIndex:, the subview is collapsed. This is the mirror operation of collapsing towards the left.
2011-10-23 00:01:53 +01:00
Alexander Ljungberg cc63c239f6 Fix StaticResource.includeURLs caching.
The cache was being shadowed by a local variable, forcing the list of includeURLs to be recreated for every call to StaticResource.includeURLs.
2011-10-21 16:06:52 +01:00
Alexander Ljungberg 4b82cae638 Add missing semicolons. 2011-10-21 15:58:50 +01:00
Alexander Ljungberg 68c8d15ed4 Improve split view delegate error handling.
Fixed: if the split view delegate sent non numeric responses when asked to constrain divider positions, subviews would be resized with corrupt size information, which in turn could lead to infinite loops and redraw errors. These bad results are now handled more gracefully.
2011-10-21 15:55:34 +01:00
Alexander Ljungberg 021f5bb030 Fixed: disappearing or fuzzy table header dividing lines at certain table sizes. 2011-10-20 18:51:59 +01:00
Alexander Ljungberg fc5d9a413d Fixes #1380. Fixes #1383. Avoid "popen error (pipe): Too many open files" error when building Cappuccino. 2011-10-20 13:49:16 +01:00
Kevin Jamieson e09acb9208 Update internal string value of CPTextField when a newline is entered or the field loses focus. 2011-10-17 22:00:38 -07:00
Alexander Ljungberg 2f57404c9c Clarify and format bootstrap messages. 2011-10-17 21:51:43 +01:00
Alexander Ljungberg a29bdf0cf4 Merge pull request #1361 from hammerdr/cappuccino
---

Tusk seems to need OJTest to be alone in order to calculate and/or
download dependencies (which are the Objective-J and Cappuccino
pre-built packages).
2011-10-17 21:30:31 +01:00
Alexander Ljungberg c29597689c Tweak bootstrap instructions. 2011-10-17 19:41:41 +01:00
Alexander Ljungberg 797fbca6d4 Merge pull request #1381 from primalmotion/cappuccino
---

running tusk install browserjs jake shrinksafe AND extra packages (OJtest, objj and capp)
in a single instruction prevent the installation of the lasts.

This patch splits the procedure in two separate instructions and should fix all problems.
2011-10-17 19:25:11 +01:00
Antoine Mercadal 6ed4b289d8 Fix bootstrap errors
running tusk install browserjs jake shrinksafe AND extra packages (OJtest, objj and capp)
in a single instruction prevent the installation of the lasts.
This patch splits the procedure in two separate instructions
2011-10-17 20:04:54 +02:00
Alexander Ljungberg 7dd07b2f5b Refs #1378. Unit test for radio group actions. 2011-10-10 14:31:49 +01:00
Alexander Ljungberg b371fda0a5 Refs #1378. Position the continuous button test window so it's visible. 2011-10-10 14:21:08 +01:00
Alexander Ljungberg 3bdb11d804 Merge pull request #1378 from primalmotion/cappuccino
---

Cocoa compliance.

 * updated manual test: log a text only when user clicks a radio button butnot when using the CPButton that uses setState:
 * ignore .xCodeSupport folders.
2011-10-10 14:07:17 +01:00
Antoine Mercadal 199b777dcc update CPButtonTest to test setState: behavior 2011-10-10 14:52:08 +02:00
Antoine Mercadal 70ccec2e82 do not send action when using setState: programatically 2011-10-10 14:49:59 +02:00
Antoine Mercadal a195624549 ignore .xCodeSupport folders 2011-10-10 14:49:06 +02:00
Alexander Ljungberg e417eba6bd CPSplitView autosave support. 2011-10-09 19:11:38 +01:00
Antoine Mercadal 210bb3e5c9 prevent scrollers to show track on mouse enter when ratio is 1 2011-10-06 16:41:36 +02:00
Antoine Mercadal 140ae354a1 try to get 'NSScrollerKnobStyle'. for NSTableView in Xcode, this is not positioned and cause a crash 2011-10-06 15:10:19 +02:00
Antoine Mercadal 2451b08306 fix accidental global 2011-10-06 13:38:31 +02:00
Alexander Ljungberg 04d33e772f Allow binding a table column value to an array controller reached through a key path.
Cocoa might not support this but it is reasonable and consistent, and allows indirect bindings when using multiple CIB files.
2011-10-06 01:59:56 +01:00
Alexander Ljungberg 3592fd8dae Whitespace cleanup. 2011-10-06 01:59:48 +01:00
Alexander Ljungberg 889e8d3b6e Test automatic table bindings. 2011-10-06 00:36:13 +01:00
Alexander Ljungberg 908fc67f96 Whitespace cleanup. 2011-10-06 00:11:59 +01:00
Antoine Mercadal c9a645285a make labels selectable in test project to test accessibility of stuff under the overlay scrollers 2011-10-05 17:54:53 +02:00
Antoine Mercadal 3655724810 fix missing labels in test project 2011-10-05 17:51:49 +02:00
Antoine Mercadal 866047c116 fix sone visual glitches 2011-10-05 17:46:51 +02:00
Antoine Mercadal 8912d31bec do not fade in scrollers on overing 2011-10-05 17:32:44 +02:00
Antoine Mercadal 1e65342814 add manual test for CPScrollView specificities 2011-10-05 17:07:17 +02:00
Antoine Mercadal c7ca352205 remove debug print 2011-10-05 17:00:31 +02:00
Antoine Mercadal 4b1ce8bc0b better art for default knob style 2011-10-05 16:55:08 +02:00
Antoine Mercadal 422e940bc7 use default knob style as default. logic. 2011-10-05 16:24:37 +02:00
Antoine Mercadal 76e2a2b8ca support new properties in nib2cib 2011-10-05 16:24:12 +02:00
Antoine Mercadal e3565bdc7d fix visual glitch when scroller are hidden and overed 2011-10-05 15:57:18 +02:00
Antoine Mercadal 86f01cfaec add a timer before fading out the scroller when overed 2011-10-05 11:34:06 +02:00
Antoine Mercadal 6e4007adc0 add support for the different scroller knob styles 2011-10-05 11:27:32 +02:00
Antoine Mercadal 8c6913c399 small theming adjustment 2011-10-04 17:03:23 +02:00
Antoine Mercadal efdfd0db10 fix some bugs and update arts 2011-10-04 16:21:24 +02:00
Antoine Mercadal d6412eec58 tidy up the CPScrollView class file 2011-10-04 14:36:08 +02:00
Antoine Mercadal 53a6d2de83 support for changing scroller styles 2011-10-04 14:05:02 +02:00
Antoine Mercadal 7fe990e9f6 keep scroller visible if mouse is over, even if timer fire 2011-10-03 21:15:21 +02:00
Antoine Mercadal 7b7ad0715b add artwork 2011-10-03 21:08:06 +02:00
Antoine Mercadal 1a57d032b9 make CPScrollView acting like Mac OS X Lion ones 2011-10-03 21:07:46 +02:00
Alexander Ljungberg 77bb169680 Merge pull request #1371 from primalmotion/cappuccino
---

CPTokenField has the theme state ```CPTextFieldStatePlaceholder``` even if tokens are present, resulting with a wrong positioning of tokens.
2011-10-03 17:10:12 +01:00
Antoine Mercadal b424c19eee optimization 2011-10-03 17:28:32 +02:00
Antoine Mercadal 4d597069cf fix problem in CPTokenField with wrong theme state if containing tokens 2011-10-03 17:08:21 +02:00
Alexander Ljungberg 5afbdf7f20 Merge pull request #1370 from primalmotion/cappuccino
---

Store the conversion date before starting to actually convert. This should avoid to loop indefinitly in case of long conversion time.
Also convert tabs to space, and remove trailing spaces.
2011-10-03 15:10:12 +01:00
Antoine Mercadal 33f558b221 Fix conversion loop
Store the conversion date before starting to actually convert. This should avoids to loop indefinitly in case of long conversion time.
Also convert tabs to space, and remove trailing spaces.
2011-10-03 15:22:16 +02:00
Stephen Ierodiaconou b05d0dd1ec Fix for comparing decimal numbers < 1.0 with 0.0 2011-10-01 10:50:23 +01:00
Alexander Ljungberg b2b305cc4b Merge pull request #1274 from aparajita/cappuccino
---

- Enhanced -description method of CPImage and CPColor to show the exact content, especially for pattern colors.

- Added CPColorWithImages() convenience function, analogous to PatternColor() function used in theme descriptors.

- Added @cond/@endcond in CPColor to ignore local variables.

- Sample app included. See the console for samples of -description output for all color/image types.
2011-09-27 20:53:41 +01:00
Aparajita Fishman c5a9ee544c Comment cleanup, replace CPRect with _CGRect. 2011-09-25 17:06:02 -07:00
Aparajita Fishman 368d66f76e Copy the input frame, it should not be modified in place. 2011-09-25 16:59:44 -07:00
Nicolas GoyandAparajita Fishman 5aaae61b46 Modified CPStepper to support theming better by adding the ability to size buttons through theme 2011-09-25 15:19:14 -07:00
Alexander Ljungberg 29fe50c2d7 Merge pull request #1365 from primalmotion/cappuccino
---

My previous patches was preventing to change the CPPlatformWindowt title once it was opened using windows setTitle:

This patch fix it.
2011-09-21 13:04:24 +01:00
Antoine Mercadal d0c59ee253 fix bug preventing the CPPlatformWindow's title to change once opened 2011-09-21 14:00:35 +02:00
Aparajita Fishman d2e39238f4 Jakefile improvements...
- 'jake clean' now cleans instead of clobbers.
- Added task 'clean-sprites', cleans sprited images.
- Added task 'clobber-theme', clobbers all traces of Aristo.
- Added missing semicolons, followed JavaScript lint suggestions for using dot notation instead of [""].
2011-09-19 21:42:59 -07:00
Alexander Ljungberg 4aec3f7466 Refs #1355. Manual window title test.
In the PlatformWindows test, change the window title both when theWindow is a non platform window and when it is a platform window to verify that the browser window title changes only when it should.
2011-09-17 11:07:38 +01:00
Alexander Ljungberg c8991e07b9 Merge pull request #1355 from primalmotion/cappuccino
---

if setTitle: is called on a CPWindow with the primaryPlatformWindow as platformWindow,
the main pages title is changed. This patch prevent changing the primaryPlatformWindows title.
This is not optimal, but this is better than changing the title at each window setTitle: call
2011-09-17 10:55:43 +01:00
Alexander Ljungberg 48157db973 Refs #1360. Fixed: index was always 0 in CPTokenField tokenField:shouldAddObjects:atIndex: delegate method. 2011-09-16 21:52:09 +01:00
Alexander Ljungberg d070e5fce5 Merge branch 'master' of github.com:cappuccino/cappuccino 2011-09-16 21:47:20 +01:00
Alexander Ljungberg a8fae51ea8 Refs #1360. Cursor movement fixes, optimisations.
Don't move the cursor forward if no token was inserted. Only count new tokens once.
2011-09-16 21:46:20 +01:00
Alexander Ljungberg 2815d462be Refs #1360. Test for CPTokenField tokenField:shouldAddObjects:atIndex:. 2011-09-16 20:51:45 +01:00
Alexander Ljungberg 85f8ca9241 Refs #1360. Format code. 2011-09-16 19:29:53 +01:00
Alexander Ljungberg b5fb9e8c23 Merge pull request #1360 from jigzat/cappuccino
---

Enabled tokenField:shouldAddObjects:atIndex delegate method and used on _autocompleteWithDOMEvent method to have some control over tokens. Not sure why wasnt enabled, it needed very few code. Maybe no one needed it til now.

This is my first collaboration ever, so Im not sure if is of any use.
2011-09-16 19:10:23 +01:00
Klaas Pieter Annema 1addc002d3 Merge branch 'master' of github.com:cappuccino/cappuccino 2011-09-16 12:00:05 +02:00
Klaas Pieter Annema e99e2660e9 more fixes and tests for _CPKVCArray 2011-09-16 11:43:42 +02:00
Aparajita Fishman 03d1bb8bce Added missing statement separator, concatenated var block, fixed symlink deletion/creation sometimes failing. 2011-09-15 17:09:15 -07:00
Klaas Pieter Annema 5b00f7f2e8 improve _CPKVCArray
_CPKVCArray now consistently calls both single and multiple indexes accessors consistently
Tests that verify the behavior are included
2011-09-15 22:32:23 +02:00
Klaas Pieter Annema 97b7f0901e add tests for key view loop behavior 2011-09-15 17:50:37 +02:00
Klaas Pieter Annema 67b2671dad improve key view loops
- include the window's content view at the start of the key view loop
- set the initial first responder to the window's content view (and keep it that way unless it is explicitly changed)
- CPWindow should return NO from acceptsFirstResponder (Cocoa compliance).
- change the type of setInitialFirstResponder, this is compliant with Cocoa. The new key view loop code will break if initial first responder is anything but a view
- change the implementation of selectNextKeyView:, selectPreviousKeyView:, selectKeyViewFollowingView: and selectKeyViewPrecedingView: to follow to Cocoa's documentation
2011-09-15 16:39:24 +02:00
aparajita 7886d49e65 Merge pull request #1359 from primalmotion/fix-and-improve-doxygen-theme
Fix and improve doxygen theme
2011-09-09 21:48:17 -07:00
Samir Gartner e5284e9b43 Fixed some possible error of my part where selectedRange is moved beyond bounds 2011-09-09 22:31:17 -05:00
Samir Gartner c6403baa04 Fixed cursor position issue in a little escapade...guess that's all for now folks 2011-09-09 13:28:37 -05:00
Samir Gartner 662b1ec696 Submitted the right CPTokenField file, was missing the part to use the delegate approved tokens. Still lacks a way to put the cursor after the last token (if the delegate returns more than one token) 2011-09-09 12:48:18 -05:00
Derek Hammer 9570e541d9 Move OJTest install to after the tusk install of other packages.
Tusk seems to need OJTest to be alone in order to calculate and/or
download dependencies (which are the Objective-J and Cappuccino
pre-built packages).
2011-09-09 11:41:01 -05:00
Samir Gartner 043df71185 Enabled tokenField:shouldAddObjects:atIndex delegate method and used on _autocompleteWithDOMEvent method to have some control over tokens. Not sure why wasn't enabled, it was very few code. Maybe no one needed it 'til now 2011-09-08 22:56:52 -05:00
Antoine Mercadal 8dab47f4da mozilla compat 2011-09-08 18:12:32 +02:00
Alexander Ljungberg 90d069df2b Refs #1343. Remove now obsolete README.md.
Everything in the README has been fixed except 3 and 4. 4 is outside of the issue scope and 3 works as intended (nearly). The array controller does not have `setAvoidsEmptySelection:NO` so an empty selection should not be possible unless there are no items.
2011-09-08 17:02:15 +01:00
Antoine Mercadal dcbe3ee650 fix paremeters touching their description in bubbles 2011-09-08 17:15:12 +02:00
Antoine Mercadal e32489aba1 tiny padding improvment in generated html docs 2011-09-08 17:08:50 +02:00
Antoine Mercadal b619c0b793 some small graphical improvments 2011-09-08 16:55:12 +02:00
Antoine Mercadal fab61d14fa forget to restore the bg color of the tree view 2011-09-08 14:44:05 +02:00
Antoine Mercadal b4edc084f8 add Cappuccino logo 2011-09-08 14:00:20 +02:00
Antoine Mercadal c7518d0c49 merge Aparajita's previous improvments on the CSS 2011-09-08 12:44:10 +02:00
Antoine Mercadal a40345c14d fix the slider 2011-09-08 11:46:20 +02:00
Antoine Mercadal 909471a5d7 fix the documentation generation process 2011-09-08 01:30:58 +02:00
Antoine Mercadal 38f7ea00c2 update doxygen.css 2011-09-08 00:43:32 +02:00
Alexander Ljungberg 9f459f053e Fixed: several CPArrayController methods returned undefined instead of booleans. 2011-09-07 18:17:35 +01:00
Alexander Ljungberg 4195f3b8c6 Test that CPArrayController setSelectionIndexes: does not modify its input. 2011-09-07 18:02:53 +01:00
Alexander Ljungberg 4926824482 Fixed: CPArrayController setSelectionIndexes: sometimes modified its input.
Also very slightly improved performance as sometimes the input index set would be instantiated internally and then needlessly copied.
2011-09-07 17:53:48 +01:00
Alexander Ljungberg cb2f539cf7 Send didChange in reverse order of willChange in CPObjectController setContent:. 2011-09-07 17:32:19 +01:00
Alexander Ljungberg 7f31be7cb1 Fixed: array replaceObjectsInRange:withObjectsFromArray: always failed with a "'null' is not an object' error.
This was caused by the new range checks in f8404c7a97.
2011-09-07 16:18:08 +01:00
Alexander Ljungberg 78b9c5b576 Fixes #1343. Support nested willChange… didChange… calls.
When multiple calls are nested, only the first willChange… and the last didChange… will notify observers, avoiding duplicate notifications for the same change.
2011-09-07 16:14:01 +01:00
Alexander Ljungberg 01e35efdbb Refs #1343. Recreate manual bindings test as an automatic test. 2011-09-07 16:04:35 +01:00
Aparajita FishmanandAlexander Ljungberg bef1687b1f Test app for bindings fixes. 2011-09-07 12:51:36 +01:00
Antoine Mercadal afa691376e fix unable to change mainWindow's title 2011-09-02 14:00:49 +02:00
Antoine Mercadal be10bcf27a Fix CPPlatformWindow's title bug
if setTitle: is called on a CPWindow with the primaryPlatformWindow as platformWindow,
the main page's title is changed. This patch prevent changing the primaryPlatformWindow's title.
This is not optimal, but this is better than changing the title at each window setTitle: call
2011-09-02 12:42:09 +02:00
Alexander Ljungberg 608cb86a4a Whitespace cleanup. 2011-08-31 18:51:15 +01:00
Alexander Ljungberg 88780ff0a9 Merge pull request #1352 from primalmotion/cappuccino
---

In latest versions of webkit window.open(url) return undefined if url == ""
2011-08-31 18:47:43 +01:00
Antoine Mercadal a5e241afd7 update PlatformWindows test (use the slider to play with the titles) 2011-08-31 19:17:41 +02:00
Antoine Mercadal 28772d3254 use CPWindow's title for platform window 2011-08-31 19:17:10 +02:00
Antoine Mercadal d1f5c1eebc patch for enventual webkit bug with window.open() 2011-08-31 18:28:47 +02:00
Alexander Ljungberg c77a282aaf Raise CPRangeException if CPString substringToIndex: is out of bounds. 2011-08-27 23:50:18 +01:00
Alexander Ljungberg 7a1cd5c545 Fix CPString substringToIndex documentation. The index parameter is not inclusive. 2011-08-27 23:49:40 +01:00
Alexander Ljungberg 29ff54054e Fix a typo. 2011-08-22 23:03:34 +01:00
Alexander Ljungberg 8e1bbe0132 Merge pull request #1345 from primalmotion/cappuccino
---

This patch allow to send play message before
the sound is actually loaded (by remembering the play request
and playing the sound when loaded if needed)

this allows to do:

```objj
var sound = [[CPSound alloc] initWithContentsOfURL:aSoundURL byReference:NO];
[sound play];
```
2011-08-22 22:59:39 +01:00
Antoine Mercadal a2b6585c0d CPSound support play while loading
This patch allow to send 'play' message before
the sound is actually loaded (by remembering the play request
and playing the sound when loaded if needed)

this allow to do:

```objj
var sound = [[CPSound alloc] initWithContentsOfURL:aSoundURL byReference:NO];
[sound play];
```
2011-08-20 18:48:11 +02:00
Francisco Ryan Tolmasky I aa452952a8 Merge pull request #1344 from aparajita/valueForKeyPath-tweak
Much more efficient test for first character of string
2011-08-18 09:43:46 -07:00
Aparajita Fishman 6ea4aa0a66 Much more efficient test for first character of string 2011-08-18 00:52:59 -04:00
Randy Luecke 2462cd7b1d Merge pull request #1316 from primalmotion/cppopover
add CPPopover (Cocoa API compliant)
2011-08-17 11:17:02 -07:00
Randy Luecke 331e338c06 Merge pull request #1333 from eventualbuddha/CPAlert-subclass-builder-support
Allow CPAlert subclasses to use +alertWithMessageText:... et al.
2011-08-17 11:16:20 -07:00
Randy Luecke 2b68f40872 Merge pull request #1341 from cacaodev/CPTableView_drawBackgroundInClipRect
CPTableView: -drawBackroundInClipRect: bug
2011-08-17 11:15:33 -07:00
Randy Luecke 2f7b3c306d Merge pull request #1335 from alexmipego/master
CPBox autoresize settings
2011-08-17 11:13:46 -07:00
Randy Luecke eba5dbe654 Merge pull request #1334 from aparajita/array-range-checking
Added some missing range checking.
2011-08-17 11:11:49 -07:00
Randy Luecke 9ae1f548bf Merge pull request #1338 from purem/master
Added zsh to xcodecapp-cocoa
2011-08-17 11:05:18 -07:00
Alexander Ljungberg d191255a84 Merge branch 'master' of github.com:280north/cappuccino 2011-08-12 19:50:49 -04:00
Alexander Ljungberg 9bf8824109 nib2cib support for token fields. 2011-08-12 19:50:30 -04:00
Alexander Ljungberg f773bd217c Fixed with token field: remove false ivar '_tokenIndex' and fix tokenField:tokenField completionsForSubstring:indexOfToken:indexOfSelectedItem: ignoring its indexOfToken: parameter. 2011-08-12 19:46:39 -04:00
Alexander Ljungberg a5f0f0e3db CPTokenField archiving support. 2011-08-12 19:29:59 -04:00
Alexander Ljungberg 6f6bfc667b Inverted CPCharacterSet characterSetWithCharactersInString now archive properly. 2011-08-12 19:27:02 -04:00
Alexander Ljungberg 0789f49b94 CPCharacterSet isEqual support when the set is of the characterSetWithCharactersInString kind. 2011-08-12 19:12:47 -04:00
Alexander Ljungberg 92c94eab8f CPCharacterSet archiving support when the set is of the characterSetWithCharactersInString kind. 2011-08-12 18:50:06 -04:00
cacaodev 9f06ed725e CPTableView: -drawBackroundInClipRect:
Fixes a bug where we were drawing rows from 0 instead of the first exposed when usesAlternatingBackgroundColors:YES
2011-08-11 21:06:19 +02:00
Jonathan R H Evans c45039fd70 Added zsh to the list of shell configs that xcodecapp-cocoa checks. 2011-08-09 10:15:23 +01:00
Aparajita Fishman 8e203ec78e Fixed range checking for insertObject:atIndex: 2011-08-08 15:14:30 -07:00
alexmipego e32515e5cc Make boxEnclosingView: copy the auto resizing settings of the view 2011-08-07 20:22:14 +01:00
Klaas Pieter Annema 2b77da821c always build xcodecapp with 10.6 SDK 2011-08-06 16:43:11 +02:00
Aparajita Fishman f8404c7a97 Added some missing range checking. 2011-08-05 14:40:13 -07:00
Brian Donovan 156610ee07 Allow CPAlert subclasses to use +alertWithMessageText:... et al. 2011-08-05 08:32:44 -07:00
Alexander Ljungberg fcaf672bf8 Merge branch 'master' of github.com:280north/cappuccino 2011-07-29 02:43:52 -04:00
Alexander Ljungberg dd5d8fcdce Closes #1305. Fixed: don't constrain max toolbar item width to the width of the label. 2011-07-29 02:42:42 -04:00
Alexander Ljungberg e0c4f6455d Tweak some messages. 2011-07-29 02:02:11 -04:00
Alexander Ljungberg dd5d7e9979 Whitespace cleanup. 2011-07-29 02:01:31 -04:00
Alexander Ljungberg 408baac91e Fix Xcode capitalisation in xcodecapp-cocoa. 2011-07-29 02:00:14 -04:00
Klaas Pieter Annema f241142216 don't disallow setEnabled for auto enabled items 2011-07-21 14:41:47 +02:00
Klaas Pieter Annema f0561844d8 don't close a menu item with a submenu
A submenu item should only close the menu if it has a non default action.
This is compliant with how Cocoa behavior.
2011-07-21 12:23:11 +02:00
Randall Luecke bd6294b806 Updated Jakefile for xcodecapp-cocoa to use the proper variable name. This should also fix the buildbot. 2011-07-17 22:46:27 -07:00
Alexander Ljungberg 70f8e3a832 Merge pull request #1278 from aparajita/cappuccino
---

 I discovered the following behavior that is not in conformance with Cocoa:

- Backspace, tab, escape, and space are considered key equivalents.
- Function keys (F1 - FNN) are not considered key equivalents.
- CPTextField executes `performKeyEquivalent` twice if a field is first responder.

Build this Cocoa project and debug it: http://d.pr/Xc3h

Take a look at the debug log while typing some keys. You will see that backspace, tab, escape and space do not trigger `performKeyEquivalent`, and that `performKeyEquivalent` is only executed once for the first responder.

Then run the performKeyEquivalentsTest app in this commit and look at the console log while trying keys in the text fields. If you turn the old code on, you will see how `performKeyEquivalent` is executed twice for the first responder.

For reference on key handling code, I consulted this:

http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/EventOverview/EventArchitecture/EventArchitecture.html%23//apple_ref/doc/uid/10000060i-CH3-SW11
2011-07-17 22:55:18 -04:00
Alexander Ljungberg 59b302acde Merge pull request #1177 from cacaodev/cappuccino
---

Adds -scrollViewWillScroll: and -scrollviewDidScroll: delegate methods to CPScrollView.

These methods are not in AppKit but exist in UIKit. Useful for lazy loading data in a view, for example a CPTableview.
Tested in the CPScrollView example.

Conflicts:
	AppKit/CPScrollView.j
2011-07-17 22:05:55 -04:00
Alexander Ljungberg f54f8dfec9 Merge branch 'master' of github.com:280north/cappuccino 2011-07-17 21:48:53 -04:00
Alexander Ljungberg 93135e7e81 Header fixes. 2011-07-17 21:47:40 -04:00
Alexander Ljungberg b8026e19ba Merge pull request #1320 from MCF/cappuccino
---

If a CPTextFields target action changed the first responder then the target action was called twice if the textfield edit was completed by hitting the enter/return key.  This fixes the problem by setting the _isEditing flag to NO before the action is called in the insertNewline function.

See [this thread](https://groups.google.com/group/objectivej-dev/browse_thread/thread/ff64a4520102b3c5?hl=en) for more details.

Also included a new manual test for an editable CPTableView to make testing the fix easier.
2011-07-17 21:43:23 -04:00
Randy Luecke 147d9282fb Merge pull request #1323 from primalmotion/xcodecapp-cocoa-menu-for-error-panel
Small improvments in XcodeCapp-Cocoa
2011-07-17 15:49:21 -07:00
Antoine Mercadal 7c18b8bc5f Small improvments in XcodeCapp-Cocoa
- Do not release the Error & Warning window on close (or you can't open it again)
 - Small graphical updates
 - Remove the Growl notification in case of error (panel is sufficient)
 - Add a menu to open the error and warning panel when user wants to
2011-07-17 23:50:14 +02:00
Randall Luecke 2ccbf5d4e5 Errors in xcodecapp-cocoa now show up in their own panel. Should we keep growl? 2011-07-17 13:46:57 -07:00
Randall Luecke da6d8c86d1 Merge branch 'xcodecapp-cocoa-merge' of https://github.com/primalmotion/cappuccino into primalmotion-xcodecapp-cocoa-merge 2011-07-17 13:45:41 -07:00
Randall Luecke 78d997b404 Remove xcodecapp-cocoa in preparation for a proper merge 2011-07-17 13:44:09 -07:00
Aparajita Fishman 89b23ef0d7 Framework capp template 2011-07-17 09:17:08 +03:00
Aparajita Fishman b958911c63 Support for postinstall scripts 2011-07-17 09:15:26 +03:00
Randall Luecke c6e5219f2e Add Xcodecapp-cocoa build to Tools Jakefile 2011-07-16 23:11:13 -07:00
Randall Luecke 3bb450adbf Merge branch 'master' of git://github.com/280north/cappuccino 2011-07-16 22:57:56 -07:00
Randall Luecke a0f5257258 Errors in xcodecapp-cocoa now show up in their own panel. Should we keep growl? 2011-07-16 22:57:12 -07:00
Randall Luecke 6520615bb0 Merged xcodecapp-cocoa 2011-07-16 22:53:49 -07:00
Randy Luecke 4593212698 Merge pull request #1299 from farcaller/5d26066e02f6d1203981b27c8acf7f7991f4a419
Fixup for CPDictionary's dictionaryWithJSObject:recursively: and null objects in arrays
2011-07-16 19:45:45 -07:00
Randy Luecke 5363deb122 Merge pull request #1285 from aparajita/CPPredicate-fix
CPPredicate fix
2011-07-16 19:40:17 -07:00
Randy Luecke d5a651fc43 Merge pull request #1290 from hammerdr/include-ojtest
Adding OJTest installation to the bootstrap.sh file.
2011-07-16 19:39:52 -07:00
Randy Luecke 4740acbcc6 Merge pull request #1292 from aparajita/doxygen-font-fix
Use Menlo if Consolas is not available
2011-07-16 19:36:35 -07:00
Randy Luecke bfb2134329 Merge pull request #1293 from aparajita/CPKeyedArchiver-tweak
CPKeyedArchiver - Removed unused variable, fixed typo
2011-07-16 19:36:00 -07:00
Randy Luecke ec83977fe1 Merge pull request #1312 from aparajita/CPPlatformString-missing-methods
Make sure CPPlatformString +sizeOfString and +metricsOfFont work with CommonJS
2011-07-16 19:33:32 -07:00
Randy Luecke 98d08ff05d Merge pull request #1317 from aparajita/themeClass-fix
Have to set _themeClass when class changes
2011-07-16 19:32:54 -07:00
Randy Luecke 1eb6319b49 Merge pull request #1313 from cacaodev/CPViewAnimation
CPViewAnimation: current frame based on -currentValue.
2011-07-16 19:30:25 -07:00
Mike Fellows 8f7e06f9d6 Fix regression to CPTextField's insertNewline, duplicate target actions were being called when an edit on a textfield was ended with an enter/return keypress 2011-07-15 18:55:03 -07:00
Mike Fellows 81e3abe10c Add CPTableView test for editable table cells. 2011-07-15 18:54:53 -07:00
Klaas Pieter Annema edcee8934d fix empty contextual menus out of bounds error 2011-07-14 16:26:58 +02:00
Klaas Pieter Annema d115d2ef47 fix context menu only closes after two clicks
This is a regression from 73b4c33f05.
Because we were only tracking wether the left mouse button went up after a contextual menu (which is opened with the right mouse)
would only close after the second left mouse up.
2011-07-14 11:15:34 +02:00
Alexander Ljungberg d1dd725848 Merge pull request #1318 from aparajita/cappuccino
---

And several bugs fixed in the process.
2011-07-09 20:51:33 -04:00
Aparajita Fishman ebdba33082 Whitespace cleanup 2011-07-09 17:08:08 -07:00
Aparajita Fishman 918f6fbb8f CPFormatter support, bug fixes...
- Test application.

CPControl
---------
- Moved _formatter declaration up next to value, it was in the Target-Action Support section before.

- sendAction:to: should return a BOOL.

- Support for CPFormatter -editingStringForObjectValue.

- If a nil string is passed to -setStringValue in Cocoa, it raises an invalid parameter assertion and does nothing.

- Per Cocoa, if setting a string value fails, it tries again with an empty string.

- Removed a few extra blank lines.

- Changed NULL to nil.

CPTextField
-----------
- The string value is now cached in _stringValue to avoid constant calls to the formatter.

- There were several places where references to _inputElement were not wrapped with #if PLATFORM(DOM).

- When resigning first responder, if there is a formatter and formatting fails, reject the resignation and keep focus. Also, if the delegate responds to control:didFailToFormatString:errorDescription:, invoke it.

- _willBecomeFirstResponderByClick was not being set to NO when resigning. As a result, if you clicked in a field, tabbed to another field, and tabbed back to the original field, it would not select the text because it thought there was a mouse click.

- Don't send _sendStringValue: in keyUp: if the value has not changed. Previously it would do that for non-printing keys like navigation keys.

- insertNewLine: validates the string the same way resigning does.

- insertNewLine: would not send textDidEndEditing: if the field had no action, but it should.

- insertNewLine: should select all text (per Cocoa).

- insertNewLineIgnoringFieldEditor: and insertTabIgnoringFieldEditor: were not replacing the selection, Cocoa docs say they should.

- Per Cocoa, when setting an object value and there is a formatter, the value is first formatted as a string. If that fails, an object value for an empty string is attempted.

CPFormatter
-----------
- Fixed up the docs to match the method signatures.

- Indicated with "Ref" in argument types if the argument is pass by reference.

- isPartialStringValid:newEditingString:errorDescription: has a default implementation in Cocoa that nils the return values and returns YES.

- Fixed the name of isPartialStringValid:proposedSelectedRange:originalString:originalSelectedRange:errorDescription:

- isPartialStringValid:proposedSelectedRange:originalString:originalSelectedRange:errorDescription: has a default implementation in Cocoa that invokes isPartialStringValid:newEditingString:errorDescription:
2011-07-09 17:05:23 -07:00
Antoine Mercadal 28733ec592 label are white in CPPopoverTest if popover is HUD 2011-07-09 15:29:37 +02:00
Antoine Mercadal 916b9a399b make color matching Aristo 2.0 ones 2011-07-09 15:29:13 +02:00
Antoine Mercadal 3d62791477 fix animation lack in FF prevents Popover to close 2011-07-09 11:50:52 +02:00
Aparajita Fishman 64e6764015 Have to set _themeClass when class changes 2011-07-08 19:04:33 -07:00
Antoine Mercadal cbed5c9cb1 support for CPPopover 2011-07-08 17:51:08 +02:00
Antoine Mercadal 0246d501e2 full support for CPPopover and nib2cib + enchanced delegates 2011-07-08 17:49:53 +02:00
Antoine Mercadal 3d5b30ab9e add CPPopover (Cocoa API compliant) 2011-07-08 15:50:29 +02:00
Klaas Pieter Annema 4719578f10 fix 0 is a valid highlighted index 2011-07-07 20:40:22 +02:00
Klaas Pieter Annema fe370c7066 Merge branch 'master' of github.com:280north/cappuccino 2011-07-07 18:37:24 +02:00
Klaas Pieter Annema 63d208bf20 never return a separator as the highlighted item 2011-07-07 18:33:00 +02:00
Alexander LjungbergandKlaas Pieter Annema 5158540208 Fixed: initialise CPNumberFormatter maximumFractionalDigits to 3. 2011-07-07 16:04:12 +02:00
Alexander LjungbergandKlaas Pieter Annema a69f7dc81a Test CPTextField with a formatter. 2011-07-07 16:04:11 +02:00
Alexander LjungbergandKlaas Pieter Annema e848e161d4 CPNumberFormatter maximum fractional digits support. Optimise by only creating CPDecimalNumberHandler when needed and caching the result. 2011-07-07 16:04:11 +02:00
Alexander LjungbergandKlaas Pieter Annema 3db61216e1 CPFormatter support for CPControl which actually works. 2011-07-07 16:04:11 +02:00
Alexander LjungbergandKlaas Pieter Annema 63b00186f4 Fixed: level indicator warning and critical level ranges should be inclusive. 2011-07-07 16:04:11 +02:00
Alexander LjungbergandKlaas Pieter Annema 110d4c478d Fixed: pressing the up arrow key in a table view would cause a crash if the previous selection was non continuous. 2011-07-07 16:04:11 +02:00
Alexander LjungbergandKlaas Pieter Annema 49c29ded92 Nib2cib support for formatters. 2011-07-07 16:04:11 +02:00
Alexander LjungbergandKlaas Pieter Annema 06670f2214 CPFormatter support for CPControl. 2011-07-07 16:04:11 +02:00
Alexander LjungbergandKlaas Pieter Annema 134bfec615 Temporary numberFromString:. 2011-07-07 16:04:11 +02:00
Alexander LjungbergandKlaas Pieter Annema 279326ffe1 CPNumberFormatter rounding mode support. 2011-07-07 16:04:10 +02:00
Alexander LjungbergandKlaas Pieter Annema ecb04e983e Simple CPNumberFormatter stringFromNumber for CPNumberFormatterDecimalStyle. 2011-07-07 16:04:10 +02:00
Klaas Pieter Annema 73b4c33f05 track if the mouse was released after menu open
Make sure the menu isn't closed by the mouse up that is directly followed by the mouse down that opened the menu.
2011-07-07 16:04:10 +02:00
Klaas Pieter Annema ad30f4dcbb call delegate when submenu open and close 2011-07-07 16:04:10 +02:00
Klaas Pieter Annema 0318587f80 Set the title of a menu item's submenu
Correspond to Cocoa's behavior by automatically having CPMenuItem set the title of it's submenu
2011-07-07 16:04:10 +02:00
Klaas Pieter Annema 2b6fddf26c move menu delegate logic to generic methods 2011-07-07 16:04:04 +02:00
Alexander Ljungberg da61da392b Fixed: initialise CPNumberFormatter maximumFractionalDigits to 3. 2011-07-06 14:08:44 -04:00
Alexander Ljungberg 984b46ba07 Test CPTextField with a formatter. 2011-07-06 13:36:41 -04:00
Alexander Ljungberg 1abce77b3a Merge branch 'master' of github.com:280north/cappuccino 2011-07-06 13:32:46 -04:00
Francisco Ryan Tolmasky I 420606d8e8 Tests for forward invocation.
Reviewed by @tolmasky.
2011-07-02 13:33:53 -07:00
Francisco Ryan Tolmasky I 80c8fd9794 Fix bundletask to include .js files.
Reviewed by @tolmasky.
2011-07-02 08:38:10 -07:00
Antoine Mercadal 1f479c3f20 fix another problem with space in name that prevent launching XCode on the shadow project 2011-07-01 18:28:00 +02:00
Klaas Pieter Annema 0af89853d4 Merge pull request #1311 from aparajita/registerThemeValues-tweak
Added missing type in +registerThemeValues signature
2011-07-01 08:41:29 -07:00
Antoine Mercadal b5bb9c8ec3 fix a bug with NSURL and spaces 2011-07-01 17:29:12 +02:00
Randall Luecke ff13de9f75 Merge branch 'master' of git://github.com/280north/cappuccino 2011-07-01 00:05:19 -07:00
Randall Luecke 47f40eb04b Added left/right arrow key expand and collapse... just for you @tolmasky. 2011-07-01 00:04:09 -07:00
Aparajita Fishman 1ffc7ed6fb Make sure CPPlatformString +sizeOfString and +metricsOfFont work with CommonJS, so that OJUnitTest will work. 2011-06-29 10:52:22 -07:00
Aparajita Fishman 63710d5fae Added missing type in method signature 2011-06-29 09:08:12 -07:00
Klaas Pieter Annema a2ef701d18 Merge branch 'master' of github.com:280north/cappuccino 2011-06-29 16:05:26 +02:00
Klaas Pieter Annema 55e07536d9 don't start dragging if there are no rows 2011-06-29 16:04:46 +02:00
Randall Luecke fc81483371 Fix typeo in CPToolbar.j CPToolbarItems to not respect maxSize. Closes #1305. 2011-06-25 00:45:07 -07:00
Klaas Pieter Annema e552b022ba Merge branch 'pull-request-1302' 2011-06-24 12:21:02 +02:00
Antoine Mercadal af0a479f88 small style fix 2011-06-21 17:18:16 +02:00
Andrea D'Amore 86a28d8cc1 removed warning for Growl's framework path from relase target too 2011-06-21 17:05:00 +02:00
Andrea D'Amore 3dd178a69d fixes warnings while building: Growl bridging protocol, menu delegate, nonexistent framework search path, parser.j compiling 2011-06-21 16:09:21 +02:00
Antoine Mercadal 417334419a display the two last path components in title (usefull for localized bundles) + increase FSEvent latency 2011-06-20 15:37:13 +02:00
Antoine Mercadal 6c34bec51e do not return 0 if any conversion fail (return 2 instead) 2011-06-19 19:32:42 +02:00
Antoine Mercadal c03b3c2d34 use terminationStatus, not lenght of the nib2cib output 2011-06-19 19:24:45 +02:00
Antoine Mercadal e97d4a8e72 fix typo in FS checking 2011-06-19 18:55:06 +02:00
Antoine Mercadal 24d0af3104 warn if something goes wrong about sourcing bash profile path + add quote on paths in NSTasks' arguments 2011-06-18 21:07:15 +02:00
Antoine Mercadal 5790e99359 small style fix 2011-06-16 20:39:29 +02:00
Tobias Adamson 0d6c2c9890 Changed from using system call to NSTask, this enables the app to report on incorrect nib2cib and objj settings and usage.
Examples where a Growl message will now be send to indicate error
1. nib2cib or objj not found in path
2. Compilation errors with objj
3. XIB files with Cocoa components that are not supported yet
2011-06-16 18:57:34 +08:00
Ross Boucher cbabb544ab bootstrap should have a +x bit. 2011-06-15 12:54:11 -07:00
Alexander Ljungberg 42220e057b CPNumberFormatter maximum fractional digits support. Optimise by only creating CPDecimalNumberHandler when needed and caching the result. 2011-06-13 23:19:06 -07:00
Derek Hammer c5df9c973f Making the directions go before the prompt (doh!). Changing bootstrap to
+x.
2011-06-13 21:50:17 -07:00
Alexander Ljungberg 91509e7d36 CPFormatter support for CPControl which actually works. 2011-06-13 18:39:17 -07:00
Derek Hammer b89aa9af0d Merge branch 'master' of git://github.com/280north/cappuccino into include-ojtest 2011-06-12 10:07:15 -07:00
Alexander Ljungberg 4421b55613 Fixed: level indicator warning and critical level ranges should be inclusive. 2011-06-11 04:43:16 -07:00
Alexander Ljungberg 75d9929483 Fixed: pressing the up arrow key in a table view would cause a crash if the previous selection was non continuous. 2011-06-11 04:21:49 -07:00
Alexander Ljungberg 7c78c2ef5d Nib2cib support for formatters. 2011-06-11 03:59:52 -07:00
Alexander Ljungberg 3758c86d20 CPFormatter support for CPControl. 2011-06-11 03:59:33 -07:00
Alexander Ljungberg ada547a79d Temporary numberFromString:. 2011-06-11 03:36:44 -07:00
Alexander Ljungberg 445adcb47f CPNumberFormatter rounding mode support. 2011-06-10 11:41:23 -07:00
Alexander Ljungberg 4e9b975ca8 Simple CPNumberFormatter stringFromNumber for CPNumberFormatterDecimalStyle. 2011-06-10 11:23:36 -07:00
Vladimir Pouzanov 5d26066e02 Fixed dictionaryWithJSObject on arrays with null values 2011-06-08 14:10:10 +03:00
Antoine Mercadal de73d86684 Merge pull request #1 from gustaf-lindqvist/xcodecapp-cocoa-space-in-path-fix
xcodecapp-cocoa space in path fix

Reviewed.
2011-06-08 01:11:02 -07:00
Gustaf Lindqvist d6244f090e Fix white spaces in path for system() 2011-06-08 09:10:28 +02:00
Alexander Ljungberg aac09d8208 Clicking on a non-editable level indicator in a table row now selects that row. 2011-06-06 00:44:15 -04:00
Alexander Ljungberg a127fc9ec3 'Enabled' support for nib2cib of NSLevelIndicator. 2011-06-06 00:35:41 -04:00
Alexander Ljungberg 551aa300ea Merge branch 'master' of github.com:280north/cappuccino 2011-06-06 00:11:23 -04:00
Alexander Ljungberg 485e59b5eb More handlesContentAsCompoundValue, although fairly guess-work based. More research needed in the future. 2011-06-06 00:11:04 -04:00
Alexander Ljungberg fdfcbf1da2 CPArrayController handlesContentAsCompoundValue support for contentArray binding. 2011-06-05 19:39:28 -04:00
Alexander Ljungberg 0f5eee0258 nib2cib compatible CPNumberFormatter skeleton. 2011-06-05 19:27:21 -04:00
Alexander Ljungberg 870492eb96 Fix selection behaviour in previous commit. 2011-06-05 19:19:14 -04:00
Alexander Ljungberg b50005049e Fixed: array controller remove: would not only remove selected rows, but any other rows isEqual: to the selected rows. 2011-06-05 18:57:36 -04:00
Alexander Ljungberg 0e890e19ea Fixed: during CPUserDefault change notifications, objectForKey: could return the value from prior to the change. 2011-06-05 17:32:56 -04:00
Alexander Ljungberg 59aabc150c Crude but functional infinite recursion checker, optional at compile time. 2011-06-04 01:23:24 -04:00
Alexander Ljungberg b159815349 Suppress binding updates support. 2011-06-04 00:57:57 -04:00
Tom Robinson fa0a4d3b56 Fix tests for CI. 2011-06-03 21:15:25 -07:00
Aparajita Fishman 1c44dc1052 Removed unused variable, fixed typo 2011-06-03 18:09:57 -07:00
Alexander Ljungberg bfe5afaddd Whitespace cleanup. 2011-06-03 00:05:30 -04:00
Alexander Ljungberg 64e907156c Minor array controller optimisation: don't send a filterPredicate change notification if clearsFilterPredicateOnInsertion is YES but filterPredicate is already nil when insertObject:atArrangedObjectIndex: is called. 2011-06-03 00:00:39 -04:00
Alexander Ljungberg 5d01ca428c Optimise CPArrayController insertObject:atArrangedObjectIndex: by not attempting to arrange the content array. The given index is only meant for the arrangedObjects. 2011-06-02 23:41:03 -04:00
Alexander Ljungberg 0a9c9741e8 CPArray mutableCopy. 2011-06-02 15:09:54 -04:00
Alexander Ljungberg 2a3b9e13c3 Merge branch 'master' of github.com:280north/cappuccino 2011-06-02 12:35:23 -04:00
Alexander Ljungberg 4e07c9f9ee Decode but mostly ignore NSImages in nib2cib. Fixed: radio groups in IB come with an NSImage and so would not nib2cib anymore after the recent addition of template image support in NSButton. 2011-06-02 12:33:43 -04:00
Aparajita Fishman 4f7fbdc344 Use Menlo if Consolas is not available 2011-06-01 18:22:57 -07:00
Klaas Pieter Annema 9f2804c700 Merge branch '0.9.1b' 2011-06-01 12:10:10 +02:00
Klaas Pieter Annema 16183cca09 fix nib2cibbed controls enabled state 2011-06-01 12:09:49 +02:00
Klaas Pieter Annema 0af3b2f97c Merge branch 'master' of github.com:280north/cappuccino 2011-05-31 14:38:38 +02:00
Klaas Pieter Annema 065227a467 Merge branch '0.9.1b' 2011-05-31 14:38:18 +02:00
Klaas Pieter Annema 753257a650 Always tile the collectionview
A collectionview should always tile because it needs to adjusts it's size to properly work with an enclosing scrollview
2011-05-31 14:37:29 +02:00
Derek Hammer c5f37e665b Adding OJTest installation to the bootstrap.sh file. Also added the
cappuccino/objective-j packages back to the file.
2011-05-31 03:05:24 -07:00
Francisco Ryan Tolmasky I 671666e842 Fix selector typo.
Reviewed by me.
2011-05-31 01:27:41 -07:00
Francisco Ryan Tolmasky I b9ba1bbe93 Merge branch 'master' of github.com:280north/cappuccino 2011-05-31 00:46:23 -07:00
Francisco Ryan Tolmasky I 33e4fea0ec Fix forwarding in Objective-J (and many infinite recursions, such as when there is no superclass):
1. Fix infinite recursion when no superclass and method isn't implemented. Closes #469.
2. Fix infinite recursion when coercing an object without description implemented into a string. Closes #1289.
3. Add -forwardingTargetForSelector: support.

Reviewed by @tolmasky.
2011-05-31 00:44:16 -07:00
Aparajita Fishman 99180ba001 Enable escape as key equivalent. 2011-05-30 23:20:06 -07:00
Randall Luecke 2887d4224c Remove empty setThemeState method in CPTableView 2011-05-30 23:08:41 -07:00
Randall Luecke 7a52805587 Support for setContinuous in CPLevelIndicator 2011-05-30 22:16:38 -07:00
Alexander Ljungberg 56d0ebe420 Typo fix. 2011-05-30 22:48:12 -04:00
Alexander Ljungberg b4b54e5744 Partial button image support in nib2cib covering NSAddTemplate and NSRemoveTemplate (standard plus and minus buttons). 2011-05-30 22:16:42 -04:00
Alexander Ljungberg 8a9d997b44 Manual test for CPUserDefaultsController and nib2cib of it. 2011-05-30 21:34:20 -04:00
Alexander Ljungberg e1f55fce3a nib2cib support for CPUserDefaultsController. 2011-05-30 21:15:43 -04:00
Alexander Ljungberg 6f6ce40c06 CPUserDefaultsController. 2011-05-30 21:03:44 -04:00
Alexander Ljungberg e32b302c59 Fixed: don't return nil from CPController initWithCoder:. 2011-05-30 20:45:35 -04:00
Alexander Ljungberg 302e753ebc Table nib2cib test with taller table rows and a level indicator cell. The latter is very useful when comparing cell spacing between Cappuccino and Cocoa. 2011-05-30 18:05:49 -04:00
Alexander Ljungberg 1c007461bd Draw table view gridlines precisely inside the right side of cells so that grid line positioning and spacing matches Cocoa.
Checked against Cocoa with 0, 1, 2 and 3 px intercell spacing.
2011-05-30 17:46:46 -04:00
Alexander Ljungberg 3d1638c780 Fixed: remove unused var block. 2011-05-30 16:56:24 -04:00
Alexander Ljungberg c5965c41d5 Fixed: don't repeat level indicator graphics downwards when the indicator is made taller than its natural size. Instead centre the indicator vertically.
This is not strictly like Cocoa - Cocoa places it on top vertically. But vertical centring makes more sense in e.g. tables with a large row height so it seems to make sense to deviate slightly here.
2011-05-30 16:21:50 -04:00
Alexander Ljungberg 7cc6fa348c Less flashy level indicator colours. 2011-05-30 12:56:35 -04:00
Alexander Ljungberg 1e6bca2214 Test level indicator with many segments. 2011-05-30 12:44:00 -04:00
Alexander Ljungberg d199bd86e6 More square level indicator segments which look better when each segment is very small. Colour and shadowing tweaks. Removed most of control border for a cleaner look. 2011-05-30 12:42:19 -04:00
Alexander Ljungberg 6338b01cb4 Fix accidental global. 2011-05-30 11:56:52 -04:00
Alexander Ljungberg 7714bcc34c Merge pull request #1288 from primalmotion/cappuccino
---

This patch avoids to have this kind of problem when too much segments are present:

<http://gyazo.com/36da2019514c429dd6edc2318fc101fc>

And do this:

<http://gyazo.com/65e23eb978dc493be96633c612e538ca.png>

+ fix typo ("self" not "sef")
2011-05-30 11:55:21 -04:00
Antoine Mercadal e6f029c1fa use all remaining space for last segment 2011-05-30 17:17:42 +02:00
Antoine Mercadal fe606e4757 fix typo + wrong sizing behaviour with too much segment 2011-05-30 17:06:39 +02:00
Alexander Ljungberg a6ee37e030 Support level indicators as table cells through nib2cib. 2011-05-30 00:56:28 -04:00
Alexander Ljungberg 71364c9b1a Fixed: very large numbers written to 280north1 plist files would be read back as very small numbers.
This affected nib2cib and cib files in particular.
2011-05-30 00:51:35 -04:00
Alexander Ljungberg a34155da61 Whitespace cleanup. 2011-05-30 00:43:07 -04:00
Alexander Ljungberg 2b8fa11b84 Optimise level indicator archiving (don't record static background colour). 2011-05-30 00:03:12 -04:00
Alexander Ljungberg 8fdcbac2bd Fix CPTableColumn width, minWidth and maxWidth encoding. 2011-05-29 23:18:30 -04:00
Alexander Ljungberg 4316192b8d Support NSButtonCell (e.g. checkboxes) in table columns through nib2cib. 2011-05-29 21:24:41 -04:00
Alexander Ljungberg 19090de380 Relayout level indicator as needed. 2011-05-29 16:47:36 -04:00
Alexander Ljungberg 85c5094c8b Manual test for level indicator. 2011-05-29 16:17:40 -04:00
Alexander Ljungberg ed8811e66b Click and drag edit support for level indicators. 2011-05-29 16:04:27 -04:00
Alexander Ljungberg b2e13919e0 Support for editing level indicators. 2011-05-29 15:41:53 -04:00
Alexander Ljungberg b4dabb6c35 Fix level indicator property names. 2011-05-29 15:26:21 -04:00
Alexander Ljungberg e9d0be1b6a Level indicator drawing. 2011-05-29 15:17:28 -04:00
Alexander Ljungberg 3f2607c2d0 CPLevelIndicator nib2cib support. 2011-05-28 18:44:32 -04:00
Alexander Ljungberg ceaea9c5b0 Remove leftover reference code. 2011-05-28 18:44:16 -04:00
Alexander Ljungberg 5419272e48 Fixed: don't import NSSlider.j in NSSlider.j. 2011-05-28 18:08:17 -04:00
Alexander Ljungberg 888fc89f86 Foundation for CPLevelIndicator. 2011-05-28 17:53:39 -04:00
Alexander Ljungberg 66c644641c Merge branch 'master' of github.com:280north/cappuccino 2011-05-28 02:08:22 -04:00
Alexander Ljungberg 669c6d4ac0 Merge branch '0.9.1b' 2011-05-28 02:08:03 -04:00
Alexander Ljungberg 8ed06169d1 Merge branch '0.9.1b' of github.com:280north/cappuccino into 0.9.1b 2011-05-28 02:07:33 -04:00
Alexander Ljungberg cf04fcc9d0 Verify correctness of observation notifications on arrangedObjects when the addObjects: message is sent. 2011-05-28 02:06:27 -04:00
Alexander Ljungberg 2e5081b137 Optimise array controller addObject: by eliminating entirely pointless rearrange when added objects did not pass the filter. Also avoided double rearrange if clearsFilterPredicateOnInsertion.
CPArrayControllerPerformance.j execution time on "testAddObject_, sorted, filtered" down from ~420ms to ~60ms on my machine.
2011-05-28 02:02:24 -04:00
Alexander Ljungberg a1a06c3f75 Performance test array controller addObject: when clearing the filter predicate. 2011-05-28 01:47:25 -04:00
Alexander Ljungberg e4950bd831 Fixed: duplicate observer notification for array controller addObject: (on arrangedObjects). 2011-05-28 01:26:28 -04:00
Alexander Ljungberg 607f681780 Typo fix. 2011-05-26 23:59:49 -04:00
Alexander Ljungberg 6eb4bf6656 Add temporary @ref and @deref analogs. 2011-05-26 23:59:08 -04:00
Aparajita Fishman 9377cf9128 Test app and unit test to validate pinned ranges in beginsWith/endsWith predicate comparison. 2011-05-26 14:31:20 -07:00
Aparajita Fishman e17d8ca302 Pin ranges to valid values. 2011-05-26 14:31:13 -07:00
Klaas Pieter Annema 9b3926cada Merge branch '0.9.1b' 2011-05-24 12:30:07 +02:00
Klaas Pieter Annema 815e64356d implement _minimumFrameSize in CPButton 2011-05-24 12:29:23 +02:00
Klaas Pieter Annema 249a63af95 don't use remove method for removeMany selector 2011-05-24 12:28:25 +02:00
Klaas Pieter Annema 8520247605 Merge pull request #1247 from primalmotion/bundletask-option-preventsnib2cib
add setPreventsNib2Cib to bundletask.js
2011-05-23 22:45:42 -07:00
Aparajita Fishman acbaa1eec4 Restored space, backspace and escape as key equivalents, but only if the first responder is not a CPTextField. Updated test app to show clearly the effect of this change. 2011-05-23 16:31:52 -07:00
Alexander Ljungberg 686bce00d9 Merge branch '0.9.1b' 2011-05-23 13:49:09 -04:00
Alexander Ljungberg 8ae94c2745 Put CPBox in the right documentation module and add some basic documentation. 2011-05-23 13:46:09 -04:00
Klaas Pieter Annema 8feb5b5cee Merge branch 'right-command-key-fix' of https://github.com/aparajita/cappuccino into aparajita-right-command-key-fix 2011-05-23 11:14:12 +02:00
cacaodevandKlaas Pieter Annema 2b52f7d8da - Fixed a bug where the right control was incorrectly recreated with a default value when switching operators.
- As per cocoa, the predicate is recomputed when you send the right control action, not when you change text.  Update-as-you-type can be turned ON by subclassing -_sendsActionOnIncompleteTextChange method. Default is NO.
- Rewrote _reconfigureSubviews method, should be faster.
2011-05-23 10:59:44 +02:00
cacaodevandKlaas Pieter Annema ea660e3dd4 CPPredicateEditorRowtemplate:
Fixed a bug  when menu item titles and their corresponding keypath expressions where different and templates created in IB.
Fixed a bug appearing in Xcode4 IB when titles and keypath where identical.
2011-05-23 10:59:43 +02:00
cacaodevandKlaas Pieter Annema ca1a1b43f1 CPRuleEditor & CPPredicateEditor & CPPredicateEditorRowtemplate implementations with theming, nib2cib support.
Tests: CPRuleEditorCibTest, CPPredicateEditorCibTest, SmartFoldersDemo: a real world usage of CPPredicateEditor.
Documentation for these 3 new classes.
2011-05-23 10:59:43 +02:00
Aparajita Fishman 65b6ff6ecc Fixed set of keys that can be considered a key equivalent, removed redundant call to performKeyEquivalent, test app 2011-05-22 18:05:48 -07:00
Ross Boucher 6c6ac4bd2e Merge pull request #1276 from hammerdr/Documentation
Elaborate what setItemPrototype expects and does in CPCollectionView.
2011-05-22 17:17:04 -07:00
Aparajita Fishman 59e5689d1a On WebKit (at least on Mac), right Command key code is 93, not 91. This was not being interpreted correctly. 2011-05-22 17:07:49 -07:00
Derek Hammer 7194a6961a Forgot a forward slash to end the pre tag. 2011-05-22 17:58:25 -05:00
Derek Hammer e404217e8b Elaborate what setItemPrototype expects and does in CPCollectionView. 2011-05-22 17:55:17 -05:00
Randy Luecke f419629ce4 Merge pull request #1260 from aparajita/cpmenu-remove-all
Added CPMenu -removeAll
2011-05-21 18:21:15 -07:00
Randy Luecke 35f958f1a7 Merge pull request #1273 from aparajita/cornerview-fix
CPTableView does not remove corner view if header view is removed
2011-05-21 18:20:43 -07:00
Antoine Mercadal df7aa30267 include xcodecapp-cocoa in the Cappuccino build process. 2011-05-21 00:39:50 +02:00
Antoine Mercadal 0f4aab926e add Jakefile to build xcodecapp-cocoa 2011-05-21 00:24:10 +02:00
Antoine Mercadal 7f3512d22c update .gitignore 2011-05-21 00:23:47 +02:00
Antoine Mercadal a6b5ed22b0 make parse.j LGPLv3 2011-05-21 00:02:22 +02:00
Antoine Mercadal e843b31287 update license of xcodecapp-cocoa 2011-05-20 23:39:13 +02:00
Antoine Mercadal 06a5aa45ba Merge remote branch 'xcodecapp-cocoa/master' into xcodecapp-cocoa-merge 2011-05-20 23:34:07 +02:00
Antoine Mercadal 45a5eed62f Merge xcodecapp-cocoa 2011-05-20 23:32:17 +02:00
Antoine Mercadal 188e27e931 update status bar icon 2011-05-20 23:05:41 +02:00
Aparajita Fishman f7a7f06c67 Use CPLog instead of console.log 2011-05-20 08:12:37 -07:00
Antoine Mercadal ed560ed489 display ... when actually doing some jobs 2011-05-20 12:13:28 +02:00
Antoine Mercadal 186eb66f52 Make XCodeCapp-Cocoa a status bar application
+ fix bash_profile, thanks to @natemartinsf
 + add gitignore
2011-05-20 11:59:43 +02:00
Aparajita Fishman 860f0d5846 CPColor and CPImage enhancements
- Enhanced -description method of CPImage and CPColor to show the exact content, especially for pattern colors.

- Added CPColorWithImages() convenience function, analogous to PatternColor() function used in theme descriptors.

- Added @cond/@endcond in CPColor to ignore local variables.

- Sample app included.
2011-05-20 00:23:55 -07:00
Alexander Ljungberg 64f9309994 Merge pull request #1268 from primalmotion/cappuccino
---

This patch makes nib2cib dealing with NSButtons much more better by setting particular offsets
according to the the kind of button.

Here is a screenshot of what I have done in IB :
<http://img839.imageshack.us/img839/4379/19894787.png>

This is the rendering of nib2cib without this patch:
<http://img263.imageshack.us/img263/1708/without.png>

This is the rendering of nib2cib with this patch:
<http://img263.imageshack.us/img263/1097/with.png>
2011-05-19 21:54:12 -04:00
Alexander Ljungberg 1c201d7dba Refs #1270. Fix a typo. 2011-05-19 21:50:30 -04:00
Alexander Ljungberg e1cd4d0f6e Merge pull request #1270 from aparajita/cappuccino
---

- Worked around a major bug in doxygen. It turns out that doxygen would not generate documentation for the first method -- or sometimes all methods (e.g. CPPredicate) -- if the ivar block for a class was missing or empty. This is solved now by inserting a dummy __doxygen__ ivar block.
- Missed a text substitution
- Darkened up the method header a bit to make it easier for the eye to anchor on.
- Changed to centered, fixed-width layout, it results in shorter line lengths which reads more easily.
- Moved support files to separate support directory.
- Removed blank lines at end of multi-parameter method prototypes.
- Fixed font declaration so fonts are correct in FireFox.
- Added spacing between parameter descriptions in method prototype.
- Fixed formatting of class description for CPPredicate.
- Added a missing @endverbatim to CPExpression.j.
2011-05-19 21:44:49 -04:00
Alexander Ljungberg 8fcbf3ce0c Merge branch '0.9.1' 2011-05-19 21:39:18 -04:00
Antoine MercadalandAlexander Ljungberg 915867e296 update the CPToolTip manual test 2011-05-19 21:33:36 -04:00
Antoine MercadalandAlexander Ljungberg ac24b9ee68 Fix Firefox problem. close #1271
This patch fix the blink problem with FF, by changing the positionning of tooltips, which by the way reflects more the Cocoa behaviour.
2011-05-19 21:33:25 -04:00
Aparajita Fishman aa7345935d Oops, accessor methods weren't being synthesized, removed some cruft 2011-05-19 17:10:50 -07:00
Aparajita Fishman 3937e66e06 Major fix to documentation generation:
- It turns out doxygen would not generate documentation for the first method in a file (or sometimes any methods at all) if there was no ivar block or an empty ivar block. Now a dummy __doxygen__ ivar is inserted in empty blocks to force correct behavior.

- Added a missing @endverbatim to CPExpression.j.

- Tweaked class documentation for CPPredicate.j.
2011-05-19 16:47:11 -07:00
Aparajita Fishman 634fa7b850 Stupid Uber Glory bundle duplicated the file a few times when stripping whitespace. 2011-05-18 17:33:30 -07:00
Aparajita Fishman f132ec5a50 Fixed formatting of lists and code in class description. The code did not change, I don't know why git says it did. 2011-05-18 16:55:43 -07:00
Aparajita Fishman 896f91215e Whitespace cleanup 2011-05-18 16:54:21 -07:00
Alexander Ljungberg b3d3f742f1 Merge pull request #1272 from primalmotion/cappuccino
---

This patch fix the blink problem with FF, by changing the positionning of tooltips, which by the way reflects more the Cocoa behaviour.
2011-05-18 14:50:53 -04:00
Antoine Mercadal bf516b5fc5 update the CPToolTip manual test 2011-05-18 19:33:01 +02:00
Aparajita Fishman 4ab69ebb68 If there is no header view, there should be no corner view. This is what Cocoa does. Also for correctness -enclosingScrollView should be used to get the table's scrollview. Test app included. 2011-05-18 10:30:43 -07:00
Antoine Mercadal 5a7c38d6eb Fix Firefox problem. close #1271
This patch fix the blink problem with FF, by changing the positionning of tooltips, which by the way reflects more the Cocoa behaviour.
2011-05-18 19:30:16 +02:00
Aparajita Fishman 6d962bc51a More documentation enhancements...
- Changed to centered, fixed-width layout, it results in shorter line lengths which reads more easily.
- Moved support files to separate support directory.
- Removed blank lines at end of multi-parameter method prototypes.
2011-05-18 07:50:27 -07:00
Antoine Mercadal e8a38e0bc0 add small visual test project 2011-05-18 08:51:05 +02:00
Aparajita Fishman 800e32edad Missed a text substitution, darkened up the method header a bit 2011-05-17 21:14:01 -07:00
Antoine Mercadal 4acb757aec adjust CPTextField positioning. Offsets changed since the usage of the new Aristo Art 2011-05-17 23:02:25 +02:00
Antoine Mercadal 9708985901 Make CPPopUpButton positionning pixel perfect 2011-05-17 22:16:26 +02:00
Ross Boucher 27a1c5e9a4 Merge pull request #1269 from aparajita/CPScrollView-doc-tweak
CPScrollView documentation tweak
2011-05-17 12:40:24 -07:00
Aparajita Fishman d7ef31c4f5 Documentation tweak 2011-05-17 10:54:52 -07:00
Antoine Mercadal fde18bba2e Correct button positionning.
This patch makes nib2cib dealing with NSButtons much more better by setting particular offsets
according the the kind of button.
2011-05-17 19:30:42 +02:00
Alexander Ljungberg f7a2a2e6fd Merge branch '0.9.1'
Conflicts:
	Tools/nib2cib/NSFont.j
2011-05-17 01:18:56 -04:00
Alexander Ljungberg fb07e2ae06 Refs #1266. Simple manual/visual test for font conversion. 2011-05-17 01:17:38 -04:00
Alexander Ljungberg f414ed2e8d Refs #1266. Still convert default font size in nib2cib even if the default font is bold.
(E.g. Lucida Grande 13 Bold should become Arial 12 Bold, not Arial 13 Bold.)
2011-05-17 01:16:03 -04:00
Alexander Ljungberg 86f3cc1831 Refs #1266. Minor optimisation. 2011-05-17 00:45:36 -04:00
Antoine MercadalandAlexander Ljungberg e77c706c38 nib2cib now takes care of bold and italic
This allows to set bold and italic in IB even if the size of the font is the default one
2011-05-17 00:45:28 -04:00
Alexander Ljungberg 8bdb0f6215 Replace extremely outdated and defunct NibApp manual test with a new one based on current templates, preserving and fixing the good parts of NibApp. 2011-05-17 00:40:41 -04:00
Alexander Ljungberg ec5c0e361d Refs #1266. Minor optimisation. 2011-05-17 00:38:39 -04:00
Alexander Ljungberg 533dbbfc69 Merge branch 'master' of github.com:280north/cappuccino 2011-05-17 00:12:08 -04:00
Alexander Ljungberg 0e04f7cae3 Merge pull request #1266 from primalmotion/cappuccino
---

This allows to set bold and italic in IB even if the size of the font is the default one
2011-05-17 00:11:57 -04:00
Antoine Mercadal e4c708efde nib2cib now takes care of bold and italic
This allows to set bold and italic in IB even if the size of the font is the default one
2011-05-17 00:28:33 +02:00
Francisco Ryan Tolmasky I 28bd18fab6 Merge pull request #1265 from aparajita/NSColorWell-enabled
NSColorWell was not setting its enabled state
2011-05-16 12:28:29 -07:00
Aparajita Fishman c9faea8753 NSColorWell was not setting its enabled state 2011-05-16 11:16:22 -07:00
Alexander Ljungberg 24c5b5f6c9 Merge branch '0.9.1' 2011-05-15 19:48:32 -04:00
Alexander Ljungberg 868201b492 Merge pull request #1033 from jlujan/cappuccino
---

The expression in the while loop in setParameters results in the wrong value being assigned to "key" which results in malformed param tags that look like the following:

    <param name=​"[object HTMLObjectElement]" >

Also, _params is not checked before assignment in setParameters which will overwrite flashvars if setFlashVars was called before setParameters.

Addresses issues #1031 and #1032
2011-05-15 19:47:43 -04:00
Alexander Ljungberg 8db94c0849 Merge branch '0.9.1' 2011-05-15 19:37:10 -04:00
Alexander Ljungberg f8984ced97 Refs #903. Comment out failing tests until Obj-J 2 fixes them. 2011-05-15 19:36:04 -04:00
Alexander Ljungberg 7539b5b06d Merge pull request #903 from paulbaumgart/cappuccino
---

Some OJTestCases for the Preprocessor to help make sure it still works as expected when it gets revamped to remove with() from method code generation.

Note that this adds a test case which the current Preprocessor fails: http://github.com/paulbaumgart/cappuccino/commit/8cc61cccfd78debe96eba96a7b332938e6d5377e#L1R81
2011-05-15 19:25:10 -04:00
Alexander Ljungberg 4ae47ed7c4 Merge branch 'master' of github.com:280north/cappuccino 2011-05-15 19:06:26 -04:00
Alexander Ljungberg 23cc507b12 Refs #1264. Make tooltip delay a constant and reduce it to 1.0 second to match Cocoa a little more closely.
Perhaps we should implement something like [[CPToolTipManager sharedToolTipManager] setInitialToolTipDelay:X] for completeness.
2011-05-15 19:01:26 -04:00
Alexander Ljungberg e9cfc806b6 Refs #1264. Size to fit small tooltips to remove empty whitespace on right side. 2011-05-15 18:58:01 -04:00
Alexander Ljungberg 5994c48d5f Refs #1264. Fix accidental global, cleanup. 2011-05-15 18:36:21 -04:00
Alexander Ljungberg bba0de3306 Merge pull request #1264 from primalmotion/cappuccino
---

These commits make the tooltips looking like cocoa ones.

 - More simple implementation (only one file added _CPToolTips.j)
 - Removal of CPAttachedWindow and CPAttachedWindowView
 - Placement is based on mouse position (just like cocoa)
 - It will try to find the best placement in case of a lake of space

Here is a screenshot : http://twitpic.com/4x401t
2011-05-15 18:29:51 -04:00
Francisco Ryan Tolmasky I 55937daa20 Merge pull request #1263 from aparajita/CPMenuManager-cleanup
_CPMenuManager style cleanup
2011-05-15 13:37:08 -07:00
Antoine Mercadal fe53f2503b let a fancy padding in case of placement forcing due to a lack of space 2011-05-15 22:36:33 +02:00
Antoine Mercadal 9058857403 style 2011-05-15 22:17:11 +02:00
Antoine Mercadal c7517d81c7 remove useless variables 2011-05-15 22:17:11 +02:00
Antoine Mercadal b8f46565ef make CPToolTip a framework private class 2011-05-15 22:17:11 +02:00
Antoine Mercadal 10940ace13 improve CPToolTips. Make them more cocoa like. Remove usage of CPAttachedWindow 2011-05-15 22:15:37 +02:00
Antoine Mercadal c57842d125 move Tooltips to CPView 2011-05-15 22:14:44 +02:00
Aparajita Fishman bb3ed30b4e Style cleanup 2011-05-15 12:15:00 -07:00
Alexander Ljungberg 1b1bd039c9 Merge branch '0.9.1' 2011-05-14 13:32:22 -04:00
Alexander Ljungberg 3fe907f007 Merge remote branch 'aparajita/better-docs' into 0.9.1 2011-05-14 13:28:19 -04:00
Alexander Ljungberg c784a2a1ca Merge branch '0.9.1' 2011-05-14 13:14:04 -04:00
Alexander Ljungberg d4d01d9686 Refs #1261. Clean up README.html tmp build file when jake docs is done. 2011-05-14 13:10:49 -04:00
Alexander Ljungberg 7ca8d0fb01 Whitespace cleanup. 2011-05-14 13:05:07 -04:00
Aparajita Fishman b985081184 Tweak the class list page 2011-05-12 23:16:50 -04:00
Aparajita Fishman 02f61fa413 Lightened up box around method prototype 2011-05-12 16:56:28 -04:00
Alexander Ljungberg 1a8808a4fd Merge pull request #1261 from aparajita/cappuccino
---

- Added generic facility for pre- and post-processor scripts to be run.
- Added support utility script for inclusion by processors.
- Totally overhauled css to make the pages more readable (I hope).
- Fixed some doc errors in CPTableView.
- Dont generate XML.
- Added colorize() and colorPrint() functions to common.jake.
- Added docs-no-frame task for generating docs without a sidebar frame.
2011-05-12 15:02:57 -04:00
Aparajita Fishman be5bbdcb32 Another overhaul of doc generation.
- Added generic facility for pre- and post-processor scripts to be run.
- Added support utility script for inclusion by processors.
- Totally overhauled css to make the pages more readable (I hope).
- Fixed some doc errors in CPTableView.
- Don't generate XML.
- Added colorize() and colorPrint() functions to common.jake.
- Added docs-no-frame task for generating docs without a sidebar frame.
2011-05-12 14:41:54 -04:00
Aparajita Fishman 1e9798eead Whitespace cleanup 2011-05-11 23:59:43 -04:00
Aparajita Fishman 3242e35250 Added CPMenu -removeAll method, removed unused internal _itemIsHighlighted method, test app 2011-05-11 23:59:33 -04:00
Alexander Ljungberg 864c4495c3 Merge branch '0.9.1' 2011-05-11 21:39:58 -04:00
Alexander Ljungberg 1c0f679f50 Refs #1245. Fixed: setToolTip: belongs in CPView, not CPControl. 2011-05-11 21:36:49 -04:00
Alexander Ljungberg 71763d041b Merge branch '0.9.1' 2011-05-11 21:04:47 -04:00
Alexander Ljungberg 345d48e224 Refs #1245. Make CPToolTip and CPAttachedWindow internal since they're not part of the Cocoa API. Refactored some code from CPControl to CPToolTip. 2011-05-11 20:35:13 -04:00
Alexander Ljungberg bb97c107c9 Refs #1245. Minor clean up. 2011-05-11 20:02:08 -04:00
Alexander Ljungberg 37cad2f59a Merge pull request #1245 from primalmotion/cappuccino
---

This is a basic merge of the TNKits tooltip system in Cappuccino.
2011-05-11 19:30:41 -04:00
Alexander Ljungberg 4ccbd592b2 Merge branch '0.9.1' 2011-05-11 19:28:34 -04:00
Alexander Ljungberg 8f5fe55dea Manual test for continuous buttons. 2011-05-11 19:28:01 -04:00
Alexander Ljungberg a51a051cee Fixed: if a button was unarchived it would have no continuous push delay and a 0 interval. 2011-05-11 19:15:44 -04:00
Alexander Ljungberg abd32f5abc Renamed CPButtonImageTest to CPButtonTest to reuse it for non image related tests.
Having fewer but slightly wider manual tests reduces the number of individual apps which need testing when changes are made.
2011-05-11 19:03:21 -04:00
Alexander Ljungberg d869350a56 Merge branch 'master' of github.com:280north/cappuccino 2011-05-11 18:54:50 -04:00
Alexander Ljungberg a3cd47b57c Merge pull request #1100 from MCF/cappuccino
---

Move the functionality from CPSteppers _CPContinuousButton object into CPButton.  Now any button can be made continuous instead of just the buttons for CPStepper.
2011-05-11 18:40:07 -04:00
Francisco Ryan Tolmasky I 019acb76a3 Very minor style change.
Reviewed by me.
2011-05-10 21:34:34 -07:00
Francisco Ryan Tolmasky I 4509df3c2a Merge pull request #1259 from masonmark/fix-test-for-leopard-sdk
Fix build-time test for presence of Mac OS X 10.5 SDK
2011-05-10 21:33:25 -07:00
Mason Mark 7059dd63b7 Use code style similar to other code in file 2011-05-11 13:26:18 +09:00
Mason Mark 402c82801b Extra newline typo 2011-05-11 13:23:09 +09:00
Mason Mark b84d721887 Fix build-time test for presence of Mac OS X 10.5 SDK
Some jake build tasks test whether the 10.5 SDK is present, and if so, they build using it. However, the path to the SDK is not necessarily consistent across installations, so testing for path existence is not the best way to check whether the SDK is present. Doing it that way caused build failures on machines with both Xcode 3 and Xcode 4 installed. In this fix, we now ask xcodebuild what SDKs are present, and only fall back on the path existence test if the local copy of xcodebuild does not support listing SDKs (as is the case for old versions of xcodebuild).
2011-05-11 13:15:12 +09:00
Randy Luecke 48ccbb8883 Merge pull request #1258 from aparajita/performKeyEquivalent-docs
Correct -performKeyEquivalent docs.
2011-05-10 16:23:38 -07:00
Aparajita Fishman 23a5b83ea6 Corrected and added -performKeyEquivalent docs. 2011-05-10 19:20:37 -04:00
Alexander Ljungberg 5a2e5a7de3 Fixed CPColor isEqual: for pattern images. 2011-05-09 21:38:32 -04:00
Alexander Ljungberg 3db05c94ab Closes #682. Fix CPColor isEqual:. 2011-05-09 20:59:38 -04:00
Alexander Ljungberg 1ba69aee91 Refs #1254. Updated unit test to account for, and verify that CPSet addObject:nil/undefined throws an exception. 2011-05-09 20:03:09 -04:00
Aparajita Fishman ea958160dc Although it is not directly documented, CPMutableSet -addObject should raise with nil or undefined. 2011-05-09 15:49:44 -04:00
Alexander Ljungberg 3d614b38c1 Merge branch '0.9.1' 2011-05-09 14:54:54 -04:00
Alexander Ljungberg d51921d4f3 Closes #664. Fixed: web view sizing bug when loading contents prior to adding the view to the display tree. 2011-05-09 14:54:30 -04:00
Alexander Ljungberg eb8d9775aa [CPView _isVisible] convenience method. 2011-05-09 14:54:24 -04:00
Alexander Ljungberg d5a0469333 Closes #664. Fixed: web view sizing bug when loading contents prior to adding the view to the display tree. 2011-05-09 14:38:17 -04:00
Alexander Ljungberg d5f281320f [CPView _isVisible] convenience method. 2011-05-09 14:37:54 -04:00
Alexander Ljungberg 1e49072763 Merge branch '0.9.1' 2011-05-09 01:37:29 -04:00
Alexander Ljungberg d6c7fecf64 Closes #684. Cleaned up, added attribution and instructions for the CPWebView2 manual test. 2011-05-09 01:36:23 -04:00
Alexander Ljungberg 1392714896 Manual test which tests the effectiveness of both of the previous fixes.
The test also includes a URL based web view to show it works before and after the fixes.
2011-05-09 01:24:33 -04:00
Alexander Ljungberg 2563cb5dc1 Refs #684. Handle content reflows and associated scroll updates when unhiding a CPWebViewScrollAppKit webview. 2011-05-09 01:13:57 -04:00
Alexander Ljungberg c42295f0c7 Refs #684. Fixed: sizing problem when revealing hidden CPWebView. 2011-05-09 00:59:45 -04:00
Alexander Ljungberg cc9bcabf38 Remove apparently unused CPWebView ivar _scrollSize and code.
_scrollSize was never set anywhere in Cappuccino, yet it only had an effect if set.
2011-05-09 00:46:25 -04:00
Alexander Ljungberg 6d98583fa6 Merge branch '0.9.1' 2011-05-09 00:34:22 -04:00
Alexander Ljungberg 6f869cebc1 Closes #688. Unit test verifying that the CPColor hexString weakness described in issue 688 has been resolved. 2011-05-09 00:29:43 -04:00
Francisco Ryan Tolmasky I 5c10615c9f Fix for could not load theme errors in nib2cib. CFBundle was using Image to determine if the platform in question supported image spriting. On Rhino, the Image object doesn't exist, throwing an exception and causing everything to break from that point forward.
Reviewed by me.
2011-05-06 12:40:09 -07:00
Klaas Pieter Annema 1a842b2a6f add manual test case for previous commit 2011-05-05 13:21:50 +02:00
Klaas Pieter Annema 9842640474 add more CPMenuItem keyEquivalent mappings 2011-05-05 13:15:38 +02:00
Ross Boucher 1b1bd4f972 Merge pull request #1249 from aparajita/shared-image-fix.
Ensure multiple _CPImageAndTextViews sharing the same image are notified
2011-05-04 11:10:58 -07:00
Klaas Pieter Annema d8a09722c6 Merge branch '0.9.1' 2011-05-04 19:08:42 +02:00
Klaas Pieter Annema 21a50b990f fix 2 bugs in CPIndexPath
1. we didn't return a copy of the indexes
2. indexPathByRemovingLastIndex didn't remove the last index
2011-05-04 19:07:06 +02:00
Aparajita Fishman 739c844b10 Make sure multiple _CPImageAndTextViews sharing the same image are all notified when it is loaded. 2011-05-04 12:16:43 -04:00
Randall Luecke cd05d30f86 Fix for setting a new platform window on a visisble window throwing a DOM exception. 2011-05-01 21:01:13 -04:00
Antoine Mercadal 8b566f06f0 set default build as Universal Binary 2011-04-30 15:50:36 +02:00
Antoine Mercadal 3012cc7c92 add setPreventsNib2Cib to bundletask.js
This allows to be able to have the XIB/NIB and CIB version in the resource
directory and to prevent to run nib2cib by just copying the CIB version.
This is very usefull in the caseof using a Linux build machine for your application
2011-04-30 11:40:47 +02:00
Klaas Pieter Annema a9fe07f854 Merge branch '0.9.1' 2011-04-29 12:02:14 +02:00
Klaas Pieter Annema 0f88207d7b fix out of bounds error in itemWithTitle: 2011-04-29 12:01:51 +02:00
Antoine Mercadal 28d174d9d8 handle when user click on cancle on open panel 2011-04-28 18:19:18 +02:00
Antoine Mercadal dd892f746d enable garbage collection + growl support 2011-04-28 18:08:27 +02:00
Antoine Mercadal 95b1b8b19d at first launch, parse all the project in a thread 2011-04-28 17:00:11 +02:00
Antoine Mercadal 298b73ddfc initial commit 2011-04-28 16:35:57 +02:00
Klaas Pieter Annema 81ffed3b9b Merge branch '0.9.1' 2011-04-28 14:01:24 +02:00
Klaas Pieter Annema ead6e4a592 implement CPDictionary's keysSortedByValueUsingSelector 2011-04-28 14:01:04 +02:00
Alexander Ljungberg 288c3e9c70 Merge branch 'master' of github.com:280north/cappuccino 2011-04-27 13:20:51 -04:00
Alexander Ljungberg 5a580f4983 Merge branch '0.9.1' 2011-04-27 13:20:39 -04:00
Alexander Ljungberg 9cf664fe7b Merge branch '0.9.1' of github.com:280north/cappuccino into 0.9.1 2011-04-27 13:16:49 -04:00
Alexander Ljungberg 10ec8b528c Correct return type for [CPURL staticResourceData]. 2011-04-27 13:14:44 -04:00
Antoine Mercadal 3ddf6031fb Support for tooltips on CPControls 2011-04-26 14:46:30 +02:00
Klaas Pieter Annema 0ee304058d consolidate both CPKeyValueObservingTests into one 2011-04-26 11:34:47 +02:00
Klaas Pieter Annema 03e7d81ffa fail more gracefully when attempting to remove the same observer twice
Before this commit we would fail gracefully for single keys. For key paths an application would crash because we would try to get the forwarder property of an undefined object. This commit makes sure we don't attempt any removal and logs a warning (just like Cocoa) about the attempt to remove an unregistered observer.
2011-04-26 11:34:40 +02:00
Klaas Pieter Annema afb2352a7c consolidate both CPKeyValueObservingTests into one 2011-04-26 11:20:47 +02:00
Klaas Pieter Annema cde179786c fail more gracefully when attempting to remove the same observer twice
Before this commit we would fail gracefully for single keys. For key paths an application would crash because we would try to get the forwarder property of an undefined object. This commit makes sure we don't attempt any removal and logs a warning (just like Cocoa) about the attempt to remove an unregistered observer.
2011-04-26 11:19:51 +02:00
Randall Luecke 1b3792a1cc Exclude build directory in xcodecapp. 2011-04-25 17:13:43 -04:00
Randy Luecke 3d8b836184 Merged pull request #1243 from gorenje/more_unit_tests_2.
Fix shadowOffset not being copied when creating a copy of the GState
2011-04-25 10:17:35 -07:00
Randy Luecke 08d33f3c1f Merged pull request #1242 from gorenje/unit_tests_cgcolor.
Some more unit tests for coregraphics - cgcolor and cgcolorspace
2011-04-25 10:16:54 -07:00
Randy Luecke 7d1b873beb Merged pull request #1241 from gorenje/remove_two_color_assumption.
remove an assumption of two colors in the gradient creation stuff
2011-04-25 10:09:33 -07:00
Gerrit Riessen 6c12442870 Fixed copy the shadowOffset, similar to the copying of the affine transform 2011-04-25 14:13:16 +02:00
Gerrit Riessen 6a4d8a24be unit test for CGContext 2011-04-25 14:13:04 +02:00
Gerrit Riessen d147e9cbaa unit test for CGAffineTransform 2011-04-25 14:12:52 +02:00
Randall Luecke 7480f02c22 Merge branch '0.9.1' 2011-04-24 22:29:07 -04:00
Randall Luecke 26afe7c0d8 Fix return type on sortUsingDescriptors in CPMutableArray. 2011-04-24 22:28:41 -04:00
Gerrit Riessen c537541825 added test for color equal to color 2011-04-23 20:56:23 +02:00
Gerrit Riessen e248433ec0 fixed an issue where setting the alpha after creating the color causes all colors referencing that color in the cache to have their alpha value changed 2011-04-23 20:50:42 +02:00
Gerrit Riessen 63e63ce7a1 fix the color creation when using shortcut functions 2011-04-23 17:22:02 +02:00
Gerrit Riessen 6e6011c5ea testing rgb colorspace 2011-04-23 15:50:32 +02:00
Gerrit Riessen 4ce8dcef12 testing cgcolorspace 2011-04-23 15:25:11 +02:00
Gerrit Riessen 7ee414d0b8 remove an assumption of two colors in the gradient creation stuff 2011-04-23 14:10:23 +02:00
Randall Luecke 2c8972514f Merge branch '0.9.1' 2011-04-22 12:59:25 -04:00
Randall Luecke 05b0abacd4 When dragging horizontally we need to update the location of the header view too 2011-04-22 12:59:16 -04:00
Randall Luecke 5315095182 When dragging horizontally we need to update the location of the header view too 2011-04-22 12:53:49 -04:00
Alexander Ljungberg 321c11ec9f Merge branch '0.9.1' 2011-04-21 20:02:22 -04:00
Alexander Ljungberg ca53e56c19 Merge branch '0.9.1' of github.com:280north/cappuccino into 0.9.1 2011-04-21 20:01:53 -04:00
Alexander Ljungberg dcf1d324a5 Additional test for the previous bug. 2011-04-21 19:03:10 -04:00
Alexander Ljungberg 27211db0cc Fixed: JS objects 'randomly' failed to unarchive.
The problem was that if the same JS object was decoded twice as part of a more complex object, the first decoded version was cached in its unwrapped state and not properly unwrapped the second time. This caused very hard to debug theming errors where e.g. a CPTextField's custom inset would decode fine, but a subclass of a CPTextField otherwise exactly the same would fail to decode the inset.
2011-04-21 18:59:30 -04:00
Klaas Pieter Annema 2743fe4c0d Merge branch 'master' of github.com:280north/cappuccino 2011-04-20 21:01:24 +02:00
Klaas Pieter Annema dc5d8f5fd3 never disable menu items with submenus 2011-04-20 21:00:52 +02:00
Randall Luecke be96e3037d Merge branch '0.9.1' 2011-04-20 12:25:41 -04:00
Gerrit RiessenandRandall Luecke b249a1db13 test demostrating limitations of CGGradientCreateWithColorComponents 2011-04-20 12:25:24 -04:00
Randall Luecke f001b7f2d3 Merge branch '0.9.1' 2011-04-20 12:24:32 -04:00
Randall Luecke 561d22168a Stop references function arguments with arguments["name"] in CG. 2011-04-20 12:19:29 -04:00
Klaas Pieter Annema da2c360446 Merge branch '0.9.1' of github.com:280north/cappuccino into 0.9.1 2011-04-20 16:22:28 +02:00
Klaas Pieter Annema 8027ebbe02 Merge branch '0.9.1' 2011-04-20 16:21:59 +02:00
Klaas Pieter Annema 71d8582f94 make unhandled keyboard events travel past the window 2011-04-20 16:21:28 +02:00
Klaas Pieter Annema f8674b6d87 add collectionView:menuForItemAtIndex delegate 2011-04-20 14:40:47 +02:00
Klaas Pieter Annema a086e2fa71 Merge branch '0.9.1' 2011-04-20 11:24:28 +02:00
Klaas Pieter Annema 592328f604 Merge branch 'menu-validation' into 0.9.1 2011-04-20 11:24:17 +02:00
Klaas Pieter Annema 089372be4b Merge branch '0.9.1' 2011-04-20 11:23:58 +02:00
Klaas Pieter Annema ba3a2a9f89 add unit test for CPMenu user interface validation 2011-04-20 11:20:07 +02:00
Klaas Pieter Annema 8e3c26c313 implement CPMenu user interface validation 2011-04-20 10:38:22 +02:00
Klaas Pieter Annema dc264231c8 open menu bar menus directly 2011-04-20 08:58:30 +02:00
Randall Luecke 86e3717222 Fixes for splitview documentation 2011-04-19 01:46:41 -04:00
Alexander Ljungberg c4fb9ccc17 Merge branch '0.9.1' 2011-04-18 20:28:25 -04:00
Alexander Ljungberg 041f2ecf4d Merge branch '0.9.1' of github.com:280north/cappuccino into 0.9.1 2011-04-18 20:16:36 -04:00
Alexander Ljungberg 1db9b6a9d8 Merge branch 'CPTableView-setDropRow_dropOperation-fix' of https://github.com/eventualbuddha/cappuccino into eventualbuddha-CPTableView-setDropRow_dropOperation-fix 2011-04-18 20:13:59 -04:00
Klaas Pieter Annema 3b6bd5a292 take min and max size from item prototype 2011-04-18 10:36:56 +02:00
Francisco Ryan Tolmasky IandKlaas Pieter Annema 51d8fd512a Don't traverse subprojects (folders with Jakefiles).
Reviewed by me.
2011-04-18 10:36:56 +02:00
Francisco Ryan Tolmasky IandKlaas Pieter Annema a578d4881d Don't make IBOutlet a pointer.
Reviewed by me.
2011-04-18 10:36:56 +02:00
Francisco Ryan Tolmasky IandKlaas Pieter Annema 2fb58d3ae1 Always convert to pointers, not just with NS classes.
Reviewed by me.
2011-04-18 10:36:56 +02:00
Francisco Ryan Tolmasky IandKlaas Pieter Annema 35bbb1a3d5 Handle source files being deleted.
Reviewed by me.
2011-04-18 10:36:56 +02:00
Francisco Ryan Tolmasky IandKlaas Pieter Annema d5355df61c Fix superclasses in class generation.
Reviewed by me.
2011-04-18 10:36:56 +02:00
Francisco Ryan Tolmasky IandKlaas Pieter Annema 222223b847 Minor fix.
Reviewed by me.
2011-04-18 10:36:55 +02:00
Francisco Ryan Tolmasky IandKlaas Pieter Annema 9e03df7416 First pass at Xcode 4 support.
Reviewed by me.
2011-04-18 10:36:55 +02:00
Francisco Ryan Tolmasky IandKlaas Pieter Annema 26d124d54b Store type info for ivars when proper flags are set.
Reviewed by me.
2011-04-18 10:36:55 +02:00
Aparajita FishmanandKlaas Pieter Annema 635a0d965c If $CAPP_BUILD is not set or entity is not found in it, look in the narwhal cappuccino package. 2011-04-18 10:36:55 +02:00
Francisco Ryan Tolmasky IandKlaas Pieter Annema c891418849 Change NibApplication template's slider to be continuous since it makes for a better first experience.
Reviewed by me.
2011-04-18 10:36:55 +02:00
Klaas Pieter Annema 39459c9a44 take min and max size from item prototype 2011-04-18 10:34:45 +02:00
Francisco Ryan Tolmasky I 8661625dac Don't traverse subprojects (folders with Jakefiles).
Reviewed by me.
2011-04-15 09:16:25 -07:00
Klaas Pieter Annema 38db22db06 fix a decoding bug with CPBox and it's contentView 2011-04-15 16:01:03 +02:00
Klaas Pieter Annema 722ffeda88 add CPIndexPath to Foundation.j 2011-04-15 16:01:03 +02:00
Klaas Pieter Annema ca74f32e3b fix a decoding bug with CPBox and it's contentView 2011-04-15 16:00:18 +02:00
Klaas Pieter Annema a837b26ac3 add CPIndexPath to Foundation.j 2011-04-15 15:59:59 +02:00
Francisco Ryan Tolmasky I 3b9ed4c1b5 Don't make IBOutlet a pointer.
Reviewed by me.
2011-04-14 14:52:36 -07:00
Francisco Ryan Tolmasky I 77b5f0475d Always convert to pointers, not just with NS classes.
Reviewed by me.
2011-04-14 14:47:14 -07:00
Francisco Ryan Tolmasky I 1c5d311ec2 Handle source files being deleted.
Reviewed by me.
2011-04-14 14:35:29 -07:00
Francisco Ryan Tolmasky I 7d3768e13d Fix superclasses in class generation.
Reviewed by me.
2011-04-14 13:57:24 -07:00
Francisco Ryan Tolmasky I e6acc7a7d8 Minor fix.
Reviewed by me.
2011-04-14 10:27:24 -07:00
Francisco Ryan Tolmasky I 7099acde2f First pass at Xcode 4 support.
Reviewed by me.
2011-04-14 09:49:34 -07:00
Francisco Ryan Tolmasky I 96e3c4db68 Store type info for ivars when proper flags are set.
Reviewed by me.
2011-04-14 09:49:33 -07:00
Alexander Ljungberg 3b35703c2b Merge branch 'master' of github.com:280north/cappuccino 2011-04-14 11:58:05 -04:00
Alexander Ljungberg 1a0b69c10b Merge branch '0.9.1' of github.com:280north/cappuccino into 0.9.1 2011-04-14 11:54:40 -04:00
Alexander Ljungberg 5564b75ed0 Merge branch 'CPArrayController-arrangedObjects-fix-redux' of https://github.com/eventualbuddha/cappuccino into eventualbuddha-CPArrayController-arrangedObjects-fix-redux 2011-04-14 11:52:58 -04:00
Brian Donovan 27cf82e1d3 Use our internal setter while initializing to make sure arrangedObjects is properly observable.
This fixes both the case I reported earlier (#1174) and a new issue I found where attempting to bind to a CPArrayController's arrangedObjects before calling -setContent: would throw this exception:

Uncaught CPInvalidArgumentException: Unsupported method on CPArray

The reason for this exception is that the old implementation set _arrangedObjects to an instance of _CPJavaScriptArray, whereas the new one will set it to a _CPObservableArray.
2011-04-13 21:18:33 -07:00
Aparajita Fishman 025e761929 If $CAPP_BUILD is not set or entity is not found in it, look in the narwhal cappuccino package. 2011-04-13 18:02:08 -04:00
Klaas Pieter Annema 1a99ac7681 Merge branch 'master' of github.com:280north/cappuccino 2011-04-13 17:34:40 +02:00
Francisco Ryan Tolmasky IandKlaas Pieter Annema 1ecbe997df Change NibApplication template's slider to be continuous since it makes for a better first experience.
Reviewed by me.
2011-04-13 17:33:52 +02:00
Klaas Pieter Annema 1d28b120dc fix CPOutlineView providing the dragged items in reverse order 2011-04-13 17:31:29 +02:00
Klaas Pieter Annema 97289d9070 add CPCoding support to CPIndexPath 2011-04-13 17:31:14 +02:00
Klaas Pieter Annema a303b3c04f Merge branch '0.9.1' 2011-04-13 08:27:53 +02:00
Klaas Pieter Annema c317274a26 Merge branch 'purem-master' into 0.9.1 2011-04-13 08:27:45 +02:00
Klaas Pieter Annema 547e57c014 Merge branch 'master' of https://github.com/purem/cappuccino into purem-master 2011-04-13 08:27:23 +02:00
Klaas Pieter Annema 5a1a7f2c86 Merge branch 'purem-master' 2011-04-13 08:24:56 +02:00
Klaas Pieter Annema fb866699e5 Merge branch 'master' of https://github.com/purem/cappuccino into purem-master 2011-04-13 08:24:47 +02:00
Francisco Ryan Tolmasky I cf487ba4de Change NibApplication template's slider to be continuous since it makes for a better first experience.
Reviewed by me.
2011-04-12 09:49:14 -07:00
Brian Donovan f79203f5d5 Fix feedback view when retargeting the drop row & operation.
CPTableView was inappropriately preserving the retargeted drop row & operation as the drag operation continued, causing the data source call to - tableView:validateDrop:proposedRow:proposedDropOperation: to echo any row and operation set by the first call to -setDropRow:dropOperation:, making it impossible for the data source to determine new values for -setDropRow:dropOperation:, making the feedback view stay in the same place it was initially drawn.
2011-04-11 15:00:20 -07:00
purem d7fe42387c Edited bootstrap to find zsh's configuration file ~/.zshrc by default 2011-04-11 11:16:10 -07:00
Alexander Ljungberg ff7f469f9f Fixed: CPColor colorWithCSSString did not properly handle the alpha component of the CSS rbga() syntax. Fixes #687. 2011-04-10 22:16:28 -04:00
Alexander Ljungberg e44ffdc7f4 CPString subtringWithRange: and rangeOfString:options:range now throws CPRangeException for out of bounds ranges. 2011-04-10 21:20:22 -04:00
Alexander Ljungberg 91ef6bf925 Fixed: CPString rangeOfString:options:range returned locations relative to the passed-in range instead of the full string. 2011-04-10 21:05:43 -04:00
Alexander Ljungberg a33dd51d8e Fixed: searching a string for @"" with CPString rangeOfString returned results other than CPNotFound. 2011-04-10 20:38:51 -04:00
Alexander Ljungberg 2166fc1d51 Fixed: CPString rangeOfString: anchored backwards search did not work. 2011-04-10 20:19:04 -04:00
Alexander Ljungberg b29e722132 Fixed: CPString rangeOfString: backwards search did not work. Fixes #1065. 2011-04-10 20:12:33 -04:00
Alexander Ljungberg 06122bba19 Test CPString rangeOfString: in CPCaseInsensitiveSearch | CPBackwardsSearch mode. 2011-04-10 20:10:08 -04:00
Alexander Ljungberg b40f920ec6 Fixed: don't crash on the first mouse move event after merge #1211. Fixes #1221. 2011-04-10 18:33:57 -04:00
Alexander Ljungberg e327c39776 Code formatting. 2011-04-10 17:26:22 -04:00
Alexander Ljungberg c7a1717ebe Added CPDate test which catches mishandling of timezones in initWithString.
(Unfortunately the test is rather crude and only works when your current timezone offset is not 0 (UTC).)
2011-04-10 17:24:18 -04:00
Randall Luecke b9533386b4 Merge branch 'natemartinsf-master' into 0.9.1 2011-04-08 09:32:14 -04:00
Mike FellowsandRandall Luecke 69d27364d5 Trivial fix, add missing spinner.gif from manual scroll view test 2011-04-08 09:30:56 -04:00
Aparajita FishmanandRandall Luecke e3abd4e407 Fixed timezone calculation in initWithString. 2011-04-08 09:29:45 -04:00
Mike FellowsandRandall Luecke 2f501ad736 Add a manual test for drag and drop in a CPTableView 2011-04-08 09:28:30 -04:00
Randall Luecke ae5359f953 Merge branch '0.9.1' of git://github.com/280north/cappuccino into 0.9.1 2011-04-08 09:26:55 -04:00
Mike FellowsandRandall Luecke 4a57f6a1c4 Better inset bounds to improve autoscrolling while dragging in a scrollview. 2011-04-08 09:26:04 -04:00
Nathaniel Martin 9b1eac1923 deltaX and deltaY now set on mousemoved, based on last mouse event 2011-04-07 22:00:09 -07:00
Nathaniel Martin 875dbaa78f Fix for issue 1210 2011-04-06 23:16:13 -07:00
Klaas Pieter Annema 6b64291690 Merge branch 'aparajita-nib2cib-man' 2011-04-06 11:55:17 +02:00
Aparajita Fishman 52ce4c1ebf Properly documented the -F option, some formatting tweaks 2011-04-06 05:15:52 -04:00
Aparajita Fishman a7161e3ca7 Changed comparison in initial check to <=, a cib with an equal mtime could not have been converted from an IB file, it would have a later mtime. 2011-04-06 04:40:05 -04:00
Aparajita Fishman 73746e00b0 Fixes and enhancements...
- If an IB file is deleted, the corresponding cib is no longer deleted.
- In watch mode, the first time through no conversion is done if an IB file has a corresponding cib file with a later mtime.
- In watch mode, an add does not convert if there is a corresponding cib file with a later mtime.
- When catching exceptions, deal correctly with both CPException and strings.
2011-04-06 04:34:56 -04:00
Klaas Pieter Annema 327d796653 implement outlineViewDeleteKeyPressed 2011-04-06 08:14:29 +02:00
Aparajita Fishman af6d38fd16 Fixes and enhancements
- When a xib/nib is deleted, the corresponding cib is deleted.
- Fixed the calculation of the output path when given a relative path.
- Works with .nib files now.
- Works with -R option now. NSCustomResource was assuming an image path would always be relative to cwd().
- The Resources directory is always inferred from the input path, so the -R option is usually unnecessary.
- Added --default-theme option.
- Multiple extra themes can be specified with the --theme option.
- Verbose mode displays the inferred application and resources paths, and the source theme used when doing font substitutions.
- Added a man page.
- Themes are read using StaticResource instead of parsing the file myself.
- Error message tweaks.
2011-04-05 16:57:16 -04:00
Klaas Pieter Annema ab105e7273 Merge branch 'capp-man' of https://github.com/aparajita/cappuccino into aparajita-capp-man 2011-04-05 13:53:02 +02:00
Alexander Ljungberg 6115acea05 Merge branch '0.9.1' 2011-04-04 23:58:13 -04:00
Alexander Ljungberg 0d8bd95c86 Fixed: systems without xcodebuild would fail jake clean and jake clobber. 2011-04-04 23:56:30 -04:00
Klaas Pieter Annema 40bfb55b64 don't resolve nib2cib output path 2011-04-04 14:23:36 +02:00
Alexander Ljungberg f0bba44e45 Completed CPTabView documentation. 2011-04-03 17:56:31 -04:00
Alexander Ljungberg 7107adfe16 Minor doc formatting. 2011-04-03 17:45:53 -04:00
Alexander Ljungberg 501c15775e Use bsdtar explicitly for 'jake docs' in case the user has GNU tar installed through e.g. fink.
This enables the -s parameter to work.
2011-04-03 16:58:39 -04:00
Alexander Ljungberg f29dcc9c6b Document CPScreen. 2011-04-03 16:12:27 -04:00
Alexander Ljungberg 370960418f Better formatting, clickable links and basic code styling for the Doxygen docs front page. This look will resemble that of the GitHub front page.
The README file was converted to Markdown which is nice to read in the terminal and automatically formatted by GitHub. For Doxygen, the markdown is first converted to HTML.
2011-04-03 14:34:20 -04:00
Aparajita Fishman c9fb862ee2 Tweak 2011-04-03 07:56:16 -04:00
Antoine Mercadal 6e1acf1f06 fix wrong AGPL header in CPUserDefaultTest.j 2011-04-03 11:41:56 +02:00
Alexander Ljungberg 2952070698 Whitespace, comment tweak. 2011-04-03 00:56:28 -04:00
Alexander Ljungberg dbb10f69f6 Merge branch 'aparajita-fonts' into 0.9.1 2011-04-02 23:32:59 -04:00
Alexander Ljungberg 9fc10260fb Merge branch 'fonts' of https://github.com/aparajita/cappuccino into aparajita-fonts 2011-04-02 22:26:21 -04:00
Alexander Ljungberg 2fbd54521d Fix up and restore all functionality to ArrayController manual test. 2011-04-02 20:08:36 -04:00
Alexander Ljungberg ae3780c0cf Recreated and cleaned up ArrayController1 since MainMenu.xib was missing. 2011-04-02 19:43:51 -04:00
Alexander Ljungberg ccf9225773 Minor KVO optimisation. 2011-04-02 18:10:13 -04:00
Alexander Ljungberg 8aaa5fe07f Test array controller KVC binding correctness.
This change splits the insertObjectAtArrangedObjectIndex:, addObject:, and removeObject: tests into two versions: one for a regular AC setContent: setup and one for when the AC is bound to an array-like destination implementing KVC.
2011-04-02 18:09:16 -04:00
Alexander Ljungberg fa1a10730e Fixed: an array controller with a bound contentArray would sometimes fail when add:, remove: and similar methods were called.
In particular the AC would fail when a _CPKeyValueCodingArray proxy was required (the destination implements insertObject:in<key>AtIndex etc.). The previous commit by cacaodev is the larger part of this fix as it enables use of mutableArrayValueForKeyPath properly. This commit merely fixes an error exposed by the previous commit where e.g. add: would apparently add two objects rather than one. This was caused by the AC observing and reacting to its own change even that it already had an optimised path to update arrangedObjects.
2011-04-02 18:03:21 -04:00
cacaodevandAlexander Ljungberg e91bc3eeef Adds a binder subclass for CPArrayController's contentArray binding. This binder allows destination.keypath who are kvc compliant, still works if they're not (through _CPKVCArray). Fixes addObject: error when contentArray is bound to a kvc array, a bug visible in ArrayController1 manual test. 2011-04-01 21:29:37 -04:00
Alexander Ljungberg 76400ecca9 Make table column internal bindings support methods private. 2011-03-31 20:48:51 -04:00
Alexander Ljungberg 9a0cf2b37d Manual test for bindings based table view editing. 2011-03-31 20:35:11 -04:00
Alexander Ljungberg dae36cda56 Bindings support for inline table view cell editing. 2011-03-31 20:26:56 -04:00
Aparajita Fishman e07ff706ab Fixed stupid bug in figuring out what directory to watch 2011-03-31 20:10:18 -04:00
Aparajita Fishman 7ec31a7c53 If no directory is passed to --watch, default to Resources 2011-03-31 19:51:22 -04:00
Aparajita Fishman b4221aebcb fontinfo binary is built directly in $CAPP_BUILD, and intermediate build products are put there also. 2011-03-31 16:43:58 -04:00
Aparajita Fishman fdcd56e0ae Added a man page for capp, global function for copying a man page 2011-03-31 14:52:38 -04:00
Alexander Ljungberg 2532c760ea Closes #1202. Test that CPEvent deltaX, deltaY and deltaZ do work. Also initialise deltas to 0 instead of nil. 2011-03-31 11:11:57 -04:00
Aparajita Fishman 0f68fa0141 Added ability to pass a string and get its width, removed some unnecessary releases 2011-03-30 00:28:45 -04:00
Aparajita Fishman 26fba1fdd9 Remove bogus line, not sure how it got there 2011-03-29 17:44:34 -04:00
Aparajita Fishman 16bacae7e3 More cool stuff...
- The holy grail! I took Klaas' great autonib2cib and rolled it into nib2cib.
- Removed check for stream in CPLogColorize, it isn't necessary and reduces its general-purpose usage.
2011-03-29 16:06:19 -04:00
Aparajita Fishman d00a8b9d18 Use a parser action to show version and quit 2011-03-29 12:54:54 -04:00
Alexander Ljungberg 094b798765 Fixed: when table view grid lines were active they did not draw on top of selection highlights like in Cocoa. 2011-03-29 00:45:25 -04:00
Alexander Ljungberg 89974796b1 Fixed: table view's rectOfColumn: method returned a rect reduced by the intercell spacing. It should return the rect of the entire column. Fixed: when a column was selected the column selection colour would not cover the whole column. Fixed: in recent builds, table view header divider lines did not line up with body divider lines.
Ultimately, intercell spacing is only applied, as the name implies, inside of cells. It is not applied in the header, nor at the column or row level. Only data views inside of cells are offset.
2011-03-29 00:33:32 -04:00
Aparajita Fishman 90c19b1856 Added explicit size for completeness of sample, fixed font substitution if theme has no font, used LucidaGrande-Bold 13 to do better code coverage. 2011-03-28 23:55:31 -04:00
Aparajita Fishman 044a605e47 Added font methods so that nib2cib can do font substitution 2011-03-28 23:51:45 -04:00
Aparajita Fishman 7d62b6e1eb Made the defaults global constants 2011-03-28 23:50:56 -04:00
Aparajita Fishman 93f36a2326 Added missing license, added a lot more support for radio button attributes, included fix for issue #1190 2011-03-28 22:44:03 -04:00
Aparajita Fishman 0218246678 Added key equivalents to radio buttons, more attributes to test new radio button support 2011-03-28 22:42:46 -04:00
Aparajita Fishman 79fde3fbeb Factored out font substitution code, added special case for radio buttons 2011-03-28 22:38:26 -04:00
Alexander Ljungberg 539ea2e589 Merge branch '0.9.1' of github.com:280north/cappuccino into 0.9.1 2011-03-28 22:14:32 -04:00
Alexander Ljungberg 4f6d939634 Minor table view cleanup. 2011-03-28 22:14:11 -04:00
Alexander Ljungberg d68d84cfdf Merge branch '0.9.1' of github.com:280north/cappuccino into 0.9.1 2011-03-28 21:24:45 -04:00
Alexander Ljungberg 1ef7fc45f5 Added a note to the CPContinuouslyUpdates test clarifying the purpose of the sliders. 2011-03-28 21:23:53 -04:00
Alexander Ljungberg 430a74735b Fixed: CPSliders always became continuous when archived/unarchived through CPCoding. 2011-03-28 21:18:47 -04:00
Randall Luecke de08addfa1 Fix for grid lines not being drawn in the headers of table columns which were not originally exposed. 2011-03-28 21:10:59 -04:00
Alexander Ljungberg 26003365bc Fixed: CPSlider isContinuous disagreed with setContinuous. 2011-03-28 21:06:07 -04:00
Alexander Ljungberg 11ab9a77ad Minor performance improvement to CPContinuouslyUpdatesValueBindingOption. 2011-03-28 20:12:32 -04:00
Aparajita Fishman 52f3f81265 Changed window title 2011-03-28 18:59:03 -04:00
Aparajita Fishman 2599f820c7 Merge branch 'font-fun' into fonts
Conflicts:
	Tools/nib2cib/NSButton.j
2011-03-28 18:51:10 -04:00
Aparajita Fishman 8fed2c7a9a Factored code into functions, fixed input and output path computation 2011-03-28 18:45:03 -04:00
Alexander Ljungberg f9f03c8b54 Manual test for CPContinuouslyUpdatesValueBindingOption and CPNullPlaceholderBindingOption. 2011-03-28 18:23:17 -04:00
Alexander Ljungberg 110d75b1e5 Text field support for CPContinuouslyUpdatesValueBindingOption. 2011-03-28 18:20:19 -04:00
Alexander Ljungberg 79ec12e2a2 Added support for the CPNullPlaceholderBindingOption for bound text fields. 2011-03-28 18:02:52 -04:00
Aparajita Fishman 5133a7dc91 Fix NSButton so it will merge with master 2011-03-28 16:28:28 -04:00
Klaas Pieter Annema 425401c049 Merge branch 'keyview' of https://github.com/aparajita/cappuccino into aparajita-keyview 2011-03-28 20:12:45 +02:00
Klaas Pieter Annema 38f896d018 fix CPURL equality check 2011-03-28 18:56:25 +02:00
Alexander Ljungberg 7b3ae56031 CPObjectController automaticallyPreparesContent support. 2011-03-28 11:06:12 -04:00
Klaas Pieter Annema 4418b2403f add test case for firstObject 2011-03-28 15:23:03 +02:00
Klaas Pieter Annema 42c60913c6 add firstObject method to CPArray 2011-03-28 13:14:25 +02:00
Alexander Ljungberg 65ce93ce42 Merge branch '0.9.1' of github.com:280north/cappuccino into 0.9.1 2011-03-27 18:18:30 -04:00
Alexander Ljungberg 651882b3c8 Merge branch 'aparajita-keyEquivalent' into 0.9.1 2011-03-27 18:18:07 -04:00
Aparajita Fishman ac7ff24dd7 These got left out in f1f78d6c6a 2011-03-27 15:22:13 -04:00
Aparajita Fishman b54ea6e8ac Ignore Xcode project user data, added fontinfo package 2011-03-25 23:38:49 -04:00
Randall Luecke cf6d7f2d85 Rev version number to 0.9.1 2011-03-25 23:36:07 -04:00
Alexander Ljungberg 65043c5d78 Added some missing LGPL headers. 2011-03-25 22:52:57 -04:00
Aparajita Fishman 30484e04b9 Moved some useful functions to common.jake and made some private functions global so they can be reused by our Jakefiles 2011-03-25 18:51:37 -04:00
Aparajita Fishman 4decc6d9c7 Use a relative path in the symlink 2011-03-25 18:47:41 -04:00
Aparajita Fishman 1a5b8f5210 Fixed install-symlinks to actually work, added sudo-install-symlinks 2011-03-25 18:47:24 -04:00
Aparajita Fishman 93119233cd Prevent self-reference in _next/_previousKeyView 2011-03-25 14:45:19 -04:00
Alexander Ljungberg 2f56f899cf Merge branch 'master' of https://github.com/eventualbuddha/cappuccino into eventualbuddha-master 2011-03-25 12:53:42 -04:00
Brian Donovan b69c25bc2a Fix documentation typo. 2011-03-25 08:50:06 -07:00
Alexander Ljungberg bdcf84ec15 Merge branch '0.9.1' of github.com:280north/cappuccino into 0.9.1 2011-03-25 00:43:36 -04:00
Aparajita FishmanandRandall Luecke f1f78d6c6a Fixed the infamous "wandering checkbox" bug 2011-03-24 23:39:25 -04:00
Randall Luecke 83e4e7ecce Merge branch 'jake-install-symlinks' of https://github.com/aparajita/cappuccino into aparajita-jake-install-symlinks 2011-03-24 23:38:45 -04:00
Alexander Ljungberg e6eb14e819 Fixed: in Firefox, certain web views would not send the first webView:didFinishLoadForFrame: delegate message nor detect the need for AppKit scrollbars. 2011-03-24 23:33:44 -04:00
Alexander Ljungberg 380a860ba9 Fixed: loading an empty string into a web view would make it entirely white regardless of the background colour specified. 2011-03-24 21:20:55 -04:00
Alexander Ljungberg 5cbbafdf72 Support for web views with transparent or coloured backgrounds. 2011-03-24 21:13:41 -04:00
cacaodev 4b9695ff50 cache respondsToSelector: ; Fire the timer only if both methods exists 2011-03-24 18:40:25 +01:00
Klaas Pieter Annema 863c4639cf implement outline view menu delegate method 2011-03-24 14:56:23 +01:00
Alexander Ljungberg 79e977b2d9 CPWebView isLoading method. 2011-03-24 01:03:02 -04:00
Alexander Ljungberg 93fe320e22 Minor fixes and cleanup. 2011-03-24 00:56:35 -04:00
Alexander Ljungberg 0337744c05 Web view accessor method to check which scrollbar style is currently in use. Also documented CPWebViewScrollNone. 2011-03-24 00:43:23 -04:00
Alexander Ljungberg 43f4ecc1b4 More consistent CPCompatibility constant naming. 2011-03-23 23:54:56 -04:00
Alexander Ljungberg 310d49c74c Merge branch 'master' of github.com:280north/cappuccino 2011-03-24 00:35:26 -04:00
Alexander Ljungberg 3bd2c2d266 Fixed: web view loadHTMLString:"" now works again. Incidentally it only used to work by accident. 2011-03-24 00:33:54 -04:00
Alexander Ljungberg b9d2927368 Fixed: web views with CPWebViewScrollAuto would reload after determining which scrollbars to use. The new solution makes a best effort attempt to determine this ahead of loading, avoiding reloads.
The problem in particular is that we can't change from AppKit to Native scrollbars or vice versa once an iframe has been loaded. Until we find a way to do so, this less flexible solution will have to do. Note that if the loaded URL passes the SOP, but the content contains links to URLs which do not pass the SOP which can be brought up in the web view, CPWebViewScrollAuto will not work correctly and CPWebViewScrollNative should be used instead.
2011-03-24 00:14:06 -04:00
Randall Luecke 8737b1207f Fix for corner view not drawing the line above the left edge of the scrollview. closes #864 2011-03-23 23:02:10 -04:00
Aparajita FishmanandRandall Luecke 7b6713aa90 Better error checking, error messages, and help. 2011-03-23 21:47:02 -04:00
Aparajita FishmanandRandall Luecke ea25d22628 Cocoa docs state that if unarchiver:didDecodeObject: returns nil, the original object should be used, no replacement should be done. 2011-03-23 21:45:53 -04:00
Randall Luecke d54db1d52b Merge branch 'CPScanner' of https://github.com/cacaodev/cappuccino into cacaodev-CPScanner
Conflicts:
	Foundation/CPScanner.j
2011-03-23 21:43:43 -04:00
Randall Luecke 9746e3d554 More fixes for the splitview. 2011-03-23 13:26:38 -04:00
Aparajita Fishman 6afc5faab0 Moved some useful functions to common.jake and made some private functions global so they can be reused by our Jakefiles 2011-03-23 12:18:11 -04:00
Aparajita Fishman 2899389561 Use a relative path in the symlink 2011-03-23 11:17:01 -04:00
Aparajita Fishman a1e9322d69 Fixed install-symlinks to actually work, added sudo-install-symlinks 2011-03-23 10:54:47 -04:00
Alexander Ljungberg da0558f09c Fixed: avoid momentarily showing native scrollbars while loading URL based content of a CPWebViewScrollAuto CPWebView. 2011-03-22 19:00:54 -04:00
Alexander Ljungberg 8879ef99c6 Fixed: [CPWebView reload] did nothing if the content was an HTML string. 2011-03-22 18:37:45 -04:00
Alexander Ljungberg 09d515e6cc Reload buttons for CPWebViewTest. 2011-03-22 18:37:34 -04:00
Randall Luecke 014354432a Merge branch 'master' of git://github.com/280north/cappuccino 2011-03-22 13:44:48 -04:00
Randall Luecke d9b327db83 Fix for splitview not repositioning subviews or removing divider when a subview is removed. 2011-03-22 13:43:42 -04:00
Gerrit RiessenandFrancisco Ryan Tolmasky I da0b0d6c84 Fix for root layer transform inadvertantly changing when redisplayed.
Reviewed by tolmasky.
2011-03-22 12:34:23 -03:00
Randall Luecke 3f271463e5 Better CPWindowController docs. 2011-03-22 02:29:45 -04:00
Randall Luecke 459240bb88 Fix for scroller error when horizontal scroller is too small. 2011-03-19 22:51:45 -04:00
cacaodev a02b721944 CPScrollView: add -scrollView(Will|Did)Change: delegate methods.
CPScroller: send action when dragging starts instead of immediately on mouse down.

Test: added delegate methods to the top-left scroll view in CPScrollView example and log.
2011-03-19 10:17:12 +01:00
Randall Luecke e8210f7dde Proper fix for mem leakage. 2011-03-17 03:03:51 -04:00
Randall Luecke 32fc629c33 Prevent memory leak my only adding the observer when the searchfield is added to a superview, that way we can also remove the observer later. 2011-03-17 01:31:25 -04:00
cacaodevandRandall Luecke d5b2ccbc30 CPSearchField: register for textDidChange notifications instead of hijacking the delegate. Post the notification in -canCelOperation: (triggered by escape key OR cancel button). Fixes issue #1160 2011-03-17 01:18:25 -04:00
Aparajita FishmanandRandall Luecke a3e70a56c5 Added support for sendsActionOnEndEditing flag in nibs 2011-03-17 01:16:43 -04:00
Brian Donovan abce41d6fd Make sure -[CPArrayController arrangedObjects] always has a non-nil value. 2011-03-15 19:53:14 -07:00
Randall Luecke e1d45fd385 Merge branch 'master' of git://github.com/280north/cappuccino 2011-03-15 18:03:24 -04:00
Randall Luecke a3e6105a11 Fix for errors with variable row height edge cases. 2011-03-15 18:02:26 -04:00
Klaas Pieter Annema f022386502 Merge branch 'doc-optimize' of https://github.com/aparajita/cappuccino into aparajita-doc-optimize 2011-03-15 10:18:06 +01:00
Aparajita Fishman e18b21ec1b Fixed output path check 2011-03-13 10:15:26 -04:00
Aparajita Fishman 42c71172f2 Better path checking and error messages, fixed issue #1154 2011-03-13 10:08:17 -04:00
Aparajita Fishman dc801a11c8 Instead of blindly, recursively copying the AppKit and Foundation directories, more intelligently copy only the *.j files we want. 2011-03-12 23:34:53 -05:00
Randall Luecke 24fbf27880 Headerview and corner view fixes 2011-03-12 01:24:15 -05:00
Aparajita Fishman b0af42e236 Removed extra blank line 2011-03-11 12:39:54 -05:00
Aparajita Fishman 32fd03b4a0 Explicitly test for null cibFont for clarity 2011-03-11 12:15:58 -05:00
Aparajita Fishman 6b72651a05 Error message tweaks 2011-03-11 12:00:58 -05:00
Aparajita Fishman d6117b832f Comment tweaks 2011-03-11 09:46:42 -05:00
Aparajita Fishman 3a79e82ce8 Removed check for fontinfo, it will be part of the cappuccino package 2011-03-11 09:04:11 -05:00
Aparajita Fishman 522d4dcb2b Removed layout constants 2011-03-11 08:39:41 -05:00
Aparajita Fishman 11f92353c8 Removed layoutMode references 2011-03-11 08:37:23 -05:00
Aparajita Fishman 3b60714bf0 Documented how to configure the system font face. 2011-03-10 19:54:38 -05:00
Aparajita Fishman 239b6ed79d Fixed CPFontTest, removed unused RegExp from CPFont 2011-03-10 19:19:32 -05:00
Aparajita Fishman a20b0a7dca Removed google fonts, added test of dynamically set font with fallback 2011-03-10 18:53:57 -05:00
Randall Luecke e9dba10903 Move coder unarchiving logic to nib2cib. 2011-03-10 18:37:44 -05:00
Aparajita Fishman fd43a08fa3 Merge remote branch 'refs/remotes/280north/master' into font-fun 2011-03-10 18:18:18 -05:00
Aparajita Fishman 627566465e Moved legacy font substitution to nib2cib to avoid any side effects, linted NSTableColumn, NSTableColumn now uses cibFontForNibFont, finished test app 2011-03-10 18:13:35 -05:00
Randall Luecke b087757a72 Pump runloop for async callbacks. 2011-03-10 17:39:39 -05:00
Randall Luecke d926ad6221 Merge branch 'fix-cpsound-firefox' of https://github.com/primalmotion/cappuccino into primalmotion-fix-cpsound-firefox 2011-03-10 17:11:19 -05:00
Aparajita FishmanandRandall Luecke 90e6c21c95 Be sure the build directory exists in case 'jake docs' is done before any other jake commands 2011-03-10 17:05:40 -05:00
Randall Luecke ad4d408f3e Merge branch 'pattern-fill' of https://github.com/aparajita/cappuccino into aparajita-pattern-fill 2011-03-10 17:04:26 -05:00
Aparajita FishmanandRandall Luecke 9a2d079bee lint the template files, update setFullBridge (deprecated) to setFullPlatformWindow 2011-03-10 17:03:38 -05:00
Aparajita FishmanandRandall Luecke f254122346 Added CPView -hasThemeAttribute and tests 2011-03-10 17:02:30 -05:00
Aparajita Fishman 10bfeaf8f7 Added comment for non-obvious code, fixed option name in nib2cib 2011-03-10 12:49:50 -05:00
Aparajita Fishman f93aa2c5bc Merge branch 'master' of https://github.com/280north/cappuccino into font-fun 2011-03-10 12:38:37 -05:00
Francisco Ryan Tolmasky I acf7ef3a96 Use 10.5 SDK for building NativeHost if available, otherwise use latest Mac OS X SDK.
Reviewed by me.
2011-03-10 12:33:35 -04:00
Aparajita Fishman a8d07961c0 -familyName should always return whatever family names the font was initialized with, in case there are fallbacks for different platforms 2011-03-10 11:28:48 -05:00
Aparajita Fishman 95cc88733c Fixed default system font substitution 2011-03-09 16:37:23 -05:00
Aparajita Fishman 120c06fcb2 Further CPFont work, don't print nib2cib version all the time. 2011-03-09 14:33:11 -05:00
Aparajita Fishman d303e6e96c Initial commit before testing. 2011-03-08 17:40:41 -05:00
Aparajita Fishman c4dce38484 Added support for pattern fills in CGContext, fixed bug in COORD macro in CGContextVML.j, test app 2011-03-08 03:11:08 -05:00
Ross Boucher 8eb8b7711d Binding to wrong event in IE. 2011-03-07 15:08:57 -08:00
Alexander Ljungberg f7fc669216 Fix missing 'self' in previous commit. 2011-03-06 11:51:20 -03:00
Alexander Ljungberg 7d6b7fd676 CPCoding fix, remove a log statement. 2011-03-05 22:56:49 -03:00
Alexander Ljungberg 2387cee799 Fixed: web view AppKit scrollbars often did not reflect the true content size of the view.
The reason for this is that the size changes as the page progressively loads, and this continues after the 'load' event fired. For now, we use a simple timer to poll the size a few times after loading. These polls are very bad for performance and battery life so we terminate them quickly, meaning that the underlying problem where the contents of the web view can get out of sync with its scrollbars fundamentally remains - this fix merely alleviates the problem.
2011-03-05 22:50:20 -03:00
Alexander Ljungberg e214d49ea9 Change SOP error to a warning. Warn about problematic testing setup in CPWebViewTest. 2011-03-05 19:52:39 -03:00
Alexander Ljungberg 6f8d2190f5 Closes #1136. Fixed: for the most part, web view's setScrollMode: message did nothing. New: automatic or explicit scroll mode selection in web views.
By default the automatic mode will try to use Cappuccino scrollbars whenever possible, and otherwise fall back on Native scrollbars. Explicit settings are also allowed. The explicit AppKit setting will degrade to Native with a warning if impossible due to implement due to SOP.
2011-03-05 19:45:39 -03:00
Alexander Ljungberg 9ca1865179 Test the various web view scroll modes about to be implemented. 2011-03-05 18:00:17 -03:00
Randall Luecke a7c5ca740a Typo in doc changes 2011-03-05 00:20:28 -05:00
Randall Luecke 590b3705eb Style changes for table column documentation. 2011-03-04 23:15:24 -05:00
Klaas Pieter Annema a9f23fe082 open submenus after a short delay 2011-03-04 10:21:26 +01:00
Klaas Pieter Annema 3c77d43e03 implement mousewheel support for CPMenu 2011-03-04 10:21:26 +01:00
Klaas Pieter Annema 7fb78fe157 lint _CPMenuWindow 2011-03-04 10:21:26 +01:00
Klaas Pieter Annema 566fdf6400 lint _CPMenuManager.j 2011-03-04 10:21:25 +01:00
Klaas Pieter Annema 1dc53ed149 lint CPPlatformWindow+DOM.j 2011-03-04 10:20:55 +01:00
Klaas Pieter Annema b57b705b1d place the scroll element above menus 2011-03-04 10:20:54 +01:00
Blair DuncanandKlaas Pieter Annema 7d7c037682 add support for Home and End key and modified logic for pageUp and pageDown 2011-03-04 10:20:54 +01:00
Blair DuncanandKlaas Pieter Annema bf72a7f92d added support for escape key to cancel menus, removed unused var 2011-03-04 10:20:54 +01:00
Blair DuncanandKlaas Pieter Annema df9387fc78 remove unneccessary scrolling calls and periodic events when not needed 2011-03-04 10:20:54 +01:00
Blair DuncanandKlaas Pieter Annema 9296df89df fixed some spacing and added a delay in the reset time for longer lists 2011-03-04 10:19:35 +01:00
Blair DuncanandKlaas Pieter Annema d4d65ed4d7 Add support for keyboard navigation in menus 2011-03-04 10:19:35 +01:00
Klaas Pieter Annema 163550c3d5 determine NSControl enabled state from NSCellFlags 2011-03-04 08:56:25 +01:00
Klaas Pieter Annema a11f12ab09 fix unarchiving tableviews with no header view 2011-03-04 08:51:21 +01:00
Klaas Pieter Annema 8e14d6cebc unarchive corner and headerviews correctly 2011-03-04 08:15:54 +01:00
Randall Luecke 90d50bb593 Sizing fixes for the textfields of the color panel. 2011-03-02 22:51:03 -05:00
cacaodevandRoss Boucher b715fb6182 Enable representedObject decoding in NSMenuItem.j 2011-03-02 13:32:56 -08:00
Ross Boucher 31dbd208f4 We don't need to copy the string since strings are immutable in javascript. 2011-03-02 13:26:49 -08:00
Tobias M. BölzandRoss Boucher 49707af1ba Fixed binding name constants 2011-03-02 13:17:44 -08:00
Ross Boucher b77668dd5a Fix spacing in CPBrowser. 2011-03-02 12:36:44 -08:00
Alexander Ljungberg 50e5fa2c8e Fix accidental globals. 2011-03-01 00:02:35 -03:00
Alexander Ljungberg dedf3cd90f More AppKit coding standards. 2011-02-28 23:55:29 -03:00
Alexander Ljungberg 651d6a7ed8 Linting AppKit. 2011-02-28 23:48:34 -03:00
meelash 383dcd5ee6 Corrected mistake in CPSplitView delegate documentation 2011-02-28 20:19:00 -05:00
Francisco Ryan Tolmasky I 1589d501cc Slight typo.
Reviewed by me.
2011-02-27 10:01:16 -08:00
Randall Luecke 060563b748 Documentation style fixes for CPOutlineView. Now setDelegate: actually shows up. 2011-02-26 15:13:34 -05:00
Randall Luecke b8b74f1e35 Revert "Crazy cool selection behavior."
This reverts commit 2b498feb67.
2011-02-26 14:58:47 -05:00
Ross Boucher 6435372fd9 We weren't actually keeping track of replaced methods, and thus were replacing every time you call addObserver: 2011-02-25 17:59:54 -08:00
Klaas Pieter Annema 3ebb432d3f Merge branch 'traceback' of https://github.com/jukart/cappuccino 2011-02-25 23:57:29 +01:00
Klaas Pieter Annema f13362b224 fix sortDescriptorsDidChange: not called for outline view 2011-02-25 23:52:41 +01:00
Derek HammerandKlaas Pieter Annema 2b498feb67 Crazy cool selection behavior. 2011-02-25 23:52:41 +01:00
Randall Luecke 5c6fce4e8c Following the fix for the pane spiltter flag change in the CPSplitView, the theme file also needed to be updated. 2011-02-24 01:48:36 -05:00
Randall Luecke d000e67fc4 Merge branch 'master' of https://github.com/dbrajkovic/cappuccino into dbrajkovic-master 2011-02-24 01:28:14 -05:00
Randall Luecke c9bc6c3991 Fix for Xcode 4.0 pre-release causing cappuccino not to build because of NativeHost. This is just a work around for the time being so that Cappuccino still finishes building. 2011-02-24 01:25:11 -05:00
Randall Luecke 8c1a3a3bba Refactored the tableview docs a little. Now using real doxygen commands instead of using <pre> on everything. 2011-02-23 02:46:30 -05:00
Randall Luecke f723318601 Column resize fixes 2011-02-22 22:07:31 -05:00
Randall Luecke ebcbfc76b8 Merge branch 'fix-searchfield-glitch' of https://github.com/primalmotion/cappuccino into primalmotion-fix-searchfield-glitch 2011-02-22 21:11:53 -05:00
Randall Luecke eaa4efc805 Imageview support for tableview nib2cib 2011-02-22 21:08:30 -05:00
Randall Luecke e717fd82b9 Merge branch 'Selection' of https://github.com/hammerdr/cappuccino into tableview-selection
Conflicts:
	AppKit/CPTableView.j
2011-02-22 20:05:00 -05:00
Randall Luecke 46781cb6fd Merge branch 'mb-cpcursor-refactor' of https://github.com/saikat/cappuccino into saikat-mb-cpcursor-refactor 2011-02-22 19:58:31 -05:00
Randall Luecke 02eaded719 Merge branch 'UniformColumnSizing' of https://github.com/hammerdr/cappuccino into hammerdr-UniformColumnSizing 2011-02-22 19:54:14 -05:00
Randall Luecke 0748190ab7 Merge branch 'bootstrap-fixes' of https://github.com/paulbaumgart/cappuccino into paulbaumgart-bootstrap-fixes 2011-02-22 19:53:08 -05:00
Randall Luecke cccbb8eee4 Merge branch 'master' of https://github.com/purem/cappuccino into purem-master 2011-02-22 19:51:51 -05:00
Randall Luecke 902878756e Merge branch 'fix-progressindicator-not-cpcoding-compliant' of https://github.com/primalmotion/cappuccino into primalmotion-fix-progressindicator-not-cpcoding-compliant 2011-02-22 19:51:07 -05:00
Randall Luecke 033663f2cf fix for a couple methods not being generated for the docs. 2011-02-22 19:48:53 -05:00
Ross Boucher e4093ac3ae Merge branch '0.9' 2011-02-22 14:13:12 -08:00
Ross Boucher 16a70c5c8e Update to the starter package readme. 2011-02-22 14:09:09 -08:00
Jürgen Kartnaller b7f871e31b Merge branch 'master' into traceback 2011-02-21 14:38:49 +01:00
Klaas Pieter Annema cc5e8c3f34 fix textfield cut and paste notifications
Closes #555 #1001
2011-02-21 10:26:58 +01:00
Klaas Pieter Annema 85e80a62a3 remove old '_currentValueIsPlaceholder' code 2011-02-21 10:26:58 +01:00
Antoine Mercadal 60d1073d9a do not encode _barView 2011-02-16 17:39:06 +01:00
Antoine Mercadal b620de45a2 make CPProgressIndicator CPCodingCompliant 2011-02-16 17:34:26 +01:00
purem 536d012105 Fixed typo 2011-02-13 15:01:59 -08:00
Jürgen Kartnaller 2e24761a54 Merge branch 'master' into traceback 2011-02-09 10:30:12 +01:00
Daniel Brajkovic 956b640339 Fixes #1122. Nib2Cib was checking if NSSplitViewDividerStyle ==2 should be == 3 as NSSplitViewDividerStylePaneSplitter = 3.
In CPSplitView.j the divider thicknesses in the themeAttributes were swapped. Also swapped the statements in _setupDOMDivider if(_isPaneSplitter) statement.
2011-02-07 23:59:43 -06:00
Paul Baumgart bee1db8c7d Optionally add CAPP_BUILD to the shell config automatically. 2011-02-05 17:32:02 -08:00
Paul Baumgart 51deaf4552 Enquote more command output in bootstrap to prevent spaces in paths from breaking things. 2011-02-05 17:31:04 -08:00
Paul Baumgart 57e1431e1a Remove duplicate prompts from bootstrap. 2011-02-05 17:30:03 -08:00
Saikat Chakrabarti 975e11abfc CPCursor refactor according to discussion in http://groups.google.com/group/objectivej-dev/browse_thread/thread/eabe59dc7d71122b/ddc6f1b61e5f3c2a?lnk=gst&q=cpcursor#ddc6f1b61e5f3c2a and new test for CPCursor that is easier to go through. 2011-02-04 17:41:40 -08:00
Randall Luecke b78eddd878 Clearer explaination of setPullsDown: of CPPopupButton 2011-02-04 19:01:12 -05:00
Jürgen Kartnaller 09ebc0effd Merge branch 'master' into traceback 2011-02-03 09:04:48 +01:00
Jürgen Kartnaller 6a4e0bd43a log a traceback only once 2011-02-02 22:43:20 +01:00
Antoine Mercadal 8994f08cbf move the fix to themedRoundedTextField: 2011-02-02 18:27:31 +01:00
Antoine Mercadal 55b97a7eeb fix CPSearchField layout glitch 2011-02-02 12:02:46 +01:00
Randall Luecke 203942d123 Documentation of CPApplication. 2011-01-30 16:56:56 -05:00
Derek Hammer 436f6cb8ea Fixing uniform column resize spacing issue. 2011-01-30 13:01:44 -06:00
Derek Hammer 9c4fb2c18c Updating selection code based on feedback from Randy 2011-01-29 18:01:57 -06:00
Derek Hammer d27544f2bf Crazy cool selection behavior. 2011-01-28 12:59:01 -06:00
Klaas Pieter Annema 5957e71967 enable nib2cib image support for CPMenuItem 2011-01-28 14:50:42 +01:00
Derek Hammer 85f51d7a66 Extend selection in a meaningful way when using keys. 2011-01-27 21:50:36 -08:00
Randall Luecke fdf47eb84e Fix for tableview reloadData call inside setObjectValue: causing additional editing to being. 2011-01-27 14:37:26 -05:00
Paul Baumgart 6963b37f61 Add --clone-http option to bootstrap 2011-01-26 21:09:10 -08:00
Ayal SpitzandPaul Baumgart 379c5294c2 Added a 'clone_http' flag to enable clonging of a git repo via http 2011-01-26 20:57:42 -08:00
Francisco Ryan Tolmasky I fb27f86126 Merge branch 'paulbaumgart-bootstrap-fixes' 2011-01-26 08:03:24 -08:00
Antoine Mercadal 3a6f2c4d5b make CPSound handling error + More Cocoa compliant 2011-01-26 11:06:10 +01:00
Klaas Pieter Annema 133dd39485 don't blur input element more than once 2011-01-26 11:03:09 +01:00
Paul Baumgart d50cbb02e6 Allow users to respond 'yes' to the narwhal install location bootstrap prompt to just use the default location. 2011-01-25 17:39:24 -08:00
Antoine Mercadal f39441e101 avoid error in FF 2011-01-25 21:24:36 +01:00
Randall Luecke 30695e4110 Document delete key delegate in tableview. 2011-01-25 11:03:12 -05:00
Jürgen Kartnaller 3e79d8324d Fix check for allowsReverseTransformation in reverseTransformedValue 2011-01-25 08:46:40 +01:00
Randall Luecke 71de04787d Fix backspace issue with textfield. Closes #1107. Thanks to Jukart for the patch. 2011-01-24 18:25:18 -05:00
Randall Luecke 81332fa57e Proper theme states for the tableview edit change I made yesterday. 2011-01-24 15:35:10 -05:00
Randall Luecke 191a02a89b Update documentation version number to 0.9. 2011-01-24 14:28:07 -05:00
cacaodev f60a92d2c4 CPViewAnimation: current frame based on -currentValue. CPAnimation: early return in -currentValue if linear 2011-01-24 20:24:19 +01:00
Ross Boucher f4ae6c450b Update the README a bit. 2011-01-24 10:19:52 -08:00
Alexander Ljungberg f2c53c9f52 Documentation tweaks. 2011-01-24 14:00:15 -03:00
Alexander Ljungberg 090fcab8c6 More globals fixing. 2011-01-24 13:43:55 -03:00
Alexander Ljungberg d3836c2a52 Global fixes. 2011-01-24 13:22:07 -03:00
Alexander Ljungberg ea8c29356d More typo and formatting fixes. 2011-01-24 13:17:48 -03:00
Stephen Ierodiaconou 6a942630e4 Fixing spelling mistakes 2011-01-24 11:05:48 +02:00
Randall Luecke 2aa806e52a Docs for CPControl. 2011-01-24 01:18:40 -05:00
Randall Luecke 04f1b61534 Fixes to tableview inline editing. 2011-01-24 00:56:39 -05:00
Randall Luecke b6119a763e Docs for CPWebView. 2011-01-23 19:05:02 -05:00
Randall Luecke 0876fd6db9 Docs of CPViewAnimation. 2011-01-23 18:10:26 -05:00
Randall Luecke 3d106c0716 Merge branch 'master' of git://github.com/280north/cappuccino 2011-01-23 17:53:20 -05:00
Randall Luecke c390b19d4b Much needed documentation of CPSplitView and some docs for CPWindow. 2011-01-23 17:50:39 -05:00
Francisco Ryan Tolmasky I 6a735ecda9 Merge branch 'master' of github.com:280north/cappuccino 2011-01-23 08:44:01 -08:00
Francisco Ryan Tolmasky I aada884cff A few import fixes.
Reviewed by me.
2011-01-23 08:43:46 -08:00
Paul Baumgart b62789bb18 Check for one of curl or wget. 2011-01-21 17:35:33 -08:00
Paul Baumgart eafec339f1 Minor update to bootstrap to have it check to make sure java is installed. 2011-01-21 16:49:32 -08:00
Alexander Ljungberg ef326dbbb4 Fix an accidental global, whitespace. 2011-01-20 22:33:42 -03:00
Alexander Ljungberg 4bbbcb15f1 Array controller documentation. 2011-01-20 22:27:09 -03:00
Alexander Ljungberg 92cb69b623 Merge branch 'CPArrayControllerFixes' of https://github.com/cacaodev/cappuccino into cacaodev-CPArrayControllerFixes 2011-01-20 22:14:17 -03:00
Alexander Ljungberg 18ea086ffc Removed unused Aristo files. 2011-01-20 22:13:01 -03:00
Alexander Ljungberg 40b04b7956 Merge branch 'master' of github.com:280north/cappuccino into cacaodev-CPTableColumnValueBinder
Conflicts:
	AppKit/CPTableColumn.j
2011-01-20 21:56:30 -03:00
Francisco Ryan Tolmasky I 38dc125fc2 Fix CPSubclassableDictionaryTest.
Reviewed by me.
2011-01-20 09:50:32 -08:00
Francisco Ryan Tolmasky I 378df68995 Merge branch 'master' of github.com:280north/cappuccino 2011-01-20 09:17:29 -08:00
Francisco Ryan Tolmasky I ec330a1090 Fix for pop up not reflecting changes in individual menu items.
Reviewed by me.
2011-01-20 09:07:04 -08:00
Randall Luecke f07543045a Doc fixes and more docs in the tableview. 2011-01-20 03:07:01 -05:00
Paul Baumgart 4458884048 Fallback to wget if curl isn't installed. 2011-01-19 20:28:49 -08:00
Paul Baumgart 7245fb99a6 Check to make sure SSL is working in tusk and advise on how to fix it otherwise. 2011-01-19 20:27:16 -08:00
Paul BaumgartandPaul Baumgart 5d27661354 Update check_build_environment in bootstrap
Newer versions of OpenJDK can handle running Narwhal.
It seems the problem is fixed in versions of OpenJDK 6 >= b18.
This commit checks for a sufficiently recent version of
OpenJDK and only prints an error/exits if the OpenJDK
version is older than 6b18.
2011-01-19 20:26:28 -08:00
Francisco Ryan Tolmasky I b33b2df778 Merge branch 'master' of github.com:280north/cappuccino 2011-01-19 19:30:46 -08:00
Francisco Ryan Tolmasky I d2f27408a5 Additional fix for archived CPPopUpButtons, and backwards compatibility support for old archives/cibs.
Reviewed by me.
2011-01-19 19:29:39 -08:00
Mike Fellows a801860f90 Move the functionality from CPStepper's _CPContinuousButton object into CPButton so any CPButton can be made continuous 2011-01-19 12:02:43 -08:00
cacaodev 235b323658 Add CPTableColumnValueBinder. This binder subclass just reloads the table column when a table column's value binding is updated because of a change in the bound-to object.
TableBindings test.
2011-01-19 19:56:46 +01:00
cacaodev 54c3cc0187 CPArrayController & nib2cib: added _automaticallyRearrangeObjects flag (not used currently).
_sortDescriptors initial value is an emty array (like in cocoa), not nil;
Added shared _init with default values, added missing accessors.
2011-01-19 19:26:21 +01:00
cacaodev 59cc590b51 CPArrayController -setContent: fixed a bug where objects where not rearranged if clearsFilterPredicateOnInsertion == YES and filterPredicate == nil. 2011-01-19 19:26:01 +01:00
Randall Luecke 66a87c472b Remove old resources from the old CPTabView. 2011-01-19 11:15:31 -05:00
Francisco Ryan Tolmasky I 688aed72cb Fix for CPPopUpButton's encoded prior to CPResponder/menu change.
Reviewed by me.
2011-01-18 23:09:43 -08:00
Francisco Ryan Tolmasky I 6310733881 Fix for menu bar color being reset (+ [CPMenu initialize] didn't check the class).
Reviewed by me.
2011-01-18 13:59:57 -08:00
Francisco Ryan Tolmasky I 3fe505b8e5 Merge branch 'master' of github.com:280north/cappuccino 2011-01-18 13:26:14 -08:00
Francisco Ryan Tolmasky I 00915083d4 Quick fix for initWithCapacity: not working on CPMutableArray.
Reviewed by me.
2011-01-18 13:25:43 -08:00
Klaas Pieter Annema 4e1ecbef72 Merge branch 'CPTextField-InterpretKeyEvents' of https://github.com/luuse/cappuccino into luuse-CPTextField-InterpretKeyEvents
Conflicts:
	AppKit/CPSearchField.j
	AppKit/CPTextField.j
2011-01-18 10:07:16 +01:00
Klaas Pieter Annema e4f6214005 Merge branch 'imports' of https://github.com/stevegeek/cappuccino into stevegeek-imports 2011-01-18 09:52:40 +01:00
Klaas Pieter Annema ed98a44116 detect sort descriptors when table column is added 2011-01-18 09:29:29 +01:00
Klaas Pieter Annema 50d36e76ac reverse set sort descriptors in CPTableView 2011-01-18 09:29:28 +01:00
Randall Luecke 818bf475f2 New gradient color to match aristo better. 2011-01-17 23:30:29 -05:00
Randall Luecke 47afb96c4c Drawing fixes for the tableview gradient. 2011-01-17 23:30:04 -05:00
Randall Luecke 467dc3c2d5 OutlineView docs. 2011-01-17 20:13:54 -05:00
Randall Luecke 7e3079add6 Magic enable to outlineview variable item height 2011-01-17 20:07:15 -05:00
Stephen Ierodiaconou 37323b811c Merge branch 'master' of git://github.com/280north/cappuccino into imports
Conflicts:
	Foundation/CPDecimalNumber.j
	Foundation/CPPredicate/CPComparisonPredicate.j
	Foundation/CPPredicate/CPCompoundPredicate.j
	Foundation/CPPredicate/CPExpression.j
	Foundation/CPPredicate/CPExpression_aggregate.j
	Foundation/CPPredicate/CPExpression_constant.j
	Foundation/CPPredicate/CPExpression_function.j
	Foundation/CPPredicate/CPExpression_keypath.j
	Foundation/CPPredicate/CPExpression_self.j
	Foundation/CPPredicate/CPExpression_set.j
	Foundation/CPPredicate/CPExpression_subquery.j
	Foundation/CPPredicate/CPExpression_variable.j
	Foundation/CPPredicate/CPPredicate.j
2011-01-16 10:03:42 +02:00
Stephen Ierodiaconou 494f615aaa Merge branch 'master' into imports
Conflicts:
	Foundation/CPScanner.j
2011-01-15 09:11:46 +02:00
Stephen Ierodiaconou 76b5682234 Missing imports in CPSet+KVO 2010-12-26 10:29:46 +02:00
Stephen Ierodiaconou 4aa4f1a62a Some more missing imports 2010-12-26 01:47:26 +02:00
Stephen Ierodiaconou 7ae14e9eb5 CPCharacterSet lint and fixes 2010-12-26 01:34:43 +02:00
Stephen Ierodiaconou bfe03a8874 CPJSONPConnection Missing imports and self check 2010-12-26 01:34:43 +02:00
Stephen Ierodiaconou 66b6b44f86 CPPredicate lint, import fixes, and some bug fixes 2010-12-26 01:34:43 +02:00
Stephen Ierodiaconou b70018bd80 Import fixes and lint 2010-12-26 01:34:37 +02:00
Jeremy Lujan 41d757e0c4 *Fix issue in setParameters due to expression in while condition in CPFlashView
*Protect against overwriting flashvars in _params when setParams is called after setFlashVars in CPFlashView
2010-12-14 21:38:52 -06:00
Andreas Falk a302fdfb8f CPTextField should not bother with handling tab to go to the next key
view, CPWindow does that for us.
2010-11-15 19:44:02 +01:00
Andreas bb9e1a830d Add cancelOperation action to clear text when pressing ESC 2010-11-13 15:21:37 +01:00
Andreas 9b7f8ec31e Add -insertTabIgnoringFieldEditor: and -insertNewlineIgnoringFieldEditor: 2010-11-13 15:16:25 +01:00
Andreas 17b40fcb9d Adapt CPTextField to use interpretKeyEvents and actions instead of directly reading from keyDown 2010-11-13 15:14:09 +01:00
cacaodev 602a2c47c2 CPScanner fixes with tests. 2010-11-13 02:29:04 +01:00
cacaodev 3cfbca5a19 CPScanner: When the scanner did not accumulate any string, do not change (to nil) the object passed as a ref in ...intoSring:ref() methods. With tests. 2010-10-23 10:25:42 +02:00
Paul Baumgart 2cc6c54fbf Start index for var-args needs to be 2, not 0. I only got lucky that it worked anyway. 2010-09-29 15:19:20 -07:00
Paul Baumgart e62fd3cf40 Add a test case to test some reductions of regexes that current cause errors in the Preprocessor. 2010-09-24 16:46:31 -07:00
Paul Baumgart 8cc61cccfd add behavior tests for methods, ivars, and inheritance; currently, one of the ivar tests fails due to bug #498 2010-09-24 15:10:06 -07:00
Paul Baumgart 0802b80c35 Make local param shadowing detection print a warning instead of throwing a SyntaxError. This way it's easier to test that particular scenario, since this is actually a bug in the Preprocessor. 2010-09-24 15:03:22 -07:00
Paul Baumgart 8de508381a re-organize directory structure of preprocessor tests 2010-09-24 15:02:07 -07:00
Paul Baumgart 086fa29d78 Objective-J Preprocessor Tests: fix scoping bug that caused only the last file in FILENAMES to be tested. 2010-09-22 00:50:15 -07:00
814 changed files with 105167 additions and 14475 deletions
+5
View File
@@ -5,3 +5,8 @@ Demos
./Aristo
WebSite
.push-package
*.xcodeproj/*.pbxuser
*.xcodeproj/*.perspectivev3
xcuserdata/
!*.xcodeproj/project.pbxproj
*.xCodeSupport/
+7 -1
View File
@@ -59,16 +59,21 @@
@import "CPImage.j"
@import "CPImageView.j"
@import "CPKeyBinding.j"
@import "CPLevelIndicator.j"
@import "CPMenu.j"
@import "CPMenuItem.j"
@import "CPOpenPanel.j"
@import "CPOutlineView.j"
@import "CPPanel.j"
@import "CPPasteboard.j"
@import "CPPopover.j"
@import "CPPopUpButton.j"
@import "CPPredicateEditor.j"
@import "CPPredicateEditorRowTemplate.j"
@import "CPProgressIndicator.j"
@import "CPRadio.j"
@import "CPResponder.j"
@import "CPRuleEditor.j"
@import "CPScroller.j"
@import "CPScrollView.j"
@import "CPSearchField.j"
@@ -87,11 +92,12 @@
@import "CPTokenField.j"
@import "CPToolbar.j"
@import "CPToolbarItem.j"
@import "_CPToolTip.j"
@import "CPTreeNode.j"
@import "CPUserDefaultsController.j"
@import "CPView.j"
@import "CPViewAnimation.j"
@import "CPViewController.j"
@import "CPWebView.j"
@import "CPWindow.j"
@import "CPWindowController.j"
+1 -1
View File
@@ -69,7 +69,7 @@
@class CPAccordionView
<p>CPAccordionView provides a container for CPAccordionViewItem objects and manages layout state
for all sublayout items.</p>
for all sub-layout items.</p>
<strong>Example</strong><br />
<pre>
+5 -5
View File
@@ -6,7 +6,7 @@
* Copyright 2008, Jake MacMullin.
*
* 11/10/2008 Ross Boucher
* - Make it conform to style guidelines, general cleanup and ehancements
* - Make it conform to style guidelines, general cleanup and enhancements
* 11/10/2010 Antoine Mercadal
* - Enhancements, better compliance with Cocoa API
*
@@ -117,7 +117,7 @@ CPCriticalAlertStyle = 2;
*/
+ (CPAlert)alertWithMessageText:(CPString)aMessage defaultButton:(CPString)defaultButtonTitle alternateButton:(CPString)alternateButtonTitle otherButton:(CPString)otherButtonTitle informativeTextWithFormat:(CPString)informativeText
{
var alert = [[CPAlert alloc] init];
var alert = [[self alloc] init];
[alert setMessageText:aMessage];
[alert addButtonWithTitle:defaultButtonTitle];
@@ -142,7 +142,7 @@ CPCriticalAlertStyle = 2;
*/
+ (CPAlert)alertWithError:(CPString)anErrorMessage
{
var alert = [[CPAlert alloc] init];
var alert = [[self alloc] init];
[alert setMessageText:anErrorMessage];
[alert setAlertStyle:CPCriticalAlertStyle];
@@ -371,8 +371,8 @@ CPCriticalAlertStyle = 2;
[_informativeLabel setAlignment:[self currentValueForThemeAttribute:@"informative-text-alignment"]];
[_informativeLabel setLineBreakMode:CPLineBreakByWordWrapping];
informativeLabelWidth = CGRectGetWidth([[_window contentView] frame]) - inset.left - inset.right,
informativeLabelOriginY = [_messageLabel frameOrigin].y + [_messageLabel frameSize].height + defaultElementsMargin,
informativeLabelWidth = CGRectGetWidth([[_window contentView] frame]) - inset.left - inset.right;
informativeLabelOriginY = [_messageLabel frameOrigin].y + [_messageLabel frameSize].height + defaultElementsMargin;
informativeLabelTextSize = [[_informativeLabel stringValue] sizeWithFont:[_informativeLabel font] inWidth:informativeLabelWidth];
[_informativeLabel setFrame:CGRectMake(inset.left, informativeLabelOriginY, informativeLabelTextSize.width, informativeLabelTextSize.height + sizeWithFontCorrection)];
+4
View File
@@ -21,6 +21,7 @@
*/
@import <Foundation/CPObject.j>
@import <Foundation/CPTimer.j>
@import "CAMediaTimingFunction.j"
@@ -305,6 +306,9 @@ ACTUAL_FRAME_RATE = 0;
if ([_delegate respondsToSelector:@selector(animation:valueForProgress:)])
return [_delegate animation:self valueForProgress:t];
if (_animationCurve == CPAnimationLinear)
return t;
var c1 = [],
c2 = [];
+137 -4
View File
@@ -57,7 +57,7 @@ CPRunContinuesResponse = -1002;
@ingroup appkit
@class CPApplication
CPApplication is THE way to start up the Cappucino framework for your application to use.
CPApplication is THE way to start up the Cappuccino framework for your application to use.
Every GUI application has exactly one instance of CPApplication (or of a custom subclass of
CPApplication). Your program's main() function can create that instance by calling the
\c CPApplicationMain function. A simple example looks like this:
@@ -292,11 +292,21 @@ CPRunContinuesResponse = -1002;
}
}
/*!
Sets the applications icon image. This image is used in the default "About" window.
By default this value is pulled from the CPApplicationIcon key in your info.plist file.
@param anImage - The image to set.
*/
- (void)setApplicationIconImage:(CPImage)anImage
{
_applicationIconImage = anImage;
}
/*!
Returns the application icon image. By default this is pulled from the CPApplicationIcon key of info.plist.
@return CPImage - Your application icon image.
*/
- (CPImage)applicationIconImage
{
if (_applicationIconImage)
@@ -309,11 +319,38 @@ CPRunContinuesResponse = -1002;
return _applicationIconImage;
}
/*!
Opens the standard about panel with no options.
*/
- (void)orderFrontStandardAboutPanel:(id)sender
{
[self orderFrontStandardAboutPanelWithOptions:nil];
}
/*!
Opens the standard about panel. This method takes a single argument \c options.
Options is a dictionary that can contain any of the following keys:
<pre>
ApplicationName - The name of your application.
ApplicationIcon - Application icon image.
Version - The full version of your application
ApplicationVersion - The shorter version number of your application.
Copyright - Human readable copyright information.
</pre>
If you choose not the include any of the above keys, they will default
to the following respective keys in your info.plist file.
<pre>
CPBundleName
CPApplicationIcon (through a call to -applicationIconImage, see documentation for that method for more details)
CPBundleVersion
CPBundleShortVersionString
CPHumanReadableCopyright
</pre>
@param options - A dictionary with the aboe listed keys. You can pass nil to default to your plist values.
*/
- (void)orderFrontStandardAboutPanelWithOptions:(CPDictionary)options
{
if (!_aboutPanel)
@@ -573,6 +610,10 @@ CPRunContinuesResponse = -1002;
[[anEvent window] sendEvent:anEvent];
}
/*!
If the delegate responds to the given selector it will call the method on the delegate,
otherwise the method will be passed to CPResponder.
*/
- (void)doCommandBySelector:(SEL)aSelector
{
if ([_delegate respondsToSelector:aSelector])
@@ -664,6 +705,10 @@ CPRunContinuesResponse = -1002;
[aMenu _setMenuName:@"CPMainMenu"];
}
/*!
Opens the shared color panel.
@param aSender
*/
- (void)orderFrontColorPanel:(id)aSender
{
[[CPColorPanel sharedColorPanel] orderFront:self];
@@ -832,16 +877,38 @@ CPRunContinuesResponse = -1002;
return nil;
}
/*!
Fires a callback function when an event matching a given mask occurs.
@param aCallback - A js function to be fired.
@prarm aMask - An event mask for the next event.
@param anExpiration - The date for which this callback expires (not implemented).
@param inMode (not implemented).
@param shouldDequeue (not implemented).
*/
- (void)setCallback:(Function)aCallback forNextEventMatchingMask:(unsigned int)aMask untilDate:(CPDate)anExpiration inMode:(CPString)aMode dequeue:(BOOL)shouldDequeue
{
_eventListeners.push(_CPEventListenerMake(aMask, aCallback));
}
- (CPEvent)setTarget:(id)aTarget selector:(SEL)aSelector forNextEventMatchingMask:(unsigned int)aMask untilDate:(CPDate)anExpiration inMode:(CPString)aMode dequeue:(BOOL)shouldDequeue
/*!
Assigns a target and action for the next event matching a given event mask.
The callback method called will be passed the CPEvent when it fires.
@param aTarget - The target object for the callback.
@param aSelector - The selector which should be called on the target object.
@param aMask - The mask for a given event which should trigger the callback.
@param anExpiration - The date for which the callback expires (not implemented).
@param aMode (not implemented).
@param shouldDequeue (not implemented).
*/
- (void)setTarget:(id)aTarget selector:(SEL)aSelector forNextEventMatchingMask:(unsigned int)aMask untilDate:(CPDate)anExpiration inMode:(CPString)aMode dequeue:(BOOL)shouldDequeue
{
_eventListeners.push(_CPEventListenerMake(aMask, function (anEvent) { objj_msgSend(aTarget, aSelector, anEvent); }));
}
/*!
Returns the last event recieved by your application.
*/
- (CPEvent)currentEvent
{
return _currentEvent;
@@ -871,6 +938,19 @@ CPRunContinuesResponse = -1002;
[aWindow _attachSheet:aSheet modalDelegate:aModalDelegate didEndSelector:aDidEndSelector contextInfo:aContextInfo];
}
/*!
Ends a sheet modal.
The following are predefined return codes:
<pre>
CPRunStoppedResponse
CPRunAbortedResponse
CPRunContinuesResponse
</pre>
@param sheet - The window object (sheet) to dismiss.
@param returnCode - The return code to send to the delegate. You can use one of the return codes above or a custom value that you define.
*/
- (void)endSheet:(CPWindow)sheet returnCode:(int)returnCode
{
var count = [_windows count];
@@ -889,11 +969,31 @@ CPRunContinuesResponse = -1002;
}
}
/*!
Ends a sheet and sends the return code "0".
@param sheet - The CPWindow object (sheet) that should be dismissed.
*/
- (void)endSheet:(CPWindow)sheet
{
// FIX ME: this is wrong: by Cocoa this should be: CPRunStoppedResponse.
[self endSheet:sheet returnCode:0];
}
/*!
Returns and array of slash seperated arugments to your application.
These values are pulled from your window location hash.
For exampled if your application loaded:
<pre>
index.html#280north/cappuccino/issues
</pre>
The follow array would be returned:
<pre>
["280north", "cappuccino", "issues"]
</pre>
@return CPArray - The array of arguments.
*/
- (CPArray)arguments
{
if (_fullArgsString !== window.location.hash)
@@ -902,6 +1002,22 @@ CPRunContinuesResponse = -1002;
return _args;
}
/*!
Sets the arguments of your application.
That is, set the slash seperated values of an array as the window location hash.
For example if you pass an array:
<pre>
["280north", "cappuccino", "issues"]
</pre>
The new window location would be
<pre>
index.html#280north/cappuccino/issues
</pre>
@param args - An array of arguments.
*/
- (void)setArguments:(CPArray)args
{
if (!args || args.length == 0)
@@ -943,6 +1059,23 @@ CPRunContinuesResponse = -1002;
_args = [];
}
/*!
Returns a dictionary of the window location named arguments.
For example if your location was:
<pre>
index.html?owner=280north&repo=cappuccino&type=issues
</pre>
a CPDictionary with the keys:
<pre>
owner, repo, type
</pre>
and respective values:
<pre>
280north, cappuccino, issues
</pre>
Will be returned.
*/
- (CPDictionary)namedArguments
{
return _namedArgs;
@@ -1207,8 +1340,8 @@ var _CPAppBootstrapperActions = nil;
[editMenu addItem:undoMenuItem];
[editMenu addItem:redoMenuItem];
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Cut" action:@selector(cut:) keyEquivalent:@"x"]],
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Copy" action:@selector(copy:) keyEquivalent:@"c"]],
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Cut" action:@selector(cut:) keyEquivalent:@"x"]];
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Copy" action:@selector(copy:) keyEquivalent:@"c"]];
[editMenu addItem:[[CPMenuItem alloc] initWithTitle:@"Paste" action:@selector(paste:) keyEquivalent:@"v"]];
[editMenuItem setSubmenu:editMenu];
+354 -59
View File
@@ -1,5 +1,3 @@
/*
* CPArrayController.j
* AppKit
@@ -46,10 +44,14 @@
BOOL _selectsInsertedObjects;
BOOL _alwaysUsesMultipleValuesMarker;
id _selectionIndexes;
id _sortDescriptors;
id _filterPredicate;
id _arrangedObjects;
BOOL _automaticallyRearrangesObjects; // FIXME: Not in use
CPIndexSet _selectionIndexes;
CPArray _sortDescriptors;
CPPredicate _filterPredicate;
CPArray _arrangedObjects;
BOOL _disableSetContent;
}
+ (void)initialize
@@ -68,7 +70,8 @@
+ (CPSet)keyPathsForValuesAffectingArrangedObjects
{
return [CPSet setWithObjects:"content", "filterPredicate", "sortDescriptors"];
// Also depends on "filterPredicate" but we'll handle that manually.
return [CPSet setWithObjects:"content", "sortDescriptors"];
}
+ (CPSet)keyPathsForValuesAffectingSelection
@@ -116,13 +119,29 @@
if (self)
{
_sortDescriptors = [CPArray array];
_selectionIndexes = [CPIndexSet indexSet];
_preservesSelection = YES;
_selectsInsertedObjects = YES;
_avoidsEmptySelection = YES;
_clearsFilterPredicateOnInsertion = YES;
_alwaysUsesMultipleValuesMarker = NO;
_automaticallyRearrangesObjects = NO;
_filterRestrictsInsertion = YES; // FIXME: Not in use
[self _init];
}
return self;
}
- (void)_init
{
_sortDescriptors = [CPArray array];
_filterPredicate = nil;
_selectionIndexes = [CPIndexSet indexSet];
[self __setArrangedObjects:[CPArray array]];
}
- (void)prepareContent
{
[self _setContentArray:[[self newObject]]];
@@ -156,7 +175,7 @@
/*!
Sets whether the controller will automatically select objects as they are inserted.
@return BOOL aFlag - YES if new objects are selected, otherwise NO.
@return BOOL - YES if new objects are selected, otherwise NO.
*/
- (void)setSelectsInsertedObjects:(BOOL)value
{
@@ -164,7 +183,7 @@
}
/*!
@return BOOL aFlag - Returns YES if the controller should try to avoid an empty selection otherwise NO.
@return BOOL - YES if the controller should try to avoid an empty selection otherwise NO.
*/
- (BOOL)avoidsEmptySelection
{
@@ -173,13 +192,83 @@
/*!
Sets whether the controller should try to avoid an empty selection.
@param BOOL aFlag - YES if the reciver should attempt to avoid an empty selection, otherwise NO.
@param BOOL aFlag - YES if the receiver should attempt to avoid an empty selection, otherwise NO.
*/
- (void)setAvoidsEmptySelection:(BOOL)value
{
_avoidsEmptySelection = value;
}
/*!
Whether the receiver will clear its filter predicate when a new object is inserted.
@return BOOL YES if the receiver clears filter predicates on insert
*/
- (BOOL)clearsFilterPredicateOnInsertion
{
return _clearsFilterPredicateOnInsertion;
}
/*!
Sets whether the receiver should clear its filter predicate when a new object is inserted.
@param BOOL YES if the receiver should clear filter predicates on insert
*/
- (void)setClearsFilterPredicateOnInsertion:(BOOL)aFlag
{
_clearsFilterPredicateOnInsertion = aFlag;
}
/*!
Whether the receiver will always return the multiple values marker when multiple
items are selected, even if the items have the same value.
@return BOOL YES if the receiver always uses the multiple values marker
*/
- (BOOL)alwaysUsesMultipleValuesMarker
{
return _alwaysUsesMultipleValuesMarker;
}
/*!
Sets whether the receiver should always return the multiple values marker when multiple
items are selected, even if the items have the same value.
@param BOOL aFlag YES if the receiver should always use the multiple values marker
*/
- (void)setAlwaysUsesMultipleValuesMarker:(BOOL)aFlag
{
_alwaysUsesMultipleValuesMarker = aFlag;
}
/*!
Whether the receiver will rearrange its contents automatically whenever the sort
descriptors or filter predicates are changed.
NOTE: not yet implemented. Cappuccino always act as if this value was YES.
@return BOOL YES if the receiver will automatically rearrange its content on new sort
descriptors or filter predicates
*/
- (BOOL)automaticallyRearrangesObjects
{
return _automaticallyRearrangesObjects;
}
/*!
Sets whether the receiver should rearrange its contents automatically whenever the sort
descriptors or filter predicates are changed.
NOTE: not yet implemented. Cappuccino always act as if this value was YES.
@param BOOL YES if the receiver should automatically rearrange its content on new sort
descriptors or filter predicates
*/
- (void)setAutomaticallyRearrangesObjects:(BOOL)aFlag
{
_automaticallyRearrangesObjects = aFlag;
}
/*!
Sets the controller's content object.
@@ -187,6 +276,12 @@
*/
- (void)setContent:(id)value
{
// This is used to ignore expected setContent: calls caused by a binding to our content
// object when we are the ones modifying the content object and can deal with the update
// faster directly in the code in charge of the modification.
if (_disableSetContent)
return;
if (value === nil)
value = [];
@@ -218,9 +313,11 @@
// Don't use [super setContent:] as that would fire the contentObject change.
// We need to be in control of when notifications fire.
// Note that if we have a contentArray binding, setting the content does /not/
// cause a reverse binding set.
_contentObject = value;
if (_clearsFilterPredicateOnInsertion)
if (_clearsFilterPredicateOnInsertion && _filterPredicate != nil)
[self __setFilterPredicate:nil]; // Causes a _rearrangeObjects.
else
[self _rearrangeObjects];
@@ -252,7 +349,7 @@
/*!
Returns the content array of the controller.
@return id the content array of the reciever
@return id the content array of the receiver
*/
- (id)contentArray
{
@@ -260,7 +357,7 @@
}
/*!
Returns the content of the reciever as a CPSet.
Returns the content of the receiver as a CPSet.
@return id - the content of the controller as a set.
*/
@@ -280,7 +377,7 @@
var filterPredicate = [self filterPredicate],
sortDescriptors = [self sortDescriptors];
if (filterPredicate && sortDescriptors)
if (filterPredicate && [sortDescriptors count] > 0)
{
var sortedObjects = [objects filteredArrayUsingPredicate:filterPredicate];
[sortedObjects sortUsingDescriptors:sortDescriptors];
@@ -288,7 +385,7 @@
}
else if (filterPredicate)
return [objects filteredArrayUsingPredicate:filterPredicate];
else if (sortDescriptors)
else if ([sortDescriptors count] > 0)
return [objects sortedArrayUsingDescriptors:sortDescriptors];
return [objects copy];
@@ -338,7 +435,7 @@
if (_arrangedObjects === value)
return;
_arrangedObjects = [[_CPObservableArray alloc] initWithArray:value];
_arrangedObjects = [[_CPObservableArray alloc] initWithArray:value];
}
/*!
@@ -376,7 +473,7 @@
}
/*!
Returns the predicate used by the controller to filter the contents of the reciever.
Returns the predicate used by the controller to filter the contents of the receiver.
If no predicate is set nil is returned.
@return CPPredicate the predicate used by the controller
@@ -394,7 +491,14 @@
*/
- (void)setFilterPredicate:(CPPredicate)value
{
if (_filterPredicate === value)
return;
// __setFilterPredicate will call _rearrangeObjects without
// sending notifications, so we must send them instead.
[self willChangeValueForKey:@"arrangedObjects"];
[self __setFilterPredicate:value];
[self didChangeValueForKey:@"arrangedObjects"];
}
/*
@@ -407,8 +511,7 @@
return;
_filterPredicate = value;
// Use the non-notification version since arrangedObjects already depends
// on filterPredicate.
// Use the non-notification version.
[self _rearrangeObjects];
}
@@ -434,7 +537,7 @@
/*!
Sets the selected index
@param unsided anIndex - the new index to select
@param unsigned anIndex - the new index to select
@return BOOL - Returns YES if the selection was changed, otherwise NO.
*/
- (BOOL)setSelectionIndex:(unsigned)index
@@ -461,8 +564,9 @@
- (BOOL)setSelectionIndexes:(CPIndexSet)indexes
{
[self _selectionWillChange]
[self __setSelectionIndexes:indexes];
var r = [self __setSelectionIndexes:indexes];
[self _selectionDidChange];
return r;
}
/*
@@ -471,7 +575,7 @@
*/
- (BOOL)__setSelectionIndex:(int)theIndex
{
[self __setSelectionIndexes:[CPIndexSet indexSetWithIndex:theIndex]];
return [self __setSelectionIndexes:[CPIndexSet indexSetWithIndex:theIndex]];
}
/*
@@ -480,28 +584,38 @@
*/
- (BOOL)__setSelectionIndexes:(CPIndexSet)indexes
{
if (!indexes)
indexes = [CPIndexSet indexSet];
var newIndexes = indexes;
if (![indexes count])
if (!newIndexes)
newIndexes = [CPIndexSet indexSet];
if (![newIndexes count])
{
if (_avoidsEmptySelection && [[self arrangedObjects] count])
indexes = [CPIndexSet indexSetWithIndex:0];
newIndexes = [CPIndexSet indexSetWithIndex:0];
}
else
{
var objectsCount = [[self arrangedObjects] count];
// Don't trash the input - the caller might depend on it or we might have been
// given _selectionIndexes as the input in which case the equality test below
// would always succeed despite our change below.
newIndexes = [newIndexes copy];
// Remove out of bounds indexes.
[indexes removeIndexesInRange:CPMakeRange(objectsCount, [indexes lastIndex] + 1)];
[newIndexes removeIndexesInRange:CPMakeRange(objectsCount, [newIndexes lastIndex] + 1)];
// When avoiding empty selection and the deleted selection was at the bottom, select the last item.
if (![indexes count] && _avoidsEmptySelection && objectsCount)
indexes = [CPIndexSet indexSetWithIndex:objectsCount - 1];
if (![newIndexes count] && _avoidsEmptySelection && objectsCount)
newIndexes = [CPIndexSet indexSetWithIndex:objectsCount - 1];
}
if ([_selectionIndexes isEqualToIndexSet:indexes])
if ([_selectionIndexes isEqualToIndexSet:newIndexes])
return NO;
_selectionIndexes = [indexes copy];
// If we haven't already created our own index instance, make sure to copy it here so that
// the copy the user sent in is decoupled from our internal copy.
_selectionIndexes = indexes === newIndexes ? [indexes copy] : newIndexes;
// Push back the new selection to the model for selectionIndexes if we have one.
// There won't be an infinite loop because of the equality check above.
@@ -533,10 +647,11 @@
[self willChangeValueForKey:@"selectionIndexes"];
[self _selectionWillChange];
[self __setSelectedObjects:objects];
var r = [self __setSelectedObjects:objects];
[self didChangeValueForKey:@"selectionIndexes"];
[self _selectionDidChange];
return r;
}
/*
@@ -618,17 +733,39 @@
if (![self canAdd])
return;
if (_clearsFilterPredicateOnInsertion)
var willClearPredicate = NO;
if (_clearsFilterPredicateOnInsertion && _filterPredicate)
{
[self willChangeValueForKey:@"filterPredicate"];
willClearPredicate = YES;
}
[self willChangeValueForKey:@"content"];
/*
If the content array is bound then our addObject: message below will cause the observed
array to change. The binding will call setContent:_contentObject on this array
controller to let it know about the change. We want to ignore that message since we
A) already have the right _contentObject and B) properly update _arrangedObjects
by hand below.
*/
_disableSetContent = YES;
[_contentObject addObject:object];
if (_clearsFilterPredicateOnInsertion)
[self __setFilterPredicate:nil];
// Allow handlesContentAsCompoundValue reverse sets to trigger.
[[CPBinder getBinding:@"contentArray" forObject:self] _contentArrayDidChange];
if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:object])
_disableSetContent = NO;
if (willClearPredicate)
{
// Full rearrange needed due to changed filter.
_filterPredicate = nil;
[self _rearrangeObjects];
}
else if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:object])
{
// Insert directly into the array.
var pos = [_arrangedObjects insertObject:object inArraySortedByDescriptors:_sortDescriptors];
// selectionIndexes change notification will be fired as a result of the
@@ -638,16 +775,22 @@
else
[_selectionIndexes shiftIndexesStartingAtIndex:pos by:1];
}
else
[self _rearrangeObjects];
/*
else if (_filterPredicate !== nil)
...
// Implies _filterPredicate && ![_filterPredicate evaluateWithObject:object], so the new object does
// not appear in arrangedObjects and we do not have to update at all.
*/
// This will also send notificaitons for arrangedObjects.
[self didChangeValueForKey:@"content"];
if (_clearsFilterPredicateOnInsertion)
if (willClearPredicate)
[self didChangeValueForKey:@"filterPredicate"];
}
/*!
Adds an object at a given index to the reciever's collection.
Adds an object at a given index in the receiver's arrangedObjects. Also add the object
to the content collection (although at the end rather than the given index).
@param id anObject - The object to add to the collection.
@param int anIndex - The index to insert the object at.
@@ -657,13 +800,30 @@
if (![self canAdd])
return;
if (_clearsFilterPredicateOnInsertion)
var willClearPredicate = NO;
if (_clearsFilterPredicateOnInsertion && _filterPredicate)
{
[self willChangeValueForKey:@"filterPredicate"];
willClearPredicate = YES;
}
[self willChangeValueForKey:@"content"];
[_contentObject insertObject:anObject atIndex:anIndex];
if (_clearsFilterPredicateOnInsertion)
/*
See _disableSetContent explanation in addObject:.
*/
_disableSetContent = YES;
// The atArrangedObjectIndex: part of this method's name only refers to where the
// object goes in arrangedObjects, not in the content array. So use addObject:,
// not insertObject:atIndex: here for speed.
[_contentObject addObject:anObject];
// Allow handlesContentAsCompoundValue reverse sets to trigger.
[[CPBinder getBinding:@"contentArray" forObject:self] _contentArrayDidChange];
_disableSetContent = NO;
if (willClearPredicate)
[self __setFilterPredicate:nil];
[[self arrangedObjects] insertObject:anObject atIndex:anIndex];
@@ -679,31 +839,39 @@
[self __setSelectionIndexes:[CPIndexSet indexSetWithIndex:0]];
[self didChangeValueForKey:@"content"];
if (_clearsFilterPredicateOnInsertion)
if (willClearPredicate)
[self didChangeValueForKey:@"filterPredicate"];
}
/*!
Removes a given object from the reciever's collection.
Removes a given object from the receiver's collection.
@param id anObject - The object to remove from the collection.
*/
- (void)removeObject:(id)object
{
[self willChangeValueForKey:@"content"];
[_contentObject removeObject:object];
[self willChangeValueForKey:@"content"];
if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:object])
{
// selectionIndexes change notification will be fired as a result of the
// content change. Don't fire manually.
// See _disableSetContent explanation in addObject:.
_disableSetContent = YES;
[_contentObject removeObject:object];
// Allow handlesContentAsCompoundValue reverse sets to trigger.
[[CPBinder getBinding:@"contentArray" forObject:self] _contentArrayDidChange];
_disableSetContent = NO;
if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:object])
{
// selectionIndexes change notification will be fired as a result of the
// content change. Don't fire manually.
var pos = [_arrangedObjects indexOfObject:object];
[_arrangedObjects removeObjectAtIndex:pos];
[_selectionIndexes shiftIndexesStartingAtIndex:pos by:-1];
}
}
[self didChangeValueForKey:@"content"];
[self didChangeValueForKey:@"content"];
}
/*!
@@ -739,16 +907,61 @@
*/
- (void)remove:(id)sender
{
[self removeObjects:[[self arrangedObjects] objectsAtIndexes:[self selectionIndexes]]];
[self removeObjectsAtArrangedObjectIndexes:_selectionIndexes];
}
/*!
Removes the objects at the specified indexes in the controller's arranged objects from the content array.
@param CPIndexSet indexes - indexes of the objects to remove.
*/
- (void)removeObjectsAtArrangedObjectIndexes:(CPIndexSet)indexes
- (void)removeObjectsAtArrangedObjectIndexes:(CPIndexSet)anIndexSet
{
[self _removeObjects:[[self arrangedObjects] objectsAtIndexes:indexes]];
[self willChangeValueForKey:@"content"];
/*
See _disableSetContent explanation in addObject:.
*/
_disableSetContent = YES;
var arrangedObjects = [self arrangedObjects],
index = [anIndexSet lastIndex],
position = CPNotFound,
newSelectionIndexes = [_selectionIndexes copy];
while (index !== CPNotFound)
{
var object = [arrangedObjects objectAtIndex:index];
// First try the simple case which should work if there are no sort descriptors.
if ([_contentObject objectAtIndex:index] === object)
[_contentObject removeObjectAtIndex:index];
else
{
// Since we don't have a reverse mapping between the sorted order and the
// unsorted one, we'll just simply have to remove an arbitrary pointer. It might
// be the 'wrong' one - as in not the one the user selected - but the wrong
// one is still just another pointer to the same object, so the user will not
// be able to see any difference.
contentIndex = [_contentObject indexOfObjectIdenticalTo:object];
[_contentObject removeObjectAtIndex:contentIndex];
}
[arrangedObjects removeObjectAtIndex:index];
// Deselect this row if it was selected, and either way shift all selection indexes
// following it up by 1.
[newSelectionIndexes removeIndex:index];
[newSelectionIndexes shiftIndexesStartingAtIndex:index by:-1];
index = [anIndexSet indexLessThanIndex:index];
}
// Allow handlesContentAsCompoundValue reverse sets to trigger.
[[CPBinder getBinding:@"contentArray" forObject:self] _contentArrayDidChange];
_disableSetContent = NO;
// This will automatically handle the avoidsEmptySelection case.
[self __setSelectionIndexes:newSelectionIndexes];
[self didChangeValueForKey:@"content"];
}
/*!
@@ -768,6 +981,8 @@
[contentArray addObject:[objects objectAtIndex:i]];
[self setContent:contentArray];
// Allow handlesContentAsCompoundValue reverse sets to trigger.
[[CPBinder getBinding:@"contentArray" forObject:self] _contentArrayDidChange];
}
/*!
@@ -785,7 +1000,15 @@
- (void)_removeObjects:(CPArray)objects
{
[self willChangeValueForKey:@"content"];
// See _disableSetContent explanation in addObject:.
_disableSetContent = YES;
[_contentObject removeObjectsInArray:objects];
// Allow handlesContentAsCompoundValue reverse sets to trigger.
[[CPBinder getBinding:@"contentArray" forObject:self] _contentArrayDidChange];
_disableSetContent = NO;
var arrangedObjects = [self arrangedObjects],
position = [arrangedObjects indexOfObject:[objects objectAtIndex:0]];
@@ -824,12 +1047,81 @@
@end
@implementation CPArrayController (CPBinder)
+ (Class)_binderClassForBinding:(CPString)theBinding
{
if (theBinding == @"contentArray")
return [_CPArrayControllerContentBinder class];
return [super _binderClassForBinding:theBinding];
}
@end
@implementation _CPArrayControllerContentBinder : CPBinder
- (void)setValueFor:(CPString)aBinding
{
var destination = [_info objectForKey:CPObservedObjectKey],
keyPath = [_info objectForKey:CPObservedKeyPathKey],
options = [_info objectForKey:CPOptionsKey],
isCompound = [self handlesContentAsCompoundValue];
if (!isCompound)
{
newValue = [destination mutableArrayValueForKeyPath:keyPath];
}
else
{
// handlesContentAsCompoundValue == YES so we cannot just set up a proxy.
// Every read and every write must go through transformValue and
// reverseTransformValue, and the resulting object cannot be described by
// a key path.
newValue = [destination valueForKeyPath:keyPath];
}
newValue = [self transformValue:newValue withOptions:options];
if (isCompound)
{
// Make sure we can edit our copy of the content. TODO In Cocoa, this copy
// appears to be deferred until the array actually needs to be edited.
newValue = [newValue mutableCopy];
}
[_source setValue:newValue forKey:aBinding];
}
- (void)_contentArrayDidChange
{
// When handlesContentAsCompoundValue == YES, it is not sufficient to modify the content object
// in place because what we are holding is an array 'unwrapped' from a compound value by
// a value transformer. So when we modify it we need a reverse set and transform to create
// a new compound value.
//
// (The Cocoa documentation on the subject is not very clear but after substantial
// experimentation this seems both reasonable and compliant.)
if ([self handlesContentAsCompoundValue])
{
var destination = [_info objectForKey:CPObservedObjectKey],
keyPath = [_info objectForKey:CPObservedKeyPathKey];
[self suppressSpecificNotificationFromObject:destination keyPath:keyPath];
[self reverseSetValueFor:@"contentArray"];
[self unsuppressSpecificNotificationFromObject:destination keyPath:keyPath];
}
}
@end
var CPArrayControllerAvoidsEmptySelection = @"CPArrayControllerAvoidsEmptySelection",
CPArrayControllerClearsFilterPredicateOnInsertion = @"CPArrayControllerClearsFilterPredicateOnInsertion",
CPArrayControllerFilterRestrictsInsertion = @"CPArrayControllerFilterRestrictsInsertion",
CPArrayControllerPreservesSelection = @"CPArrayControllerPreservesSelection",
CPArrayControllerSelectsInsertedObjects = @"CPArrayControllerSelectsInsertedObjects",
CPArrayControllerAlwaysUsesMultipleValuesMarker = @"CPArrayControllerAlwaysUsesMultipleValuesMarker";
CPArrayControllerAlwaysUsesMultipleValuesMarker = @"CPArrayControllerAlwaysUsesMultipleValuesMarker",
CPArrayControllerAutomaticallyRearrangesObjects = @"CPArrayControllerAutomaticallyRearrangesObjects";
@implementation CPArrayController (CPCoding)
@@ -845,6 +1137,8 @@ var CPArrayControllerAvoidsEmptySelection = @"CPArrayControllerAvoid
_preservesSelection = [aCoder decodeBoolForKey:CPArrayControllerPreservesSelection];
_selectsInsertedObjects = [aCoder decodeBoolForKey:CPArrayControllerSelectsInsertedObjects];
_alwaysUsesMultipleValuesMarker = [aCoder decodeBoolForKey:CPArrayControllerAlwaysUsesMultipleValuesMarker];
_automaticallyRearrangesObjects = [aCoder decodeBoolForKey:CPArrayControllerAutomaticallyRearrangesObjects];
_sortDescriptors = [CPArray array];
if (![self content] && [self automaticallyPreparesContent])
[self prepareContent];
@@ -865,6 +1159,7 @@ var CPArrayControllerAvoidsEmptySelection = @"CPArrayControllerAvoid
[aCoder encodeBool:_preservesSelection forKey:CPArrayControllerPreservesSelection];
[aCoder encodeBool:_selectsInsertedObjects forKey:CPArrayControllerSelectsInsertedObjects];
[aCoder encodeBool:_alwaysUsesMultipleValuesMarker forKey:CPArrayControllerAlwaysUsesMultipleValuesMarker];
[aCoder encodeBool:_automaticallyRearrangesObjects forKey:CPArrayControllerAutomaticallyRearrangesObjects];
}
- (void)awakeFromCib
+1 -1
View File
@@ -38,7 +38,7 @@ var DefaultLineWidth = 1.0;
@class CPBezierPath
A CPBezierPath allows you to create paths for drawing to the screen using a simpler API than CoreGraphics.
Paths can form any shape, including regular polgyons like squares and triangles; circles, arcs; or complex
Paths can form any shape, including regular polygons like squares and triangles; circles, arcs; or complex
line segments.
A path can be stroked and filled using the relevant method. The currently active fill and stroke color will
+69 -2
View File
@@ -35,6 +35,12 @@ CPLineBorder = 1;
CPBezelBorder = 2;
CPGrooveBorder = 3;
/*!
@ingroup appkit
@class CPBox
A CPBox is a simple view which can display a border.
*/
@implementation CPBox : CPView
{
CPBoxType _boxType;
@@ -55,6 +61,7 @@ CPGrooveBorder = 3;
var box = [[self alloc] initWithFrame:CGRectMakeZero()],
enclosingView = [aView superview];
[box setAutoresizingMask:[aView autoresizingMask]];
[box setFrameFromContentFrame:[aView frame]];
[enclosingView replaceSubview:aView with:box];
@@ -89,16 +96,46 @@ CPGrooveBorder = 3;
// Configuring Boxes
/*!
Returns the receiver's border rectangle.
@return the border rectangle of the box
*/
- (CPRect)borderRect
{
return [self bounds];
}
/*!
Returns the receiver's border type. Possible values are:
<pre>
CPNoBorder
CPLineBorder
CPBezelBorder
CPGrooveBorder
</pre>
@return the border type of the box
*/
- (CPBorderType)borderType
{
return _borderType;
}
/*!
Sets the receiver's border type. Valid values are:
<pre>
CPNoBorder
CPLineBorder
CPBezelBorder
CPGrooveBorder
</pre>
@param borderType the border type to use
*/
- (void)setBorderType:(CPBorderType)aBorderType
{
if (_borderType === aBorderType)
@@ -108,11 +145,41 @@ CPGrooveBorder = 3;
[self setNeedsDisplay:YES];
}
/*!
Returns the receiver's box type. Possible values are:
<pre>
CPBoxPrimary
CPBoxSecondary
CPBoxSeparator
CPBoxOldStyle
CPBoxCustom
</pre>
(In the current implementation, all values act the same except CPBoxSeparator.)
@return the box type of the box.
*/
- (CPBoxType)boxType
{
return _boxType;
}
/*!
Sets the receiver's box type. Valid values are:
<pre>
CPBoxPrimary
CPBoxSecondary
CPBoxSeparator
CPBoxOldStyle
CPBoxCustom
</pre>
(In the current implementation, all values act the same except CPBoxSeparator.)
@param aBoxType the box type of the box.
*/
- (void)setBoxType:(CPBoxType)aBoxType
{
if (_boxType === aBoxType)
@@ -235,8 +302,8 @@ CPGrooveBorder = 3;
switch (_boxType)
{
case CPBoxSeparator:
// NSBox does not include a horitontal flag for the seperator type. We have to determine
// the type of seperator to draw by the width and height of the frame.
// NSBox does not include a horizontal flag for the separator type. We have to determine
// the type of separator to draw by the width and height of the frame.
if (CGRectGetWidth(bounds) === 5.0)
return [self _drawVerticalSeperatorInRect:bounds];
else if (CGRectGetHeight(bounds) === 5.0)
+5 -3
View File
@@ -304,7 +304,7 @@
tableHeight = CGRectGetHeight([tableView bounds]);
[[tableView tableColumnWithIdentifier:"Image"] setWidth:_imageWidth];
[[tableView tableColumnWithIdentifier:"Content"] setWidth:width - (_leafWidth + _delegateSupportsImages ? _imageWidth : 0) - scrollerWidth - scrollerWidth];
[[tableView tableColumnWithIdentifier:"Content"] setWidth:[self columnContentWidthForColumnWidth:width]];
[[tableView tableColumnWithIdentifier:"Leaf"] setWidth:_leafWidth];
[tableView setRowHeight:_rowHeight];
@@ -436,12 +436,14 @@
- (float)columnContentWidthForColumnWidth:(float)aWidth
{
return aWidth - (_leafWidth + _delegateSupportsImages ? _imageWidth : 0) - [CPScroller scrollerWidth];
var columnSpacing = [_tableViews[0] intercellSpacing].width;
return aWidth - (_leafWidth + columnSpacing + (_delegateSupportsImages ? _imageWidth + columnSpacing : 0)) - columnSpacing - [CPScroller scrollerWidth];
}
- (float)columnWidthForColumnContentWidth:(float)aWidth
{
return aWidth + (_leafWidth + _delegateSupportsImages ? _imageWidth : 0) + [CPScroller scrollerWidth];
var columnSpacing = [_tableViews[0] intercellSpacing].width;
return aWidth + (_leafWidth + columnSpacing + (_delegateSupportsImages ? _imageWidth + columnSpacing: 0)) + columnSpacing + [CPScroller scrollerWidth];
}
- (void)setImageWidth:(float)aWidth
+91 -16
View File
@@ -106,6 +106,11 @@ CPButtonImageOffset = 3.0;
CPString _keyEquivalent;
unsigned _keyEquivalentModifierMask;
CPTimer _continuousDelayTimer;
CPTimer _continuousTimer;
float _periodicDelay;
float _periodicInterval;
}
+ (id)buttonWithTitle:(CPString)aTitle
@@ -152,18 +157,27 @@ CPButtonImageOffset = 3.0;
[self setValue:CPImageLeft forThemeAttribute:@"image-position"];
[self setValue:CPScaleNone forThemeAttribute:@"image-scaling"];
_controlSize = CPRegularControlSize;
_keyEquivalent = @"";
_keyEquivalentModifierMask = 0;
[self setBezelStyle:CPRoundRectBezelStyle];
[self setBordered:YES];
[self _init];
}
return self;
}
- (void)_init
{
_controlSize = CPRegularControlSize;
_keyEquivalent = @"";
_keyEquivalentModifierMask = 0;
// Continuous button defaults.
_periodicInterval = 0.05;
_periodicDelay = 0.5;
}
// Setting the state
/*!
Returns a Boolean value indicating whether the button allows a mixed state.
@@ -450,6 +464,34 @@ CPButtonImageOffset = 3.0;
return _imageDimsWhenDisabled;
}
- (void)setPeriodicDelay:(float)aDelay interval:(float)anInterval
{
_periodicDelay = aDelay;
_periodicInterval = anInterval;
}
- (void)mouseDown:(CPEvent)anEvent
{
if ([self isContinuous])
{
_continuousDelayTimer = [CPTimer scheduledTimerWithTimeInterval:_periodicDelay callback: function()
{
if (!_continuousTimer)
_continuousTimer = [CPTimer scheduledTimerWithTimeInterval:_periodicInterval target:self selector:@selector(onContinousEvent:) userInfo:anEvent repeats:YES];
}
repeats:NO];
}
[super mouseDown:anEvent];
}
- (void)onContinousEvent:(CPTimer)aTimer
{
if (_target && _action && [_target respondsToSelector:_action])
[_target performSelector:_action withObject:self];
}
- (BOOL)startTrackingAt:(CGPoint)aPoint
{
[self highlight:YES];
@@ -460,6 +502,7 @@ CPButtonImageOffset = 3.0;
- (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp
{
[self highlight:NO];
[self invalidateTimers];
[super stopTracking:lastPoint at:aPoint mouseIsUp:mouseIsUp];
@@ -467,6 +510,21 @@ CPButtonImageOffset = 3.0;
[self setNextState];
}
- (void)invalidateTimers
{
if (_continuousTimer)
{
[_continuousTimer invalidate];
_continuousTimer = nil;
}
if (_continuousDelayTimer)
{
[_continuousDelayTimer invalidate];
_continuousDelayTimer = nil;
}
}
- (CGRect)contentRectForBounds:(CGRect)bounds
{
var contentInset = [self currentValueForThemeAttribute:@"content-inset"];
@@ -502,14 +560,9 @@ CPButtonImageOffset = 3.0;
return bounds;
}
/*!
Adjust the size of the button to fit the title and surrounding button image.
*/
- (void)sizeToFit
- (CGSize)_minimumFrameSize
{
[self layoutSubviews];
var size,
var size = CGSizeMakeZero(),
contentView = [self ephemeralSubviewNamed:@"content-view"];
if (contentView)
@@ -533,9 +586,19 @@ CPButtonImageOffset = 3.0;
if (maxSize.height >= 0.0)
size.height = MIN(size.height, maxSize.height);
[self setFrameSize:size];
return size;
}
if (contentView)
/*!
Adjust the size of the button to fit the title and surrounding button image.
*/
- (void)sizeToFit
{
[self layoutSubviews];
[self setFrameSize:[self _minimumFrameSize]];
if ([self ephemeralSubviewNamed:@"content-view"])
[self layoutSubviews];
}
@@ -719,7 +782,9 @@ var CPButtonImageKey = @"CPButtonImageKey",
CPButtonImageDimsWhenDisabledKey = @"CPButtonImageDimsWhenDisabledKey",
CPButtonImagePositionKey = @"CPButtonImagePositionKey",
CPButtonKeyEquivalentKey = @"CPButtonKeyEquivalentKey",
CPButtonKeyEquivalentMaskKey = @"CPButtonKeyEquivalentMaskKey";
CPButtonKeyEquivalentMaskKey = @"CPButtonKeyEquivalentMaskKey",
CPButtonPeriodicDelayKey = @"CPButtonPeriodicDelayKey",
CPButtonPeriodicIntervalKey = @"CPButtonPeriodicIntervalKey";
@implementation CPButton (CPCoding)
@@ -733,7 +798,7 @@ var CPButtonImageKey = @"CPButtonImageKey",
if (self)
{
_controlSize = CPRegularControlSize;
[self _init];
_title = [aCoder decodeObjectForKey:CPButtonTitleKey];
_alternateTitle = [aCoder decodeObjectForKey:CPButtonAlternateTitleKey];
@@ -749,6 +814,12 @@ var CPButtonImageKey = @"CPButtonImageKey",
if ([aCoder containsValueForKey:CPButtonKeyEquivalentKey])
[self setKeyEquivalent:CFData.decodeBase64ToUtf16String([aCoder decodeObjectForKey:CPButtonKeyEquivalentKey])];
if ([aCoder containsValueForKey:CPButtonPeriodicDelayKey])
_periodicDelay = [aCoder decodeObjectForKey:CPButtonPeriodicDelayKey];
if ([aCoder containsValueForKey:CPButtonPeriodicIntervalKey])
_periodicInterval = [aCoder decodeObjectForKey:CPButtonPeriodicIntervalKey];
_keyEquivalentModifierMask = [aCoder decodeIntForKey:CPButtonKeyEquivalentMaskKey];
[self setNeedsLayout];
@@ -765,6 +836,7 @@ var CPButtonImageKey = @"CPButtonImageKey",
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[self invalidateTimers];
[aCoder encodeObject:_title forKey:CPButtonTitleKey];
[aCoder encodeObject:_alternateTitle forKey:CPButtonAlternateTitleKey];
@@ -778,6 +850,9 @@ var CPButtonImageKey = @"CPButtonImageKey",
[aCoder encodeObject:CFData.encodeBase64Utf16String(_keyEquivalent) forKey:CPButtonKeyEquivalentKey];
[aCoder encodeInt:_keyEquivalentModifierMask forKey:CPButtonKeyEquivalentMaskKey];
[aCoder encodeObject:_periodicDelay forKey:CPButtonPeriodicDelayKey];
[aCoder encodeObject:_periodicInterval forKey:CPButtonPeriodicIntervalKey];
}
@end
+83 -5
View File
@@ -131,6 +131,49 @@
/*!
Sets the item prototype to \c anItem
The item prototype should implement the CPCoding protocol
because the item is copied by archiving and unarchiving the
prototypal view.
Example:
<pre>
@implement MyCustomView : CPCollectionViewItem
{
CPArray items @accessors;
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
items = [];
}
return self;
}
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
items = [aCoder decodeObjectForKey:@"KEY"];
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[aCoder encodeObject:items forKey:@"KEY"];
[super encodeWithCoder:aCoder];
}
@end
</pre>
This will allow the collection view to create multiple 'clean' copies
of the item prototype which will maintain the original values for item
and all of the properties archived by the super class.
@param anItem the new item prototype
*/
- (void)setItemPrototype:(CPCollectionViewItem)anItem
@@ -343,7 +386,7 @@
_items = [];
if (!_itemPrototype || !_content)
if (!_itemPrototype)
return;
var index = 0;
@@ -369,7 +412,7 @@
{
var width = CGRectGetWidth([self bounds]);
if (![_content count] || width == _tileWidth)
if (width == _tileWidth)
return;
// We try to fit as many views per row as possible. Any remaining space is then
@@ -589,9 +632,7 @@
_mouseDownEvent = anEvent;
var location = [self convertPoint:[anEvent locationInWindow] fromView:nil],
row = FLOOR(location.y / (_itemSize.height + _verticalMargin)),
column = FLOOR(location.x / (_itemSize.width + _horizontalMargin)),
index = row * _numberOfColumns + column;
index = [self _indexAtPoint:location];
if (index >= 0 && index < _items.length)
{
@@ -727,6 +768,28 @@
return _delegate;
}
/*!
@ignore
*/
- (CPMenu)menuForEvent:(CPEvent)theEvent
{
if (![[self delegate] respondsToSelector:@selector(collectionView:menuForItemAtIndex:)])
return [super menuForEvent:theEvent];
var location = [self convertPoint:[theEvent locationInWindow] fromView:nil],
index = [self _indexAtPoint:location];
return [_delegate collectionView:self menuForItemAtIndex:index];
}
- (int)_indexAtPoint:(CGPoint)thePoint
{
var row = FLOOR(thePoint.y / (_itemSize.height + _verticalMargin)),
column = FLOOR(thePoint.x / (_itemSize.width + _horizontalMargin));
return row * _numberOfColumns + column;
}
- (CPCollectionViewItem)itemAtIndex:(unsigned)anIndex
{
return [_items objectAtIndex:anIndex];
@@ -898,6 +961,21 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeK
@implementation CPCollectionView (CPCoding)
- (void)awakeFromCib
{
[super awakeFromCib];
if (CGSizeEqualToSize(_minItemSize, CGSizeMakeZero()) || CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero()))
{
var item = _itemPrototype;
if (CGSizeEqualToSize(_minItemSize, CGSizeMakeZero()))
_minItemSize = [[item view] frameSize];
else if (CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero()))
_maxItemSize = [[item view] frameSize];
}
}
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
+115 -10
View File
@@ -27,6 +27,7 @@
@import "CPCompatibility.j"
@import "CPImage.j"
/// @cond IGNORE
var _redComponent = 0,
_greenComponent = 1,
@@ -54,6 +55,66 @@ var cachedBlackColor,
cachedShadowColor,
cachedClearColor;
/// @endcond
/*!
Orientation to use with \c CPColorPattern for vertical patterns.
*/
CPColorPatternIsVertical = YES;
/*!
Orientation to use with \c CPColorPattern for horizontal patterns.
*/
CPColorPatternIsHorizontal = NO;
/*!
To create a simple color with a pattern image:
<code>CPColorWithImages(name, width, height{, bundle})</code>
To create a color with a three part pattern image:
<code>CPColorWithImages(slices{, orientation})</code>
where slices is an array of three [name, width, height{, bundle}] arrays,
and orientation is \c CPColorPatternIsVertical or \ref CPColorPatternIsHorizontal.
If orientatation is not passed, it defaults to \ref CPColorPatternIsHorizontal.
To create a color with a nine part pattern image:
<code>CPColorWithImages(slices);</code>
where slices is an array of nine [name, width, height{, bundle}] arrays.
*/
function CPColorWithImages()
{
if (arguments.length < 3)
{
var slices = arguments[0],
imageSlices = [];
for (var i = 0; i < slices.length; ++i)
{
var slice = slices[i];
imageSlices.push(slice ? CPImageInBundle(slice[0], CGSizeMake(slice[1], slice[2]), slice[3]) : nil);
}
if (imageSlices.length === 3)
return [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:imageSlices isVertical:arguments[1] || CPColorPatternIsHorizontal]];
else
return [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:imageSlices]];
}
else if (arguments.length === 3 || arguments.length === 4)
{
return [CPColor colorWithPatternImage:CPImageInBundle(arguments[0], CGSizeMake(arguments[1], arguments[2]), arguments[3])];
}
else
{
return nil;
}
}
/*!
@ingroup appkit
@@ -125,7 +186,7 @@ var cachedBlackColor,
}
/*!
@deprecated in favor of colorWithWhite:apha:
@deprecated in favor of colorWithWhite:alpha:
Creates a new color object with \c white for the RGB components.
For the alpha component, a value of 1.0 is opaque, and 0.0 means completely transparent.
@@ -416,7 +477,7 @@ var cachedBlackColor,
parseInt(parts[0], 10) / 255.0,
parseInt(parts[1], 10) / 255.0,
parseInt(parts[2], 10) / 255.0,
parts[3] ? parseInt(parts[3], 10) / 255.0 : 1.0
parts[3] ? parseFloat(parts[3], 10) : 1.0
];
_cssString = aString;
@@ -605,7 +666,7 @@ url("data:image/png;base64,BASE64ENCODEDDATA") // if there is a pattern image
*/
- (CPString)hexString
{
return rgbToHex([self redComponent], [self greenComponent], [self blueComponent])
return rgbToHex([self redComponent], [self greenComponent], [self blueComponent]);
}
- (BOOL)isEqual:(CPColor)aColor
@@ -616,12 +677,53 @@ url("data:image/png;base64,BASE64ENCODEDDATA") // if there is a pattern image
if (aColor === self)
return YES;
return [aColor isKindOfClass:CPColor] && [aColor cssString] === [self cssString];
if (![aColor isKindOfClass:CPColor])
return NO;
if (_patternImage || [aColor patternImage])
return [_patternImage isEqual:[aColor patternImage]];
// We don't require the components to be equal beyond 8 bits since otherwise
// simple rounding errors will make two colours which are exactly the same on
// screen compare unequal.
return ROUND([self redComponent] * 255.0) == ROUND([aColor redComponent] * 255.0) &&
ROUND([self greenComponent] * 255.0) == ROUND([aColor greenComponent] * 255.0) &&
ROUND([self blueComponent] * 255.0) == ROUND([aColor blueComponent] * 255.0) &&
[self alphaComponent] == [aColor alphaComponent];
}
- (CPString)description
{
return [super description]+" "+[self cssString];
var description = [super description],
patternImage = [self patternImage];
if (!patternImage)
return description + " " + [self cssString];
description += " {\n";
if ([patternImage isThreePartImage] || [patternImage isNinePartImage])
{
var slices = [patternImage imageSlices];
if ([patternImage isThreePartImage])
description += " orientation: " + ([patternImage isVertical] ? "vertical" : "horizontal") + ",\n";
description += " patternImage (" + slices.length + " part): [\n";
for (var i = 0; i < slices.length; ++i)
{
var imgDescription = [slices[i] description];
description += imgDescription.replace(/^/mg, " ") + ",\n";
}
description = description.substr(0, description.length - 2) + "\n ]\n}";
}
else
description += [patternImage description].replace(/^/mg, " ") + "\n}";
return description;
}
@end
@@ -666,8 +768,10 @@ url("data:image/png;base64,BASE64ENCODEDDATA") // if there is a pattern image
@end
/// @cond IGNORE
var CPColorComponentsKey = @"CPColorComponentsKey",
CPColorPatternImageKey = @"CPColorPatternImageKey";
/// @endcond
@implementation CPColor (CPCoding)
@@ -698,13 +802,12 @@ var CPColorComponentsKey = @"CPColorComponentsKey",
@end
/// @cond IGNORE
var hexCharacters = "0123456789ABCDEF";
/*!
Used for the CPColor \c +colorWithHexString: implementation
@ignore
@class CPColor
@return an array of rgb components
/*
Used for the CPColor +colorWithHexString: implementation.
Returns an array of rgb components.
*/
var hexToRGB = function(hex)
{
@@ -742,3 +845,5 @@ var byteToHex = function(n)
return hexCharacters.charAt((n - n % 16) / 16) +
hexCharacters.charAt(n % 16);
};
/// @endcond
+3 -2
View File
@@ -51,7 +51,7 @@ CPWheelColorPickerMode = 1;
*/
CPSliderColorPickerMode = 2;
CPColorPickerViewWidth = 265,
CPColorPickerViewWidth = 265;
CPColorPickerViewHeight = 370;
/*!
@@ -131,7 +131,7 @@ CPColorPickerViewHeight = 370;
[self setFloatingPanel:YES];
[self setBecomesKeyOnlyIfNeeded:YES];
[self setMinSize:CGSizeMake(219.0, 342.0)];
[self setMinSize:CGSizeMake(219.0, 363.0)];
[self setMaxSize:CGSizeMake(323.0, 537.0)];
}
@@ -372,6 +372,7 @@ CPColorPickerViewHeight = 370;
[_opacitySlider setMinValue:0.0];
[_opacitySlider setMaxValue:1.0];
[_opacitySlider setAutoresizingMask:CPViewWidthSizable];
[_opacitySlider setTarget:self];
[_opacitySlider setAction:@selector(setOpacity:)];
+17 -13
View File
@@ -44,20 +44,20 @@ CPHTMLCanvasFeature = 1 << 6;
CPHTMLContentEditableFeature = 1 << 7;
CPHTMLDragAndDropFeature = 1 << 8;
CPJavascriptInnerTextFeature = 1 << 9;
CPJavascriptTextContentFeature = 1 << 10;
CPJavascriptClipboardEventsFeature = 1 << 11;
CPJavascriptClipboardAccessFeature = 1 << 12;
CPJavaScriptInnerTextFeature = 1 << 9;
CPJavaScriptTextContentFeature = 1 << 10;
CPJavaScriptClipboardEventsFeature = 1 << 11;
CPJavaScriptClipboardAccessFeature = 1 << 12;
CPJavaScriptCanvasDrawFeature = 1 << 13;
CPJavaScriptCanvasTransformFeature = 1 << 14;
CPVMLFeature = 1 << 15;
CPJavascriptRemedialKeySupport = 1 << 16;
CPJavaScriptRemedialKeySupport = 1 << 16;
CPJavaScriptShadowFeature = 1 << 20;
CPJavaScriptNegativeMouseWheelValues = 1 << 22;
CPJavaScriptMouseWheelValues_8_15 = 1 << 23
CPJavaScriptMouseWheelValues_8_15 = 1 << 23;
CPOpacityRequiresFilterFeature = 1 << 24;
@@ -65,6 +65,7 @@ CPOpacityRequiresFilterFeature = 1 << 24;
CPInputTypeCanBeChangedFeature = 1 << 25;
CPHTML5DragAndDropSourceYOffBy1 = 1 << 26;
CPSOPDisabledFromFileURLs = 1 << 27;
var USER_AGENT = "",
PLATFORM_ENGINE = CPUnknownBrowserEngine,
@@ -92,7 +93,7 @@ else if (typeof window !== "undefined" && window.attachEvent) // Must follow Ope
// Features we can only be sure of with IE (no known independent tests)
PLATFORM_FEATURES |= CPVMLFeature;
PLATFORM_FEATURES |= CPJavascriptRemedialKeySupport;
PLATFORM_FEATURES |= CPJavaScriptRemedialKeySupport;
PLATFORM_FEATURES |= CPJavaScriptShadowFeature;
PLATFORM_FEATURES |= CPOpacityRequiresFilterFeature;
@@ -112,8 +113,8 @@ else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
if (USER_AGENT.indexOf("Chrome") === -1)
PLATFORM_FEATURES |= CPHTMLDragAndDropFeature;
PLATFORM_FEATURES |= CPJavascriptClipboardEventsFeature;
PLATFORM_FEATURES |= CPJavascriptClipboardAccessFeature;
PLATFORM_FEATURES |= CPJavaScriptClipboardEventsFeature;
PLATFORM_FEATURES |= CPJavaScriptClipboardAccessFeature;
PLATFORM_FEATURES |= CPJavaScriptShadowFeature;
var versionStart = USER_AGENT.indexOf("AppleWebKit/") + "AppleWebKit/".length,
@@ -124,15 +125,18 @@ else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
minorVersion = parseInt(versionString.substr(versionDivision + 1));
if ((USER_AGENT.indexOf("Safari") !== CPNotFound && (majorVersion > 525 || (majorVersion === 525 && minorVersion > 14))) || USER_AGENT.indexOf("Chrome") !== CPNotFound)
PLATFORM_FEATURES |= CPJavascriptRemedialKeySupport;
PLATFORM_FEATURES |= CPJavaScriptRemedialKeySupport;
// FIXME this is a terrible hack to get around this bug:
// https://bugs.webkit.org/show_bug.cgi?id=21548
if (![CPPlatform isBrowser])
PLATFORM_FEATURES |= CPJavascriptRemedialKeySupport;
PLATFORM_FEATURES |= CPJavaScriptRemedialKeySupport;
if (majorVersion < 532 || (majorVersion === 532 && minorVersion < 6))
PLATFORM_FEATURES |= CPHTML5DragAndDropSourceYOffBy1;
if (USER_AGENT.indexOf("Chrome") === CPNotFound)
PLATFORM_FEATURES |= CPSOPDisabledFromFileURLs;
}
// KHTML
@@ -178,9 +182,9 @@ if (typeof document != "undefined")
// Detect whether we have innerText or textContent (or neither)
if (DOMElement.innerText != undefined)
PLATFORM_FEATURES |= CPJavascriptInnerTextFeature;
PLATFORM_FEATURES |= CPJavaScriptInnerTextFeature;
else if (DOMElement.textContent != undefined)
PLATFORM_FEATURES |= CPJavascriptTextContentFeature;
PLATFORM_FEATURES |= CPJavaScriptTextContentFeature;
}
function CPFeatureIsCompatible(aFeature)
+226 -70
View File
@@ -20,12 +20,14 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#import "../Foundation/Ref.h"
@import "../Foundation/CPFormatter.j"
@import "CPFont.j"
@import "CPShadow.j"
@import "CPView.j"
@import "CPKeyValueBinding.j"
CPLeftTextAlignment = 0;
CPRightTextAlignment = 1;
CPCenterTextAlignment = 2;
@@ -43,21 +45,21 @@ CPLineBreakByTruncatingHead = 3;
CPLineBreakByTruncatingTail = 4;
CPLineBreakByTruncatingMiddle = 5;
CPTopVerticalTextAlignment = 1,
CPCenterVerticalTextAlignment = 2,
CPTopVerticalTextAlignment = 1;
CPCenterVerticalTextAlignment = 2;
CPBottomVerticalTextAlignment = 3;
CPScaleProportionally = 0;
CPScaleToFit = 1;
CPScaleNone = 2;
CPScaleProportionally = 0;
CPScaleToFit = 1;
CPScaleNone = 2;
CPNoImage = 0;
CPImageOnly = 1;
CPImageLeft = 2;
CPImageRight = 3;
CPImageBelow = 4;
CPImageAbove = 5;
CPImageOverlaps = 6;
CPNoImage = 0;
CPImageOnly = 1;
CPImageLeft = 2;
CPImageRight = 3;
CPImageBelow = 4;
CPImageAbove = 5;
CPImageOverlaps = 6;
CPOnState = 1;
CPOffState = 0;
@@ -72,7 +74,7 @@ CPControlTextDidBeginEditingNotification = "CPControlTextDidBeginEditingNotif
CPControlTextDidChangeNotification = "CPControlTextDidChangeNotification";
CPControlTextDidEndEditingNotification = "CPControlTextDidEndEditingNotification";
var CPControlBlackColor = [CPColor blackColor];
var CPControlBlackColor = [CPColor blackColor];
/*!
@ingroup appkit
@@ -83,6 +85,7 @@ var CPControlBlackColor = [CPColor blackColor];
@implementation CPControl : CPView
{
id _value;
CPFormatter _formatter @accessors(property=formatter);
// Target-Action Support
id _target;
@@ -95,8 +98,6 @@ var CPControlBlackColor = [CPColor blackColor];
BOOL _trackingWasWithinFrame;
unsigned _trackingMouseDownFlags;
CGPoint _previousTrackingLocation;
CPString _toolTip;
}
+ (CPDictionary)themeAttributes
@@ -149,6 +150,18 @@ var CPControlBlackColor = [CPColor blackColor];
return [super _binderClassForBinding:theBinding];
}
/*!
Reverse set the binding iff the CPContinuouslyUpdatesValueBindingOption is set.
*/
- (void)_continuouslyReverseSetBinding
{
var binderClass = [[self class] _binderClassForBinding:CPValueBinding],
theBinding = [binderClass getBinding:CPValueBinding forObject:self];
if ([theBinding continuouslyUpdatesValue])
[theBinding reverseSetValueFor:@"objectValue"];
}
- (void)_reverseSetBinding
{
var binderClass = [[self class] _binderClassForBinding:CPValueBinding],
@@ -171,7 +184,8 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Sets the receiver's target action
Sets the receiver's target action.
@param anAction Sets the action message that gets sent to the target.
*/
- (void)setAction:(SEL)anAction
@@ -180,7 +194,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Returns the receiver's target action
Returns the receiver's target action.
*/
- (SEL)action
{
@@ -189,6 +203,7 @@ var CPControlBlackColor = [CPColor blackColor];
/*!
Sets the receiver's target. The target receives action messages from the receiver.
@param aTarget the object that will receive the message specified by action
*/
- (void)setTarget:(id)aTarget
@@ -206,13 +221,15 @@ var CPControlBlackColor = [CPColor blackColor];
/*!
Causes \c anAction to be sent to \c anObject.
@param anAction the action to send
@param anObject the object to which the action will be sent
*/
- (void)sendAction:(SEL)anAction to:(id)anObject
- (BOOL)sendAction:(SEL)anAction to:(id)anObject
{
[self _reverseSetBinding];
[CPApp sendAction:anAction to:anObject from:self];
return [CPApp sendAction:anAction to:anObject from:self];
}
- (int)sendActionOn:(int)mask
@@ -224,33 +241,6 @@ var CPControlBlackColor = [CPColor blackColor];
return previousMask;
}
/*!
Sets the tooltip for the receiver.
@param aToolTip the tooltip
*/
/*
-(void)setToolTip:(CPString)aToolTip
{
if (_toolTip == aToolTip)
return;
_toolTip = aToolTip;
#if PLATFORM(DOM)
_DOMElement.title = aToolTip;
#endif
}
*/
/*!
Returns the receiver's tooltip
*/
/*
-(CPString)toolTip
{
return _toolTip;
}
*/
/*!
Returns whether the control can continuously send its action messages.
*/
@@ -262,7 +252,7 @@ var CPControlBlackColor = [CPColor blackColor];
/*!
Sets whether the cell can continuously send its action messages.
*/
*/
- (void)setContinuous:(BOOL)flag
{
// Some subclasses should redefine this with CPLeftMouseDraggedMask
@@ -272,6 +262,9 @@ var CPControlBlackColor = [CPColor blackColor];
_sendActionOn &= ~CPPeriodicMask;
}
/*!
Returns YES if the receiver tracks the mouse outside the frame, otherwise NO.
*/
- (BOOL)tracksMouseOutsideOfFrame
{
return NO;
@@ -334,6 +327,11 @@ var CPControlBlackColor = [CPColor blackColor];
return 0;
}
/*!
Perform a click on the receiver.
@param sender - The sender object
*/
- (void)performClick:(id)sender
{
if (![self isEnabled])
@@ -356,11 +354,18 @@ var CPControlBlackColor = [CPColor blackColor];
}
}
/*!
@ignore
Fired when the button timer finished, usually after the user hits enter.
*/
- (void)unhighlightButtonTimerDidFinish:(id)sender
{
[self highlight:NO];
}
/*!
Returns the mask of modifier keys held down when the user clicked.
*/
- (unsigned)mouseDownFlags
{
return _trackingMouseDownFlags;
@@ -411,7 +416,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Returns the receiver's object value
Returns the receiver's object value.
*/
- (id)objectValue
{
@@ -419,7 +424,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Set's the receiver's object value
Sets the receiver's object value.
*/
- (void)setObjectValue:(id)anObject
{
@@ -430,7 +435,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Returns the receiver's float value
Returns the receiver's float value.
*/
- (float)floatValue
{
@@ -439,7 +444,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Sets the receiver's float value
Sets the receiver's float value.
*/
- (void)setFloatValue:(float)aValue
{
@@ -447,7 +452,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Returns the receiver's double value
Returns the receiver's double value.
*/
- (double)doubleValue
{
@@ -456,7 +461,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Set's the receiver's double value
Sets the receiver's double value.
*/
- (void)setDoubleValue:(double)anObject
{
@@ -464,7 +469,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Returns the receiver's int value
Returns the receiver's int value.
*/
- (int)intValue
{
@@ -473,7 +478,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Set's the receiver's int value
Sets the receiver's int value.
*/
- (void)setIntValue:(int)anObject
{
@@ -481,7 +486,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Returns the receiver's int value
Returns the receiver's int value.
*/
- (int)integerValue
{
@@ -490,7 +495,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Set's the receiver's int value
Sets the receiver's int value.
*/
- (void)setIntegerValue:(int)anObject
{
@@ -498,19 +503,50 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Returns the receiver's string value
Returns the receiver's string value.
*/
- (CPString)stringValue
{
if (_formatter && _value !== undefined && _value !== nil)
{
var formattedValue = [self hasThemeState:CPThemeStateEditing] ? [_formatter editingStringForObjectValue:_value] : [_formatter stringForObjectValue:_value];
if (formattedValue !== nil && formattedValue !== undefined)
return formattedValue;
}
return (_value === undefined || _value === nil) ? "" : String(_value);
}
/*!
Set's the receiver's string value
Sets the receiver's string value.
*/
- (void)setStringValue:(CPString)anObject
- (void)setStringValue:(CPString)aString
{
[self setObjectValue:anObject];
// Cocoa raises an invalid parameter assertion and returns if you pass nil.
if (aString === nil || aString === undefined)
{
CPLog.warn("nil sent to CPControl -setStringValue");
return;
}
var value;
if (_formatter)
{
value = nil;
if ([_formatter getObjectValue:AT_REF(value) forString:aString errorDescription:nil] === NO)
{
// If the given string is non-empty and doesn't work, Cocoa tries an empty string.
if (!aString || [_formatter getObjectValue:AT_REF(value) forString:@"" errorDescription:nil] === NO)
value = undefined; // Means the value is invalid
}
}
else
value = aString;
[self setObjectValue:value];
}
- (void)takeDoubleValueFrom:(id)sender
@@ -526,21 +562,18 @@ var CPControlBlackColor = [CPColor blackColor];
[self setFloatValue:[sender floatValue]];
}
- (void)takeIntegerValueFrom:(id)sender
{
if ([sender respondsToSelector:@selector(integerValue)])
[self setIntegerValue:[sender integerValue]];
}
- (void)takeIntValueFrom:(id)sender
{
if ([sender respondsToSelector:@selector(intValue)])
[self setIntValue:[sender intValue]];
}
- (void)takeObjectValueFrom:(id)sender
{
if ([sender respondsToSelector:@selector(objectValue)])
@@ -582,96 +615,199 @@ var CPControlBlackColor = [CPColor blackColor];
[[CPNotificationCenter defaultCenter] postNotificationName:CPControlTextDidEndEditingNotification object:self userInfo:[CPDictionary dictionaryWithObject:[note object] forKey:"CPFieldEditor"]];
}
/*!
Sets the text alignment of the control.
<pre>
CPLeftTextAlignment
CPCenterTextAlignment
CPRightTextAlignment
CPJustifiedTextAlignment
CPNaturalTextAlignment
</pre>
*/
- (void)setAlignment:(CPTextAlignment)alignment
{
[self setValue:alignment forThemeAttribute:@"alignment"];
}
/*!
Returns the text alignment of the control.
*/
- (CPTextAlignment)alignment
{
return [self valueForThemeAttribute:@"alignment"];
}
/*!
Set the vertical text alignment of the control.
<pre>
CPTopVerticalTextAlignment
CPCenterVerticalTextAlignment
CPBottomVerticalTextAlignment
</pre>
*/
- (void)setVerticalAlignment:(CPTextVerticalAlignment)alignment
{
[self setValue:alignment forThemeAttribute:@"vertical-alignment"];
}
/*!
Returns the vertical text alignment of the receiver.
*/
- (CPTextVerticalAlignment)verticalAlignment
{
return [self valueForThemeAttribute:@"vertical-alignment"];
}
/*!
Sets the line break mode of the receiver.
<pre>
CPLineBreakByWordWrapping
CPLineBreakByCharWrapping
CPLineBreakByClipping
CPLineBreakByTruncatingHead
CPLineBreakByTruncatingTail
CPLineBreakByTruncatingMiddle
</pre>
*/
- (void)setLineBreakMode:(CPLineBreakMode)mode
{
[self setValue:mode forThemeAttribute:@"line-break-mode"];
}
/*!
Returns the line break mode of the control.
*/
- (CPLineBreakMode)lineBreakMode
{
return [self valueForThemeAttribute:@"line-break-mode"];
}
/*!
Sets the text color of the receiver.
@param aColor - A CPColor object.
*/
- (void)setTextColor:(CPColor)aColor
{
[self setValue:aColor forThemeAttribute:@"text-color"];
}
/*!
Returns the text color of the receiver.
*/
- (CPColor)textColor
{
return [self valueForThemeAttribute:@"text-color"];
}
/*!
Sets the shadow color of the text for the receiver.
*/
- (void)setTextShadowColor:(CPColor)aColor
{
[self setValue:aColor forThemeAttribute:@"text-shadow-color"];
}
/*!
Returns the shadow color of the text for the control.
*/
- (CPColor)textShadowColor
{
return [self valueForThemeAttribute:@"text-shadow-color"];
}
- (void)setTextShadowOffset:(float)offset
/*!
Sets the shadow offset for the text.
@param offset - a CGSize with the x and y offsets.
*/
- (void)setTextShadowOffset:(CGSize)offset
{
[self setValue:offset forThemeAttribute:@"text-shadow-offset"];
}
- (float)textShadowOffset
/*!
Returns the text shadow offset of the receiver.
*/
- (CGSize)textShadowOffset
{
return [self valueForThemeAttribute:@"text-shadow-offset"];
}
/*!
Sets the font of the control.
*/
- (void)setFont:(CPFont)aFont
{
[self setValue:aFont forThemeAttribute:@"font"];
}
/*!
Returns the font of the control.
*/
- (CPFont)font
{
return [self valueForThemeAttribute:@"font"];
}
/*!
Sets the image position of the control.
<pre>
CPNoImage
CPImageOnly
CPImageLeft
CPImageRight
CPImageBelow
CPImageAbove
CPImageOverlaps
</pre>
*/
- (void)setImagePosition:(CPCellImagePosition)position
{
[self setValue:position forThemeAttribute:@"image-position"];
}
/*!
Returns the image position of the receiver.
*/
- (CPCellImagePosition)imagePosition
{
return [self valueForThemeAttribute:@"image-position"];
}
/*!
Sets the image scaling of the control.
<pre>
CPScaleProportionally
CPScaleToFit
CPScaleNone
</pre>
*/
- (void)setImageScaling:(CPImageScaling)scaling
{
[self setValue:scaling forThemeAttribute:@"image-scaling"];
}
/*!
Returns the image scaling of the control.
*/
- (CPImageScaling)imageScaling
{
return [self valueForThemeAttribute:@"image-scaling"];
}
/*!
Sets the enabled status of the control.
Controls that are not enabled can not be used by the user and obtain the CPThemeStateDisabled theme state.
@param BOOL - YES if the control should be enabled, otherwise NO.
*/
- (void)setEnabled:(BOOL)isEnabled
{
if (isEnabled)
@@ -680,16 +816,29 @@ var CPControlBlackColor = [CPColor blackColor];
[self setThemeState:CPThemeStateDisabled];
}
/*!
Returns YES if the receiver is enabled, otherwise NO.
*/
- (BOOL)isEnabled
{
return ![self hasThemeState:CPThemeStateDisabled];
}
/*!
Highlights the receiver.
@param BOOL - YES if the receiver should be highlighted, otherwise NO.
*/
- (void)highlight:(BOOL)shouldHighlight
{
[self setHighlighted:shouldHighlight];
}
/*!
Highlights the receiver.
@param BOOL - YES if the receiver should be highlighted, otherwise NO.
*/
- (void)setHighlighted:(BOOL)isHighlighted
{
if (isHighlighted)
@@ -698,6 +847,9 @@ var CPControlBlackColor = [CPColor blackColor];
[self unsetThemeState:CPThemeStateHighlighted];
}
/*!
Returns YES if the control is highlighted, otherwise NO.
*/
- (BOOL)isHighlighted
{
return [self hasThemeState:CPThemeStateHighlighted];
@@ -721,6 +873,7 @@ var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
/*
Initializes the control by unarchiving it from a coder.
@param aCoder the coder from which to unarchive the control
@return the initialized control
*/
@@ -744,6 +897,7 @@ var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
/*
Archives the control to the provided coder.
@param aCoder the coder to which the control will be archived.
*/
- (void)encodeWithCoder:(CPCoder)aCoder
@@ -753,13 +907,15 @@ var __Deprecated__CPImageViewImageKey = @"CPImageViewImageKey";
if (_sendsActionOnEndEditing)
[aCoder encodeBool:_sendsActionOnEndEditing forKey:CPControlSendsActionOnEndEditingKey];
if (_value !== nil)
[aCoder encodeObject:_value forKey:CPControlValueKey];
var objectValue = [self objectValue];
if (objectValue !== nil)
[aCoder encodeObject:objectValue forKey:CPControlValueKey];
if (_target !== nil)
[aCoder encodeConditionalObject:_target forKey:CPControlTargetKey];
if (_action !== NULL)
if (_action !== nil)
[aCoder encodeObject:_action forKey:CPControlActionKey];
[aCoder encodeInt:_sendActionOn forKey:CPControlSendActionOnKey];
+1 -1
View File
@@ -50,7 +50,7 @@ var CPControllerDeclaredKeysKey = @"CPControllerDeclaredKeysKey";
_declaredKeys = [aDecoder decodeObjectForKey:CPControllerDeclaredKeysKey] || [];
}
return nil;
return self;
}
- (BOOL)isEditing
+174 -203
View File
@@ -1,36 +1,41 @@
/*
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
Cursor support by browser:
OS X 10.6/Chrome 8 : All
OS X 10.6/Safari 5 : All
OS X 10.6/Firefox 3 : All except disappearingItemCursor (no url() support)
OS X 10.6/Firefox 3.5 : All except disappearingItemCursor (no url() support)
OS X 10.6/Firefox 3.6 : All except disappearingItemCursor, contextualMenuCursor, dragLinkCursor, dragCopyCursor, operationNotAllowedCursor (no url() support)
OS X 10.6/Firefox 4.0b10 : All
OS X/Opera 9 : All except disappearingItemCursor, closedHandCursor, openHandCursor, contextualMenuCursor, dragLinkCursor, dragCopyCursor, operationNotAllowedCursor, resizeUpDownCursor, resizeLeftRightCursor (no url() support)
OS X/Opera 10 : All except disappearingItemCursor, closedHandCursor, contextualMenuCursor, dragLinkCursor, dragCopyCursor, operationNotAllowedCursor (no url() support)
OS X/Opera 11 : All except disappearingItemCursor, closedHandCursor, contextualMenuCursor, dragLinkCursor, dragCopyCursor, operationNotAllowedCursor (no url() support)
Win XP/Chrome 8 : All
Win XP/Safari 5 : All
Win XP/Firefox 3 : All
Win XP/Firefox 3.5 : All
Win XP/Firefox 3.6 : All
Win XP/Firefox 4.0b10 : All
Win XP/Opera 10 : All except disappearingItemCursor, closedHandCursor, openHandCursor, contextualMenuCursor, dragLinkCursor, dragCopyCursor, operationNotAllowedCursor, resizeUpDownCursor, resizeLeftRightCursor (no url() support)
Win XP/Opera 11 : All except disappearingItemCursor, closedHandCursor, openHandCursor, contextualMenuCursor, dragLinkCursor, dragCopyCursor, operationNotAllowedCursor, resizeUpDownCursor, resizeLeftRightCursor (no url() support)
Win XP/IE 7 : All
Win XP/IE 8 : All
*/
@import <Foundation/CPObject.j>
var currentCursor = nil,
cursorStack = [],
cursors = {},
cursorURLFormat = nil;
cursors = {};
@implementation CPCursor : CPObject
{
CPString _cssString;
CPString _cssString @accessors(readonly);
CPString _hotSpot @accessors(readonly, getter=hotSpot);
CPImage _image @accessors(readonly, getter=image);
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])
@@ -39,155 +44,18 @@ var currentCursor = nil,
return self;
}
+ (CPCursor)cursorWithCSSString:(CPString)cssString
// hotspot is supported in CSS3 (but not IE).
- (id)initWithImage:(CPImage)image hotSpot:(CPPoint)hotSpot
{
var cursor = cursors[cssString];
if (typeof cursor == 'undefined')
{
cursor = [[CPCursor alloc] initWithCSSString:cssString];
cursors[cssString] = cursor;
}
return cursor;
_hotSpot = hotSpot;
_image = image;
return [self initWithCSSString:"url(" + [_image filename] + ")" + hotSpot.x + " " + hotSpot.y + ", auto"];
}
+ (CPCursor)cursorWithImageNamed:(CPString)imageName
// foregroundColor and backgroundColor are ignored in Cocoa as well. See http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/NSCursor_Class/Reference/Reference.html
- (id)initWithImage:(CPImage)image foregroundColorHint:(CPColor)foregroundColor backgroundColorHint:(CPColor)backgroundColor hotSpot:(CPPoint)aHotSpot
{
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))
return [CPCursor cursorWithCSSString:@"-moz-grab"];
else if (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"];
else if (CPBrowserIsEngine(CPGeckoBrowserEngine))
return [CPCursor cursorWithCSSString:@"-moz-grabbing"];
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)]; // WebKit || FF
}
+ (CPCursor)disappearingItemCursor
{
return [CPCursor cursorWithImageNamed:CPStringFromSelector(_cmd)]; // None
return [self initWithImage:image hotSpot:hotSpot];
}
+ (void)hide
@@ -208,44 +76,6 @@ var currentCursor = nil,
[CPCursor unhide];
}
- (id)initWithImage:(CPImage)image hotSpot:(CPPoint)hotSpot
{
return [self initWithCSSString:"url(" + [image filename] + "), auto"];
}
- (void)mouseEntered:(CPEvent)event
{
}
- (void)mouseExited:(CPEvent)event
{
}
- (void)set
{
currentCursor = self;
#if PLATFORM(DOM)
[[self class] _setCursorCSS:_cssString];
#endif
}
+ (void)_setCursorCSS:(CPString)aString
{
#if PLATFORM(DOM)
var platformWindows = [[CPPlatformWindow visiblePlatformWindows] allObjects];
for (var i = 0, count = [platformWindows count]; i < count; i++)
platformWindows[i]._DOMBodyElement.style.cursor = aString;
#endif
}
- (void)push
{
currentCursor = cursorStack.push(self);
}
- (void)pop
{
[CPCursor pop];
@@ -260,6 +90,148 @@ var currentCursor = nil,
}
}
- (void)push
{
currentCursor = cursorStack.push(self);
}
- (void)set
{
currentCursor = self;
#if PLATFORM(DOM)
[[self class] _setCursorCSS:_cssString];
#endif
}
- (void)mouseEntered:(CPEvent)event
{
}
- (void)mouseExited:(CPEvent)event
{
}
+ (CPCursor)currentCursor
{
return currentCursor;
}
+ (void)_setCursorCSS:(CPString)aString
{
#if PLATFORM(DOM)
var platformWindows = [[CPPlatformWindow visiblePlatformWindows] allObjects];
for (var i = 0, count = [platformWindows count]; i < count; i++)
platformWindows[i]._DOMBodyElement.style.cursor = aString;
#endif
}
// Internal method that is used to return the system cursors. Caches the system cursors for performance.
+ (CPCursor)_systemCursorWithName:(CPString)cursorName cssString:(CPString)aString hasImage:(BOOL)doesHaveImage
{
var cursor = cursors[cursorName];
if (typeof cursor === 'undefined')
{
var cssString;
if (doesHaveImage)
cssString = @"url(" + [[CPBundle bundleForClass:self] resourcePath] + @"/CPCursor/" + cursorName + ".cur), " + aString;
else
cssString = aString
cursor = [[CPCursor alloc] initWithCSSString:cssString];
cursors[cursorName] = cursor;
}
return cursor;
}
+ (CPCursor)arrowCursor
{
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:"default" hasImage:NO];
}
+ (CPCursor)crosshairCursor
{
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"crosshair" hasImage:NO];
}
+ (CPCursor)IBeamCursor
{
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"text" hasImage:NO];
}
+ (CPCursor)pointingHandCursor
{
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"pointer" hasImage:NO];
}
+ (CPCursor)resizeDownCursor
{
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"s-resize" hasImage:NO];
}
+ (CPCursor)resizeUpCursor
{
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"n-resize" hasImage:NO];
}
+ (CPCursor)resizeLeftCursor
{
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"w-resize" hasImage:NO];
}
+ (CPCursor)resizeRightCursor
{
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"e-resize" hasImage:NO];
}
+ (CPCursor)resizeLeftRightCursor
{
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"col-resize" hasImage:NO];
}
+ (CPCursor)resizeUpDownCursor
{
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"row-resize" hasImage:NO];
}
+ (CPCursor)operationNotAllowedCursor
{
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"not-allowed" hasImage:NO];
}
+ (CPCursor)dragCopyCursor
{
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"copy" hasImage:YES];
}
+ (CPCursor)dragLinkCursor
{
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"alias" hasImage:YES];
}
+ (CPCursor)contextualMenuCursor
{
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"context-menu" hasImage:YES];
}
+ (CPCursor)openHandCursor
{
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"move" hasImage:YES];
}
+ (CPCursor)closedHandCursor
{
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"-moz-grabbing" hasImage:YES];
}
+ (CPCursor)disappearingItemCursor
{
return [CPCursor _systemCursorWithName:CPStringFromSelector(_cmd) cssString:@"auto" hasImage:YES];
}
@end
@implementation CPCursor(CPCoding)
- (id)initWithCoder:(CPCoder)coder
{
if (self = [super init])
@@ -274,4 +246,3 @@ var currentCursor = nil,
}
@end
+2 -2
View File
@@ -88,7 +88,7 @@ var CPDocumentUntitledCount = 0;
@class CPDocument
CPDocument is used to represent a document/file in a Cappuccino application.
In a document-based application, generally multiple documents are open simutaneously
In a document-based application, generally multiple documents are open simultaneously
(multiple text documents, slide presentations, spreadsheets, etc.), and multiple
CPDocuments should be used to represent this.
*/
@@ -208,7 +208,7 @@ var CPDocumentUntitledCount = 0;
throws an exception.
@param aType the format of the data
@param anError not used
@throws CPUnsupportedMethodException if this method hasn't been overriden by the subclass
@throws CPUnsupportedMethodException if this method hasn't been overridden by the subclass
@return the document data
*/
- (CPData)dataOfType:(CPString)aType error:({CPError})anError
+2 -2
View File
@@ -24,7 +24,7 @@
@import <Foundation/CPBundle.j>
@import "CPDocument.j"
@import "CPOpenPanel.j";
@import "CPOpenPanel.j"
var CPSharedDocumentController = nil;
@@ -177,7 +177,7 @@ var CPSharedDocumentController = nil;
@param aType the document type
@param aDelegate the delegate to notify
@param aSelector the selector to notify with
@param aContextInfo the context infomration passed to the delegate
@param aContextInfo the context information passed to the delegate
*/
- (CPDocument)makeDocumentWithContentsOfURL:(CPURL)anAbsoluteURL ofType:(CPString)aType delegate:(id)aDelegate didReadSelector:(SEL)aSelector contextInfo:(id)aContextInfo
{
+23 -19
View File
@@ -28,13 +28,13 @@
@import "CPWindow.j"
CPDragOperationNone = 0,
CPDragOperationCopy = 1 << 1,
CPDragOperationLink = 1 << 1,
CPDragOperationGeneric = 1 << 2,
CPDragOperationPrivate = 1 << 3,
CPDragOperationMove = 1 << 4,
CPDragOperationDelete = 1 << 5,
CPDragOperationNone = 0;
CPDragOperationCopy = 1 << 1;
CPDragOperationLink = 1 << 1;
CPDragOperationGeneric = 1 << 2;
CPDragOperationPrivate = 1 << 3;
CPDragOperationMove = 1 << 4;
CPDragOperationDelete = 1 << 5;
CPDragOperationEvery = -1;
#define DRAGGING_WINDOW(anObject) ([anObject isKindOfClass:[CPWindow class]] ? anObject : [anObject window])
@@ -44,8 +44,8 @@ var CPDragServerPreviousEvent = nil,
var CPSharedDragServer = nil;
var CPDragServerSource = nil;
var CPDragServerDraggingInfo = nil;
var CPDragServerSource = nil,
CPDragServerDraggingInfo = nil;
/*
CPDraggingInfo is a container of information about a specific dragging session.
@@ -261,7 +261,7 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
{
var contentView = [scrollView contentView],
bounds = [contentView bounds],
insetBounds = CGRectInset(bounds, 10, 10),
insetBounds = CGRectInset(bounds, 30, 30),
eventLocation = [contentView convertPoint:_draggingLocation fromView:nil],
deltaX = 0,
deltaY = 0;
@@ -270,10 +270,10 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
{
if ([scrollView hasVerticalScroller])
{
if (eventLocation.y < CGRectGetMinY(insetBounds))
deltaY = CGRectGetMinY(insetBounds) - eventLocation.y;
else if (eventLocation.y > CGRectGetMaxY(insetBounds))
deltaY = CGRectGetMaxY(insetBounds) - eventLocation.y;
if (eventLocation.y < _CGRectGetMinY(insetBounds))
deltaY = _CGRectGetMinY(insetBounds) - eventLocation.y;
else if (eventLocation.y > _CGRectGetMaxY(insetBounds))
deltaY = _CGRectGetMaxY(insetBounds) - eventLocation.y;
if (deltaY < -insetBounds.size.height)
deltaY = -insetBounds.size.height;
if (deltaY > insetBounds.size.height)
@@ -282,17 +282,21 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
if ([scrollView hasHorizontalScroller])
{
if (eventLocation.x < CGRectGetMinX(insetBounds))
deltaX = CGRectGetMinX(insetBounds) - eventLocation.x;
else if (eventLocation.x > CGRectGetMaxX(insetBounds))
deltaX = CGRectGetMaxX(insetBounds) - eventLocation.x;
if (eventLocation.x < _CGRectGetMinX(insetBounds))
deltaX = _CGRectGetMinX(insetBounds) - eventLocation.x;
else if (eventLocation.x > _CGRectGetMaxX(insetBounds))
deltaX = _CGRectGetMaxX(insetBounds) - eventLocation.x;
if (deltaX < -insetBounds.size.width)
deltaX = -insetBounds.size.width;
if (deltaX > insetBounds.size.width)
deltaX = insetBounds.size.width;
}
[contentView scrollToPoint:CGPointMake(bounds.origin.x - deltaX, bounds.origin.y - deltaY)];
var scrollPoint = _CGPointMake(bounds.origin.x - deltaX, bounds.origin.y - deltaY);
[contentView scrollToPoint:scrollPoint];
[[scrollView _headerView] scrollPoint:scrollPoint];
}
}
}
+70 -61
View File
@@ -161,21 +161,21 @@ CPEscapeFunctionKey = "\u001B";
CPSpaceFunctionKey = "\u0020";
CPDOMEventDoubleClick = "dblclick",
CPDOMEventMouseDown = "mousedown",
CPDOMEventMouseUp = "mouseup",
CPDOMEventMouseMoved = "mousemove",
CPDOMEventMouseDragged = "mousedrag",
CPDOMEventKeyUp = "keyup",
CPDOMEventKeyDown = "keydown",
CPDOMEventKeyPress = "keypress";
CPDOMEventCopy = "copy";
CPDOMEventPaste = "paste";
CPDOMEventScrollWheel = "mousewheel";
CPDOMEventTouchStart = "touchstart";
CPDOMEventTouchMove = "touchmove";
CPDOMEventTouchEnd = "touchend";
CPDOMEventTouchCancel = "touchcancel";
CPDOMEventDoubleClick = "dblclick";
CPDOMEventMouseDown = "mousedown";
CPDOMEventMouseUp = "mouseup";
CPDOMEventMouseMoved = "mousemove";
CPDOMEventMouseDragged = "mousedrag";
CPDOMEventKeyUp = "keyup";
CPDOMEventKeyDown = "keydown";
CPDOMEventKeyPress = "keypress";
CPDOMEventCopy = "copy";
CPDOMEventPaste = "paste";
CPDOMEventScrollWheel = "mousewheel";
CPDOMEventTouchStart = "touchstart";
CPDOMEventTouchMove = "touchmove";
CPDOMEventTouchEnd = "touchend";
CPDOMEventTouchCancel = "touchcancel";
var _CPEventPeriodicEventPeriod = 0,
_CPEventPeriodicEventTimer = nil,
@@ -211,6 +211,7 @@ var _CPEventPeriodicEventPeriod = 0,
/*!
Creates a new keyboard event.
@param anEventType the event type. Must be one of CPKeyDown, CPKeyUp or CPFlagsChanged
@param aPoint the location of the cursor in the window specified by \c aWindowNumber
@param modifierFlags a bitwise combination of the modifiers specified in the CPEvent globals
@@ -235,7 +236,8 @@ var _CPEventPeriodicEventPeriod = 0,
}
/*!
Creates a new mouse event
Creates a new mouse event.
@param anEventType the event type
@param aPoint the location of the cursor in the window specified by \c aWindowNumber
@param modifierFlags a bitwise combination of the modifiers specified in the CPEvent globals
@@ -257,7 +259,8 @@ var _CPEventPeriodicEventPeriod = 0,
}
/*!
Creates a new custom event
Creates a new custom event.
@param anEventType the event type. Must be one of CPAppKitDefined, CPSystemDefined, CPApplicationDefined or CPPeriodic
@param aLocation the location of the cursor in the window specified by \c aWindowNumber
@param modifierFlags a bitwise combination of the modifiers specified in the CPEvent globals
@@ -278,16 +281,28 @@ var _CPEventPeriodicEventPeriod = 0,
timestamp:aTimestamp windowNumber:aWindowNumber context:aGraphicsContext subtype:aSubtype data1:aData1 data2:aData2];
}
- (id)_initWithType:(CPEventType)anEventType
{
if (self = [super init])
{
_type = anEventType;
// Make sure these are 0 rather than nil.
_deltaX = 0;
_deltaY = 0;
_deltaZ = 0;
}
return self;
}
/* @ignore */
- (id)_initMouseEventWithType:(CPEventType)anEventType location:(CPPoint)aPoint modifierFlags:(unsigned)modifierFlags
timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
eventNumber:(int)anEventNumber clickCount:(int)aClickCount pressure:(float)aPressure
{
self = [super init];
if (self)
if (self = [self _initWithType:anEventType])
{
_type = anEventType;
_location = CPPointCreateCopy(aPoint);
_modifierFlags = modifierFlags;
_timestamp = aTimestamp;
@@ -306,11 +321,8 @@ var _CPEventPeriodicEventPeriod = 0,
timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
characters:(CPString)characters charactersIgnoringModifiers:(CPString)unmodCharacters isARepeat:(BOOL)isARepeat keyCode:(unsigned short)code
{
self = [super init];
if (self)
if (self = [self _initWithType:anEventType])
{
_type = anEventType;
_location = CPPointCreateCopy(aPoint);
_modifierFlags = modifierFlags;
_timestamp = aTimestamp;
@@ -330,11 +342,8 @@ var _CPEventPeriodicEventPeriod = 0,
timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
subtype:(short)aSubtype data1:(int)aData1 data2:(int)aData2
{
self = [super init];
if (self)
if (self = [self _initWithType:anEventType])
{
_type = anEventType;
_location = CPPointCreateCopy(aPoint);
_modifierFlags = modifierFlags;
_timestamp = aTimestamp;
@@ -349,10 +358,10 @@ var _CPEventPeriodicEventPeriod = 0,
/*!
Returns the location of the mouse (for mouse events).
If this is not a mouse event, it returns \c nil.
If \c window returns \c nil, then
the mouse coordinates will be based on the screen coordinates.
If the receiver is not a mouse event, it returns \c nil.
If \c window returns \c nil, then the mouse coordinates will be based on the screen coordinates.
Otherwise, the coordinates are relative to the window's coordinates.
@return the location of the mouse, or \c nil for non-mouse events.
*/
- (CGPoint)locationInWindow
@@ -372,7 +381,7 @@ var _CPEventPeriodicEventPeriod = 0,
}
/*!
Returns event information as a bit mask
Returns event information as a bit mask.
*/
- (unsigned)modifierFlags
{
@@ -380,7 +389,7 @@ var _CPEventPeriodicEventPeriod = 0,
}
/*!
Returns the time the event occurred
Returns the time the event occurred.
*/
- (CPTimeInterval)timestamp
{
@@ -396,7 +405,7 @@ var _CPEventPeriodicEventPeriod = 0,
}
/*!
Returns the event's associated window
Returns the event's associated window.
*/
- (CPWindow)window
{
@@ -427,7 +436,7 @@ var _CPEventPeriodicEventPeriod = 0,
}
/*!
Returns the number of clicks that caused this event. (mouse only)
Returns the number of clicks that caused this event (mouse only).
*/
- (int)clickCount
{
@@ -435,7 +444,8 @@ var _CPEventPeriodicEventPeriod = 0,
}
/*!
Returns the characters associated with this event (keyboard only)
Returns the characters associated with this event (keyboard only).
@throws CPInternalInconsistencyException if this method is called on a non-key event
*/
- (CPString)characters
@@ -445,6 +455,7 @@ var _CPEventPeriodicEventPeriod = 0,
/*!
Returns the character ignoring any modifiers (except shift).
@throws CPInternalInconsistencyException if this method is called on a non-key event
*/
- (CPString)charactersIgnoringModifiers
@@ -454,6 +465,7 @@ var _CPEventPeriodicEventPeriod = 0,
/*!
Returns \c YES if the keyboard event was caused by the key being held down.
@throws CPInternalInconsistencyException if this method is called on a non-key event
*/
- (BOOL)isARepeat
@@ -463,6 +475,7 @@ var _CPEventPeriodicEventPeriod = 0,
/*!
Returns the key's key code.
@throws CPInternalInconsistencyException if this method is called on a non-key event
*/
- (unsigned short)keyCode
@@ -495,7 +508,7 @@ var _CPEventPeriodicEventPeriod = 0,
return _DOMEvent;
}
// Getting Scroll Wheel Event Infomration
// Getting Scroll Wheel Event Information
/*!
Returns the change in the x-axis for a mouse event.
*/
@@ -558,35 +571,32 @@ var _CPEventPeriodicEventPeriod = 0,
if (_modifierFlags & (CPCommandKeyMask | CPControlKeyMask))
return YES;
// Cocoa allows almost any key as a key equivalent unless the first responder is a
// text field (presumably a subclass of NSText.)
var firstResponderIsText = [[_window firstResponder] isKindOfClass:[CPTextField class]];
// Some keys are accepted as key equivalents even if the first responder is a text
// field.
for (var i = 0; i < characterCount; i++)
{
switch (_characters.charAt(i))
var c = _characters.charAt(i);
if ((c >= CPUpArrowFunctionKey && c <= CPModeSwitchFunctionKey) ||
c === CPEnterCharacter ||
c === CPNewlineCharacter ||
c === CPCarriageReturnCharacter ||
c === CPEscapeFunctionKey)
{
case CPBackspaceCharacter:
case CPDeleteCharacter:
case CPDeleteFunctionKey:
case CPTabCharacter:
case CPCarriageReturnCharacter:
case CPNewlineCharacter:
case CPSpaceFunctionKey:
case CPEscapeFunctionKey:
case CPPageUpFunctionKey:
case CPPageDownFunctionKey:
case CPLeftArrowFunctionKey:
case CPUpArrowFunctionKey:
case CPRightArrowFunctionKey:
case CPDownArrowFunctionKey:
case CPEndFunctionKey:
case CPHomeFunctionKey:
return YES;
return YES;
}
}
// FIXME: More cases?
return NO;
return !firstResponderIsText;
}
/*!
Gene rates periodic events every \c aPeriod seconds.
Generates periodic events every \c aPeriod seconds.
@param aDelay the number of seconds before the first event
@param aPeriod the length of time in seconds between successive events
*/
@@ -599,7 +609,7 @@ var _CPEventPeriodicEventPeriod = 0,
}
/*!
Stops the periodic events from being generated
Stops the periodic events from being generated.
*/
+ (void)stopPeriodicEvents
{
@@ -637,4 +647,3 @@ function _CPEventFromNativeMouseEvent(aNativeEvent, anEventType, aPoint, modifie
return aNativeEvent;
}
+5 -2
View File
@@ -134,7 +134,10 @@ var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
_DOMObjectElement.removeChild([elements objectAtIndex:i]);
}
#endif
_params = aDictionary;
if (!_params)
_params = aDictionary;
else
[_params addEntriesFromDictionary:aDictionary];
#if PLATFORM(DOM)
if (!CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
{
@@ -143,7 +146,7 @@ var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
var enumerator = [_params keyEnumerator],
key;
while (key = [enumerator nextObject] && _DOMObjectElement)
while (_DOMObjectElement && (key = [enumerator nextObject]))
{
var param = document.createElement(@"param");
param.name = key;
+186 -29
View File
@@ -25,20 +25,49 @@
@import "CPView.j"
CPFontDefaultSystemFontFace = @"Arial, sans-serif";
CPFontDefaultSystemFontSize = 12;
var _CPFonts = {},
_CPFontSystemFontFace = @"Arial, sans-serif",
_CPWrapRegExp = new RegExp("\\s*,\\s*", "g");
var _CPFonts = {},
_CPFontSystemFontFace = CPFontDefaultSystemFontFace,
_CPFontSystemFontSize = 12,
_CPFontFallbackFaces = CPFontDefaultSystemFontFace.split(", "),
_CPFontStripRegExp = new RegExp("(^\\s*[\"']?|[\"']?\\s*$)", "g");
#define _CPCreateCSSString(aName, aSize, isBold) (isBold ? @"bold " : @"") + ROUND(aSize) + @"px " + ((aName === _CPFontSystemFontFace) ? aName : (@"\"" + aName.replace(_CPWrapRegExp, '", "') + @"\", " + _CPFontSystemFontFace))
#define _CPCachedFont(aName, aSize, isBold) _CPFonts[_CPCreateCSSString(aName, aSize, isBold)]
#define _CPFontNormalizedNames(aName) _CPFontNormalizedNameArray(aName).join(", ")
#define _CPCachedFont(aName, aSize, isBold, isItalic) _CPFonts[_CPFontCreateCSSString(_CPFontNormalizedNames(aName), aSize, isBold, isItalic)]
/*!
@ingroup appkit
@class CPFont
The CPFont class allows control of the fonts used for displaying text anywhere on the screen. The primary method for getting a particular font is through one of the class methods that take a name and/or size as arguments, and return the appropriate CPFont.
The CPFont class allows control of the fonts used for displaying text anywhere on the screen.
The primary method for getting a particular font is through one of the class methods that take
a name and/or size as arguments, and return the appropriate CPFont.
By default the system font face/size is Arial 12px, with a fallback to sans-serif. You may
configure this at runtime in two ways:
- By sending [CPFont @link CPFont::setSystemFontFace: setSystemFontFace:@endlink] and/or [CPFont @link CPFont::setSystemFontSize: setSystemFontSize:@endlink].
- By configuring Info.plist for your application or for AppKit. You can set the font face
by adding a CPSystemFontFace string item to the Info.plist, and you can set the font size
by adding a CPSystemFontSize integer item to the Info.plist.
Note that in either case, you can specify a comma-delimited list of fonts as the font face.
The browser will use the first available font in the list. CPFont always ensures that Arial
and sans-serif are in the generated CSS string, so there is no need to add them to the end
of your font list.
If you are using nib2cib, you should use the second method (using Info.plist),
and be sure to run nib2cib again any time you modify the CPSystemFontFace or CPSystemFontSize items.
For example, you might add this to your application's Info.plist to set the system font to Lucida Grande,
with an automatic fallback to Arial or sans-serif:
@code
<key>CPSystemFontFace</key>
<string>Lucida Grande</string>
@endcode
*/
@implementation CPFont : CPObject
{
@@ -47,78 +76,153 @@ var _CPFonts = {},
float _ascender;
float _descender;
float _lineHeight;
BOOL _isBold;
BOOL _isBold @accessors(readonly, getter=isBold);
BOOL _isItalic @accessors(readonly, getter=isItalic);
CPString _cssString;
}
+ (void)initialize
{
var systemFont = [[CPBundle bundleForClass:[CPView class]] objectForInfoDictionaryKey:"CPSystemFontFace"];
var systemFontFace = [[CPBundle mainBundle] objectForInfoDictionaryKey:@"CPSystemFontFace"];
if (systemFont)
_CPFontSystemFontFace = systemFont;
if (!systemFontFace)
systemFontFace = [[CPBundle bundleForClass:[CPView class]] objectForInfoDictionaryKey:@"CPSystemFontFace"];
if (systemFontFace)
[self setSystemFontFace:systemFontFace];
var systemFontSize = [[CPBundle mainBundle] objectForInfoDictionaryKey:@"CPSystemFontSize"];
if (!systemFontSize)
systemFontSize = [[CPBundle bundleForClass:[CPView class]] objectForInfoDictionaryKey:@"CPSystemFontSize"];
if (systemFontSize)
_CPFontSystemFontSize = systemFontSize;
}
/*!
Returns the default system font face, which may consist of several comma-separated family names.
*/
+ (CPString)systemFontFace
{
return _CPFontSystemFontFace;
}
/*!
Sets the default system font face, which may consist of several comma-separated family names.
*/
+ (CPString)setSystemFontFace:(CPString)aFace
{
_CPFontSystemFontFace = _CPFontNormalizedNames(aFace);
}
/*!
Returns the default system font size.
*/
+ (float)systemFontSize
{
return _CPFontSystemFontSize;
}
/*!
Sets the default system font size.
*/
+ (float)setSystemFontSize:(float)size
{
if (size > 0)
_CPFontSystemFontSize = size;
}
/*!
Returns a font with the specified name and size.
@param aName the name of the font
@param aSize the size of the font (in points)
@param aSize the size of the font (in px)
@return the requested font
*/
+ (CPFont)fontWithName:(CPString)aName size:(float)aSize
{
return _CPCachedFont(aName, aSize, NO) || [[CPFont alloc] _initWithName:aName size:aSize bold:NO];
return _CPCachedFont(aName, aSize, NO, NO) || [[CPFont alloc] _initWithName:aName size:aSize bold:NO italic:NO];
}
/*!
Returns a font with the specified name, size and style.
@param aName the name of the font
@param aSize the size of the font (in px)
@param italic whether the font should be italicized
@return the requested font
*/
+ (CPFont)fontWithName:(CPString)aName size:(float)aSize italic:(BOOL)italic
{
return _CPCachedFont(aName, aSize, NO, NO) || [[CPFont alloc] _initWithName:aName size:aSize bold:NO italic:italic];
}
/*!
Returns a bold font with the specified name and size.
@param aName the name of the font
@param aSize the size of the font (in points)
@param aSize the size of the font (in px)
@return the requested bold font
*/
+ (CPFont)boldFontWithName:(CPString)aName size:(float)aSize
{
return _CPCachedFont(aName, aSize, YES) || [[CPFont alloc] _initWithName:aName size:aSize bold:YES];
return _CPCachedFont(aName, aSize, YES, NO) || [[CPFont alloc] _initWithName:aName size:aSize bold:YES italic:NO];
}
/*!
Returns a bold font with the specified name, size and style.
@param aName the name of the font
@param aSize the size of the font (in px)
@param italic whether the font should be italicized
@return the requested font
*/
+ (CPFont)boldFontWithName:(CPString)aName size:(float)aSize italic:(BOOL)italic
{
return _CPCachedFont(aName, aSize, NO, NO) || [[CPFont alloc] _initWithName:aName size:aSize bold:YES italic:italic];
}
/*!
Returns the system font scaled to the specified size
@param aSize the size of the font (in points)
@param aSize the size of the font (in px)
@return the requested system font
*/
+ (CPFont)systemFontOfSize:(CPSize)aSize
{
return _CPCachedFont(_CPFontSystemFontFace, aSize, NO) || [[CPFont alloc] _initWithName:_CPFontSystemFontFace size:aSize bold:NO];
return _CPCachedFont(_CPFontSystemFontFace, aSize, NO, NO) || [[CPFont alloc] _initWithName:_CPFontSystemFontFace size:aSize bold:NO italic:NO];
}
/*!
Returns the bold system font scaled to the specified size
@param aSize the size of the font (in points)
@param aSize the size of the font (in px)
@return the requested bold system font
*/
+ (CPFont)boldSystemFontOfSize:(CPSize)aSize
{
return _CPCachedFont(_CPFontSystemFontFace, aSize, YES) || [[CPFont alloc] _initWithName:_CPFontSystemFontFace size:aSize bold:YES];
return _CPCachedFont(_CPFontSystemFontFace, aSize, YES, NO) || [[CPFont alloc] _initWithName:_CPFontSystemFontFace size:aSize bold:YES italic:NO];
}
/* FIXME Font Descriptor
@ignore
*/
- (id)_initWithName:(CPString)aName size:(float)aSize bold:(BOOL)isBold
{
return [self _initWithName:aName size:aSize bold:isBold italic:NO];
}
- (id)_initWithName:(CPString)aName size:(float)aSize bold:(BOOL)isBold italic:(BOOL)isItalic
{
self = [super init];
if (self)
{
_name = aName;
_name = _CPFontNormalizedNames(aName);
_size = aSize;
_ascender = 0;
_descender = 0;
_lineHeight = 0;
_isBold = isBold;
_isItalic = isItalic;
_cssString = _CPCreateCSSString(_name, _size, _isBold);
_cssString = _CPFontCreateCSSString(_name, _size, _isBold, _isItalic);
_CPFonts[_cssString] = self;
}
@@ -139,7 +243,7 @@ var _CPFonts = {},
/*!
Returns the bottom y coordinate (in CSS px), offset from the baseline, of the receiver's longest descender.
Thus, if the longest descender extends 2 points below the baseline, descender will return 2.
Thus, if the longest descender extends 2 px below the baseline, descender will return 2.
*/
- (float)descender
{
@@ -188,12 +292,17 @@ var _CPFonts = {},
- (BOOL)isEqual:(id)anObject
{
return [anObject isKindOfClass:[CPFont class]] && [anObject cssString] === [self cssString];
return [anObject isKindOfClass:[CPFont class]] && [anObject cssString] === _cssString;
}
- (CPString)description
{
return [CPString stringWithFormat:@"%@ %@ %f pt.", [super description], [self familyName], [self size]];
return [CPString stringWithFormat:@"%@ %@", [super description], [self cssString]];
}
- (id)copy
{
return [[CPFont alloc] _initWithName:_name size:_size bold:_isBold italic:_isItalic];
}
- (void)_getMetrics
@@ -207,9 +316,10 @@ var _CPFonts = {},
@end
var CPFontNameKey = @"CPFontNameKey",
CPFontSizeKey = @"CPFontSizeKey",
CPFontIsBoldKey = @"CPFontIsBoldKey";
var CPFontNameKey = @"CPFontNameKey",
CPFontSizeKey = @"CPFontSizeKey",
CPFontIsBoldKey = @"CPFontIsBoldKey",
CPFontIsItalicKey = @"CPFontIsItalicKey";
@implementation CPFont (CPCoding)
@@ -220,9 +330,12 @@ var CPFontNameKey = @"CPFontNameKey",
*/
- (id)initWithCoder:(CPCoder)aCoder
{
return [self _initWithName:[aCoder decodeObjectForKey:CPFontNameKey]
size:[aCoder decodeFloatForKey:CPFontSizeKey]
bold:[aCoder decodeBoolForKey:CPFontIsBoldKey]];
var fontName = [aCoder decodeObjectForKey:CPFontNameKey],
size = [aCoder decodeFloatForKey:CPFontSizeKey],
isBold = [aCoder decodeBoolForKey:CPFontIsBoldKey],
isItalic = [aCoder decodeBoolForKey:CPFontIsItalicKey];
return [self _initWithName:fontName size:size bold:isBold italic:isItalic];
}
/*!
@@ -234,6 +347,50 @@ var CPFontNameKey = @"CPFontNameKey",
[aCoder encodeObject:_name forKey:CPFontNameKey];
[aCoder encodeFloat:_size forKey:CPFontSizeKey];
[aCoder encodeBool:_isBold forKey:CPFontIsBoldKey];
[aCoder encodeBool:_isItalic forKey:CPFontIsItalicKey];
}
@end
// aName must be normalized
var _CPFontCreateCSSString = function(aName, aSize, isBold, isItalic)
{
var properties = (isItalic ? "italic " : "") + (isBold ? "bold " : "") + aSize + "px ";
return properties + _CPFontConcatNameWithFallback(aName);
};
var _CPFontConcatNameWithFallback = function(aName)
{
var names = _CPFontNormalizedNameArray(aName),
fallbackFaces = _CPFontFallbackFaces.slice(0);
// Remove the fallback names used in the names passed in
for (var i = 0; i < names.length; ++i)
{
for (var j = 0; j < fallbackFaces.length; ++j)
{
if (names[i].toLowerCase() === fallbackFaces[j].toLowerCase())
{
fallbackFaces.splice(j, 1);
break;
}
}
if (names[i].indexOf(" ") > 0)
names[i] = '"' + names[i] + '"';
}
return names.concat(fallbackFaces).join(", ");
};
var _CPFontNormalizedNameArray = function(aName)
{
var names = aName.split(",");
for (var i = 0; i < names.length; ++i)
names[i] = names[i].replace(_CPFontStripRegExp, "");
return names;
};
+2 -2
View File
@@ -25,7 +25,7 @@
@import "CGContext.j"
var CPGraphicsContextCurrent = nil;
var CPGraphicsContextCurrent = nil;
/*!
@ingroup appkit
@@ -33,7 +33,7 @@ var CPGraphicsContextCurrent = nil;
*/
@implementation CPGraphicsContext : CPObject
{
CPContext _graphicsPort;
CGContext _graphicsPort;
}
/*!
+20 -1
View File
@@ -44,7 +44,8 @@ CPImageNameColorPanel = @"CPImageNameColorPanel";
CPImageNameColorPanelHighlighted = @"CPImageNameColorPanelHighlighted";
var imagesForNames = { },
AppKitImageForNames = { };
AppKitImageForNames = { },
ImageDescriptionFormat = "%s {\n filename: \"%s\",\n size: { width:%f, height:%f }\n}";
AppKitImageForNames[CPImageNameColorPanel] = CGSizeMake(26.0, 29.0);
AppKitImageForNames[CPImageNameColorPanelHighlighted] = CGSizeMake(26.0, 29.0);
@@ -324,6 +325,24 @@ function CPAppKitImage(aFilename, aSize)
return NO;
}
- (CPString)description
{
var filename = [self filename],
size = [self size];
if (filename.indexOf("data:") === 0)
{
var index = filename.indexOf(",");
if (index > 0)
filename = [CPString stringWithFormat:@"%s,%s...%s", filename.substr(0, index), filename.substr(index + 1, 10), filename.substr(filename.length - 10)];
else
filename = "data:<unknown type>";
}
return [CPString stringWithFormat:ImageDescriptionFormat, [super description], filename, size.width, size.height];
}
/* @ignore */
- (void)_derefFromImage
{
+64 -17
View File
@@ -39,6 +39,8 @@ var CPBindingOperationAnd = 0,
{
CPDictionary _info;
id _source;
JSObject _suppressedNotifications;
}
+ (void)exposeBinding:(CPString)aBinding forClass:(Class)aClass
@@ -122,6 +124,7 @@ var CPBindingOperationAnd = 0,
{
_source = aSource;
_info = [CPDictionary dictionaryWithObjects:[aDestination, aKeyPath] forKeys:[CPObservedObjectKey, CPObservedKeyPathKey]];
_suppressedNotifications = {};
if (options)
[_info setObject:options forKey:CPOptionsKey];
@@ -169,15 +172,15 @@ var CPBindingOperationAnd = 0,
if (!changes)
return;
var objectSuppressions = _suppressedNotifications[[anObject UID]];
if (objectSuppressions && objectSuppressions[aKeyPath])
return;
[self setValueFor:context];
}
- (id)transformValue:(id)aValue withOptions:(CPDictionary)options
{
var valueTransformerName,
valueTransformer,
placeholder;
var valueTransformerName = [options objectForKey:CPValueTransformerNameBindingOption],
valueTransformer;
@@ -224,6 +227,50 @@ var CPBindingOperationAnd = 0,
return aValue;
}
- (BOOL)continuouslyUpdatesValue
{
var options = [_info objectForKey:CPOptionsKey];
return [[options objectForKey:CPContinuouslyUpdatesValueBindingOption] boolValue];
}
- (BOOL)handlesContentAsCompoundValue
{
var options = [_info objectForKey:CPOptionsKey];
return [[options objectForKey:CPHandlesContentAsCompoundValueBindingOption] boolValue];
}
/*!
Use this to avoid reacting to the notifications coming out of a reverseTransformedValue:.
*/
- (void)suppressSpecificNotificationFromObject:(id)anObject keyPath:(CPString)aKeyPath
{
if (!anObject)
return;
var uid = [anObject UID],
objectSuppressions = _suppressedNotifications[uid];
if (!objectSuppressions)
_suppressedNotifications[uid] = objectSuppressions = {};
objectSuppressions[aKeyPath] = YES;
}
/*!
Use this to cancel suppressSpecificNotificationFromObject:keyPath:.
*/
- (void)unsuppressSpecificNotificationFromObject:(id)anObject keyPath:(CPString)aKeyPath
{
if (!anObject)
return;
var uid = [anObject UID],
objectSuppressions = _suppressedNotifications[uid];
if (!objectSuppressions)
return;
delete objectSuppressions[aKeyPath];
}
@end
@implementation CPObject (KeyValueBindingCreation)
@@ -233,7 +280,6 @@ var CPBindingOperationAnd = 0,
[CPBinder exposeBinding:aBinding forClass:[self class]];
}
+ (Class)_binderClassForBinding:(CPString)theBinding
{
return [CPBinder class];
@@ -265,10 +311,10 @@ var CPBindingOperationAnd = 0,
- (void)bind:(CPString)aBinding toObject:(id)anObject withKeyPath:(CPString)aKeyPath options:(CPDictionary)options
{
if (!anObject || !aKeyPath)
return CPLog.error("Invalid object or path on "+self+" for "+aBinding);
return CPLog.error("Invalid object or path on " + self + " for " + aBinding);
//if (![[self exposedBindings] containsObject:aBinding])
// CPLog.warn("No binding exposed on "+self+" for "+aBinding);
// CPLog.warn("No binding exposed on " + self + " for " + aBinding);
var binderClass = [[self class] _binderClassForBinding:aBinding];
@@ -430,16 +476,17 @@ CPOptionsKey = @"CPOptionsKey";
CPMultipleValuesMarker = @"CPMultipleValuesMarker";
CPNoSelectionMarker = @"CPNoSelectionMarker";
CPNotApplicableMarker = @"CPNotApplicableMarker";
CPNullMarker = @"CPNullMarker";
// Binding name constants
CPAlignmentBinding = @"CPAlignmentBinding";
CPEditableBinding = @"CPEditableBinding";
CPEnabledBinding = @"CPEnabledBinding";
CPFontBinding = @"CPFontBinding";
CPHiddenBinding = @"CPHiddenBinding";
CPSelectedIndexBinding = @"CPSelectedIndexBinding";
CPTextColorBinding = @"CPTextColorBinding";
CPToolTipBinding = @"CPToolTipBinding";
CPAlignmentBinding = @"alignment";
CPEditableBinding = @"editable";
CPEnabledBinding = @"enabled";
CPFontBinding = @"font";
CPHiddenBinding = @"hidden";
CPSelectedIndexBinding = @"selectedIndex";
CPTextColorBinding = @"textColor";
CPToolTipBinding = @"toolTip";
CPValueBinding = @"value";
//Binding options constants
@@ -470,5 +517,5 @@ CPValueTransformerBindingOption = @"CPValueTransformer";
CPIsControllerMarker = function(/*id*/anObject)
{
return anObject === CPMultipleValuesMarker || anObject === CPNoSelectionMarker || anObject === CPNotApplicableMarker;
}
return anObject === CPMultipleValuesMarker || anObject === CPNoSelectionMarker || anObject === CPNotApplicableMarker || anObject === CPNullMarker;
}
+412
View File
@@ -0,0 +1,412 @@
/*
* CPLevelIndicator.j
* AppKit
*
* Created by Alexander Ljungberg.
* Copyright 2011, WireLoad Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPControl.j"
CPTickMarkBelow = 0;
CPTickMarkAbove = 1;
CPTickMarkLeft = CPTickMarkAbove;
CPTickMarkRight = CPTickMarkBelow;
CPRelevancyLevelIndicatorStyle = 0;
CPContinuousCapacityLevelIndicatorStyle = 1;
CPDiscreteCapacityLevelIndicatorStyle = 2;
CPRatingLevelIndicatorStyle = 3;
var _CPLevelIndicatorBezelColor = nil,
_CPLevelIndicatorSegmentEmptyColor = nil,
_CPLevelIndicatorSegmentNormalColor = nil,
_CPLevelIndicatorSegmentWarningColor = nil,
_CPLevelIndicatorSegmentCriticalColor = nil,
_CPLevelIndicatorSpacing = 1;
/*!
@ingroup appkit
@class CPLevelIndicator
CPLevelIndicator is a control which indicates a value visually on a scale.
*/
@implementation CPLevelIndicator : CPControl
{
CPLevelIndicator _levelIndicatorStyle @accessors(property=levelIndicatorStyle);
double _minValue @accessors(property=minValue);
double _maxValue @accessors(property=maxValue);
double _warningValue @accessors(property=warningValue);
double _criticalValue @accessors(property=criticalValue);
CPTickMarkPosition _tickMarkPosition @accessors(property=tickMarkPosition);
int _numberOfTickMarks @accessors(property=numberOfTickMarks);
int _numberOfMajorTickMarks @accessors(property=numberOfMajorTickMarks);
BOOL _isEditable;
BOOL _isTracking;
}
+ (void)initialize
{
var bundle = [CPBundle bundleForClass:CPLevelIndicator];
_CPLevelIndicatorBezelColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-bezel-left.png"] size:CGSizeMake(3.0, 18.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-bezel-center.png"] size:CGSizeMake(1.0, 18.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-bezel-right.png"] size:CGSizeMake(3.0, 18.0)]
]
isVertical:NO
]];
_CPLevelIndicatorSegmentEmptyColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-empty-left.png"] size:CGSizeMake(3.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-empty-center.png"] size:CGSizeMake(1.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-empty-right.png"] size:CGSizeMake(3.0, 17.0)]
]
isVertical:NO
]];
_CPLevelIndicatorSegmentNormalColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-normal-left.png"] size:CGSizeMake(3.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-normal-center.png"] size:CGSizeMake(1.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-normal-right.png"] size:CGSizeMake(3.0, 17.0)]
]
isVertical:NO
]];
_CPLevelIndicatorSegmentWarningColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-warning-left.png"] size:CGSizeMake(3.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-warning-center.png"] size:CGSizeMake(1.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-warning-right.png"] size:CGSizeMake(3.0, 17.0)]
]
isVertical:NO
]];
_CPLevelIndicatorSegmentCriticalColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-critical-left.png"] size:CGSizeMake(3.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-critical-center.png"] size:CGSizeMake(1.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-critical-right.png"] size:CGSizeMake(3.0, 17.0)]
]
isVertical:NO
]];
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
_levelIndicatorStyle = CPDiscreteCapacityLevelIndicatorStyle;
_maxValue = 2;
_warningValue = 2;
_criticalValue = 2;
[self _init];
}
return self;
}
- (void)_init
{
}
- (void)layoutSubviews
{
var bezelView = [self layoutEphemeralSubviewNamed:"bezel"
positioned:CPWindowBelow
relativeToEphemeralSubviewNamed:nil];
// TODO Make themable.
[bezelView setBackgroundColor:_CPLevelIndicatorBezelColor];
var segmentCount = _maxValue - _minValue;
if (segmentCount <= 0)
return;
var filledColor = _CPLevelIndicatorSegmentNormalColor,
value = [self doubleValue];
if (value <= _criticalValue)
filledColor = _CPLevelIndicatorSegmentCriticalColor;
else if (value <= _warningValue)
filledColor = _CPLevelIndicatorSegmentWarningColor;
for (var i = 0; i < segmentCount; i++)
{
var segmentView = [self layoutEphemeralSubviewNamed:"segment-bezel-" + i
positioned:CPWindowAbove
relativeToEphemeralSubviewNamed:bezelView];
[segmentView setBackgroundColor:(_minValue + i) < value ? filledColor : _CPLevelIndicatorSegmentEmptyColor];
}
}
- (CPView)createEphemeralSubviewNamed:(CPString)aName
{
return [[CPView alloc] initWithFrame:_CGRectMakeZero()];
}
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aViewName
{
// TODO Put into theme attributes.
var bezelHeight = 18,
segmentHeight = 17,
bounds = _CGRectCreateCopy([self bounds]);
if (aViewName == "bezel")
{
bounds.origin.y = (_CGRectGetHeight(bounds) - bezelHeight) / 2.0;
bounds.size.height = bezelHeight;
return bounds;
}
else if (aViewName.indexOf("segment-bezel") === 0)
{
var segment = parseInt(aViewName.substring("segment-bezel-".length), 10),
segmentCount = _maxValue - _minValue;
if (segment >= segmentCount)
return _CGRectMakeZero();
var basicSegmentWidth = bounds.size.width / segmentCount,
segmentFrame = CGRectCreateCopy([self bounds]);
segmentFrame.origin.y = (_CGRectGetHeight(bounds) - bezelHeight) / 2.0;
segmentFrame.origin.x = FLOOR(segment * basicSegmentWidth);
segmentFrame.size.width = (segment == segmentCount - 1) ? bounds.size.width - segmentFrame.origin.x : FLOOR(((segment + 1) * basicSegmentWidth)) - FLOOR((segment * basicSegmentWidth)) - _CPLevelIndicatorSpacing;
segmentFrame.size.height = segmentHeight;
return segmentFrame;
}
return _CGRectMakeZero();
}
/*!
Sets whether or not the receiver level indicator can be edited.
*/
- (void)setEditable:(BOOL)shouldBeEditable
{
if (_isEditable === shouldBeEditable)
return;
_isEditable = shouldBeEditable;
}
/*!
Returns \c YES if the textfield is currently editable by the user.
*/
- (BOOL)isEditable
{
return _isEditable;
}
- (CPView)hitTest:(CPPoint)aPoint
{
// Don't swallow clicks when displayed in a table.
if (![self isEditable])
return nil;
return [super hitTest:aPoint];
}
- (void)mouseDown:(CPEvent)anEvent
{
if (![self isEditable] || ![self isEnabled])
return;
[self _trackMouse:anEvent];
}
- (void)_trackMouse:(CPEvent)anEvent
{
var type = [anEvent type];
if (type == CPLeftMouseDown || type == CPLeftMouseDragged)
{
var segmentCount = _maxValue - _minValue;
if (segmentCount <= 0)
return;
var location = [self convertPoint:[anEvent locationInWindow] fromView:nil],
bounds = [self bounds],
oldValue = [self doubleValue];
newValue = oldValue;
// Moving the mouse outside of the widget to the left sets it
// to its minimum, and moving outside on the right sets it to
// its maximum.
if (type == CPLeftMouseDragged && location.x < 0)
{
newValue = _minValue;
}
else if (type == CPLeftMouseDragged && location.x > bounds.size.width)
{
newValue = _maxValue;
}
else
{
for (var i = 0; i < segmentCount; i++)
{
var rect = [self rectForEphemeralSubviewNamed:"segment-bezel-" + i];
// Once we're tracking the mouse, we only care about horizontal mouse movement.
if (location.x >= CGRectGetMinX(rect) && location.x < CGRectGetMaxX(rect))
{
newValue = (_minValue + i + 1);
break;
}
}
}
if (newValue != oldValue)
[self setDoubleValue:newValue];
// Track the mouse to support click and slide value editing.
_isTracking = YES;
[CPApp setTarget:self selector:@selector(_trackMouse:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
if ([self isContinuous])
[self sendAction:[self action] to:[self target]];
}
else if (_isTracking)
{
_isTracking = NO;
[self sendAction:[self action] to:[self target]];
}
}
/*
- (CPLevelIndicatorStyle)style;
- (void)setLevelIndicatorStyle:(CPLevelIndicatorStyle)style;
*/
- (void)setMinValue:(double)minValue
{
if (_minValue === minValue)
return;
_minValue = minValue;
[self setNeedsLayout];
}
- (void)setMaxValue:(double)maxValue
{
if (_maxValue === maxValue)
return;
_maxValue = maxValue;
[self setNeedsLayout];
}
- (void)setWarningValue:(double)warningValue;
{
if (_warningValue === warningValue)
return;
_warningValue = warningValue;
[self setNeedsLayout];
}
- (void)setCriticalValue:(double)criticalValue;
{
if (_criticalValue === criticalValue)
return;
_criticalValue = criticalValue;
[self setNeedsLayout];
}
/*
- (CPTickMarkPosition)tickMarkPosition;
- (void)setTickMarkPosition:(CPTickMarkPosition)position;
- (int)numberOfTickMarks;
- (void)setNumberOfTickMarks:(int)count;
- (int)numberOfMajorTickMarks;
- (void)setNumberOfMajorTickMarks:(int)count;
- (double)tickMarkValueAtIndex:(int)index;
- (CGRect)rectOfTickMarkAtIndex:(int)index;
*/
@end
var CPLevelIndicatorStyleKey = "CPLevelIndicatorStyleKey",
CPLevelIndicatorMinValueKey = "CPLevelIndicatorMinValueKey",
CPLevelIndicatorMaxValueKey = "CPLevelIndicatorMaxValueKey",
CPLevelIndicatorWarningValueKey = "CPLevelIndicatorWarningValueKey",
CPLevelIndicatorCriticalValueKey = "CPLevelIndicatorCriticalValueKey",
CPLevelIndicatorTickMarkPositionKey = "CPLevelIndicatorTickMarkPositionKey",
CPLevelIndicatorNumberOfTickMarksKey = "CPLevelIndicatorNumberOfTickMarksKey",
CPLevelIndicatorNumberOfMajorTickMarksKey = "CPLevelIndicatorNumberOfMajorTickMarksKey",
CPLevelIndicatorIsEditableKey = "CPLevelIndicatorIsEditableKey";
@implementation CPLevelIndicator (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
_levelIndicatorStyle = [aCoder decodeIntForKey:CPLevelIndicatorStyleKey];
_minValue = [aCoder decodeDoubleForKey:CPLevelIndicatorMinValueKey];
_maxValue = [aCoder decodeDoubleForKey:CPLevelIndicatorMaxValueKey];
_warningValue = [aCoder decodeDoubleForKey:CPLevelIndicatorWarningValueKey];
_criticalValue = [aCoder decodeDoubleForKey:CPLevelIndicatorCriticalValueKey];
_tickMarkPosition = [aCoder decodeIntForKey:CPLevelIndicatorTickMarkPositionKey];
_numberOfTickMarks = [aCoder decodeIntForKey:CPLevelIndicatorNumberOfTickMarksKey];
_numberOfMajorTickMarks = [aCoder decodeIntForKey:CPLevelIndicatorNumberOfMajorTickMarksKey];
_isEditable = [aCoder decodeBoolForKey:CPLevelIndicatorIsEditableKey];
[self _init];
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeInt:_levelIndicatorStyle forKey:CPLevelIndicatorStyleKey];
[aCoder encodeDouble:_minValue forKey:CPLevelIndicatorMinValueKey];
[aCoder encodeDouble:_maxValue forKey:CPLevelIndicatorMaxValueKey];
[aCoder encodeDouble:_warningValue forKey:CPLevelIndicatorWarningValueKey];
[aCoder encodeDouble:_criticalValue forKey:CPLevelIndicatorCriticalValueKey];
[aCoder encodeInt:_tickMarkPosition forKey:CPLevelIndicatorTickMarkPositionKey];
[aCoder encodeInt:_numberOfTickMarks forKey:CPLevelIndicatorNumberOfTickMarksKey];
[aCoder encodeInt:_numberOfMajorTickMarks forKey:CPLevelIndicatorNumberOfMajorTickMarksKey];
[aCoder encodeBool:_isEditable forKey:CPLevelIndicatorIsEditableKey];
}
@end
+86 -23
View File
@@ -52,7 +52,7 @@ var _CPMenuBarVisible = NO,
@class CPMenu
Menus provide the user with a list of actions and/or submenus. Submenus themselves are full fledged menus
and so a heirarchical structure appears.
and so a hierarchical structure appears.
*/
@implementation CPMenu : CPObject
{
@@ -80,6 +80,9 @@ var _CPMenuBarVisible = NO,
+ (void)initialize
{
if (self !== CPMenu)
return;
[[self class] setMenuBarAttributes:[CPDictionary dictionary]];
}
@@ -192,7 +195,7 @@ var _CPMenuBarVisible = NO,
}
if (!highlightColor)
[_CPMenuBarAttributes setObject:[CPColor colorWithCalibratedRed:94.0/255.0 green:130.0/255.0 blue:186.0/255.0 alpha:1.0] forKey:@"CPMenuBarHighlightColor"];
[_CPMenuBarAttributes setObject:[CPColor colorWithCalibratedRed:94.0 / 255.0 green:130.0 / 255.0 blue:186.0 / 255.0 alpha:1.0] forKey:@"CPMenuBarHighlightColor"];
if (!highlightTextColor)
[_CPMenuBarAttributes setObject:[CPColor whiteColor] forKey:@"CPMenuBarHighlightTextColor"];
@@ -334,6 +337,29 @@ var _CPMenuBarVisible = NO,
[self removeObjectFromItemsAtIndex:anIndex];
}
/*!
Removes all the menu items in the receiver.
This method is more efficient than removing menu items individually.
Unlike the other remove methods, this method does not post CPMenuDidChangeItemNotification notifications.
*/
- (void)removeAllItems
{
var count = [_items count];
// Remove the connection to this menu in case
// someone else has a reference to the menu item.
while (count--)
[_items[count] setMenu:nil];
_highlightedIndex = CPNotFound;
// Because we are changing _items directly, be sure to notify KVO
[self willChangeValueForKey:@"items"];
_items = [CPMutableArray array];
[self didChangeValueForKey:@"items"];
}
/*!
Called when a menu item has visually changed.
@param aMenuItem the item that changed
@@ -533,7 +559,6 @@ var _CPMenuBarVisible = NO,
*/
- (void)submenuAction:(id)aSender
{
}
/*!
@@ -581,11 +606,34 @@ var _CPMenuBarVisible = NO,
}
/*!
Not implemented.
Enables or disables the receivers menu items.
If the target does not implement the menu item's action method the item is disabled.
If the target responsds to selector validateMenuItem: or validateUserInterfaceItem: (in that order) the return value is used.
*/
- (void)update
{
if (![self autoenablesItems])
return;
var items = [self itemArray];
for (var i = 0; i < [items count]; i++)
{
var item = [items objectAtIndex:i];
if ([item hasSubmenu])
continue;
var validator = [CPApp targetForAction:[item action] to:[item target] from:item];
if (!validator || ![validator respondsToSelector:[item action]])
[item setEnabled:NO];
else if ([validator respondsToSelector:@selector(validateMenuItem:)])
[item setEnabled:[validator validateMenuItem:item]];
else if ([validator respondsToSelector:@selector(validateUserInterfaceItem:)])
[item setEnabled:[validator validateUserInterfaceItem:item]];
}
[[_menuWindow _menuView] tile];
}
// Managing the Title
@@ -667,10 +715,7 @@ var _CPMenuBarVisible = NO,
if (aView && !theWindow)
throw "In call to popUpMenuPositioningItem:atLocation:inView:callback:, view is not in any window.";
var delegate = [self delegate];
if ([delegate respondsToSelector:@selector(menuWillOpen:)])
[delegate menuWillOpen:self];
[self _menuWillOpen];
// Convert location to global coordinates if not already in them.
if (aView)
@@ -758,10 +803,7 @@ var _CPMenuBarVisible = NO,
+ (void)popUpContextMenu:(CPMenu)aMenu withEvent:(CPEvent)anEvent forView:(CPView)aView withFont:(CPFont)aFont
{
var delegate = [aMenu delegate];
if ([delegate respondsToSelector:@selector(menuWillOpen:)])
[delegate menuWillOpen:aMenu];
[aMenu _menuWillOpen];
if (!aFont)
aFont = [CPFont systemFontOfSize:12.0];
@@ -831,7 +873,15 @@ var _CPMenuBarVisible = NO,
*/
- (CPMenuItem)highlightedItem
{
return _highlightedIndex >= 0 ? _items[_highlightedIndex] : nil;
if (_highlightedIndex < 0)
return nil;
var highlightedItem = _items[_highlightedIndex];
if ([highlightedItem isSeparatorItem])
return nil;
return highlightedItem;
}
// Managing the Delegate
@@ -846,9 +896,25 @@ var _CPMenuBarVisible = NO,
return _delegate;
}
- (void)_menuWillOpen
{
var delegate = [self delegate];
if ([delegate respondsToSelector:@selector(menuWillOpen:)])
[delegate menuWillOpen:self];
}
- (void)_menuDidClose
{
var delegate = [self delegate];
if ([delegate respondsToSelector:@selector(menuDidClose:)])
[delegate menuDidClose:self];
}
// Handling Tracking
/*!
Cancels tracking.
Cancels tracking.
*/
- (void)cancelTracking
{
@@ -908,7 +974,7 @@ var _CPMenuBarVisible = NO,
characters = [anEvent charactersIgnoringModifiers],
modifierFlags = [anEvent modifierFlags];
for(; index < count; ++index)
for (; index < count; ++index)
{
var item = _items[index],
modifierMask = [item keyEquivalentModifierMask];
@@ -945,14 +1011,6 @@ var _CPMenuBarVisible = NO,
}
//
/*
@ignore
*/
- (BOOL)_itemIsHighlighted:(CPMenuItem)aMenuItem
{
return _items[_highlightedIndex] == aMenuItem;
}
/*
@ignore
*/
@@ -968,6 +1026,9 @@ var _CPMenuBarVisible = NO,
if (_highlightedIndex !== CPNotFound)
[[_items[_highlightedIndex] _menuItemView] highlight:YES];
if (_highlightedIndex !== CPNotFound && _menuWindow)
[_menuWindow._menuView scrollRectToVisible:[[_items[_highlightedIndex] _menuItemView] frame]];
}
- (void)_setMenuName:(CPString)aName
@@ -1094,6 +1155,8 @@ var CPMenuTitleKey = @"CPMenuTitleKey",
_showsStateColumn = ![aCoder containsValueForKey:CPMenuShowsStateColumnKey] || [aCoder decodeBoolForKey:CPMenuShowsStateColumnKey];
_autoenablesItems = YES;
[self setMinimumWidth:0];
}
+66 -66
View File
@@ -15,18 +15,18 @@ var _CPMenuBarWindowBackgroundColor = nil,
CPMenu _menu;
CPView _highlightView;
CPArray _menuItemViews;
CPMenuItem _trackingMenuItem;
CPImageView _iconImageView;
CPTextField _titleField;
CPColor _textColor;
CPColor _titleColor;
CPColor _textShadowColor;
CPColor _titleShadowColor;
CPColor _highlightColor;
CPColor _highlightTextColor;
CPColor _highlightTextShadowColor;
@@ -36,9 +36,9 @@ var _CPMenuBarWindowBackgroundColor = nil,
{
if (self != [_CPMenuBarWindow class])
return;
var bundle = [CPBundle bundleForClass:self];
_CPMenuBarWindowFont = [CPFont boldSystemFontOfSize:12.0];
}
@@ -60,27 +60,27 @@ var _CPMenuBarWindowBackgroundColor = nil,
{
[self setLevel:CPMainMenuWindowLevel];
[self setAutoresizingMask:CPWindowWidthSizable];
var contentView = [self contentView];
[contentView setAutoresizesSubviews:NO];
[self setBecomesKeyOnlyIfNeeded:YES];
//
_iconImageView = [[CPImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, 16.0, 16.0)];
[contentView addSubview:_iconImageView];
_titleField = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
[_titleField setFont:[CPFont boldSystemFontOfSize:13.0]];
[_titleField setAlignment:CPCenterTextAlignment];
[_titleField setTextShadowOffset:CGSizeMake(0, 1)];
[contentView addSubview:_titleField];
}
return self;
}
@@ -99,7 +99,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
[_titleField setStringValue:aTitle];
[_titleField sizeToFit];
[self tile];
}
@@ -122,7 +122,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
{
if (!_CPMenuBarWindowBackgroundColor)
_CPMenuBarWindowBackgroundColor = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[_CPMenuBarWindow class]] pathForResource:@"_CPMenuBarWindow/_CPMenuBarWindowBackground.png"] size:CGSizeMake(1.0, 28.0)]];
[[self contentView] setBackgroundColor:_CPMenuBarWindowBackgroundColor];
}
else
@@ -133,9 +133,9 @@ var _CPMenuBarWindowBackgroundColor = nil,
{
if (_textColor == aColor)
return;
_textColor = aColor;
[_menuItemViews makeObjectsPerformSelector:@selector(setTextColor:) withObject:_textColor];
}
@@ -143,9 +143,9 @@ var _CPMenuBarWindowBackgroundColor = nil,
{
if (_titleColor == aColor)
return;
_titleColor = aColor;
[_titleField setTextColor:aColor ? aColor : [CPColor blackColor]];
}
@@ -153,9 +153,9 @@ var _CPMenuBarWindowBackgroundColor = nil,
{
if (_textShadowColor == aColor)
return;
_textShadowColor = aColor;
[_menuItemViews makeObjectsPerformSelector:@selector(setTextShadowColor:) withObject:_textShadowColor];
}
@@ -163,9 +163,9 @@ var _CPMenuBarWindowBackgroundColor = nil,
{
if (_titleShadowColor == aColor)
return;
_titleShadowColor = aColor;
[_titleField setTextShadowColor:aColor ? aColor : [CPColor whiteColor]];
}
@@ -173,7 +173,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
{
if (_highlightColor == aColor)
return;
_highlightColor = aColor;
}
@@ -181,7 +181,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
{
if (_highlightTextColor == aColor)
return;
_highlightTextColor = aColor;
// [_menuItemViews makeObjectsPerformSelector:@selector(setActivateColor:) withObject:_highlightTextColor];
@@ -191,9 +191,9 @@ var _CPMenuBarWindowBackgroundColor = nil,
{
if (_highlightTextShadowColor == aColor)
return;
_highlightTextShadowColor = aColor;
// [_menuItemViews makeObjectsPerformSelector:@selector(setActivateShadowColor:) withObject:_highlightTextShadowColor];
}
@@ -201,9 +201,9 @@ var _CPMenuBarWindowBackgroundColor = nil,
{
if (_menu == aMenu)
return;
var defaultCenter = [CPNotificationCenter defaultCenter];
if (_menu)
{
[defaultCenter
@@ -220,16 +220,16 @@ var _CPMenuBarWindowBackgroundColor = nil,
removeObserver:self
name:CPMenuDidRemoveItemNotification
object:_menu];
var items = [_menu itemArray],
count = items.length;
while (count--)
[[items[count] _menuItemView] removeFromSuperview];
}
_menu = aMenu;
if (_menu)
{
[defaultCenter
@@ -237,41 +237,41 @@ var _CPMenuBarWindowBackgroundColor = nil,
selector:@selector(menuDidAddItem:)
name:CPMenuDidAddItemNotification
object:_menu];
[defaultCenter
addObserver:self
selector:@selector(menuDidChangeItem:)
name:CPMenuDidChangeItemNotification
object:_menu];
[defaultCenter
addObserver:self
selector:@selector(menuDidRemoveItem:)
name:CPMenuDidRemoveItemNotification
object:_menu];
}
_menuItemViews = [];
var contentView = [self contentView],
items = [_menu itemArray],
count = items.length;
for (index = 0; index < count; ++index)
{
var item = items[index],
menuItemView = [item _menuItemView];
_menuItemViews.push(menuItemView);
[menuItemView setTextColor:_textColor];
[menuItemView setHidden:[item isHidden]];
[menuItemView synchronizeWithMenuItem];
[contentView addSubview:menuItemView];
}
[self tile];
}
@@ -282,7 +282,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
[menuItemView setHidden:[menuItem isHidden]];
[menuItemView synchronizeWithMenuItem];
[self tile];
}
@@ -298,9 +298,9 @@ var _CPMenuBarWindowBackgroundColor = nil,
[menuItemView setHidden:[menuItem isHidden]];
[menuItemView synchronizeWithMenuItem];
[[self contentView] addSubview:menuItemView];
[self tile];
}
@@ -312,7 +312,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
[_menuItemViews removeObjectAtIndex:index];
[menuItemView removeFromSuperview];
[self tile];
}
@@ -343,29 +343,29 @@ var _CPMenuBarWindowBackgroundColor = nil,
var items = [_menu itemArray],
index = 0,
count = items.length,
x = MENUBAR_LEFT_MARGIN,
y = 0.0,
isLeftAligned = YES;
for (; index < count; ++index)
{
var item = items[index];
if ([item isSeparatorItem])
{
x = CGRectGetWidth([self frame]) - MENUBAR_RIGHT_MARGIN;
isLeftAligned = NO;
continue;
}
if ([item isHidden])
continue;
var menuItemView = [item _menuItemView],
frame = [menuItemView frame];
if (isLeftAligned)
{
[menuItemView setFrame:CGRectMake(x, 0.0, CGRectGetWidth(frame), MENUBAR_HEIGHT)];
@@ -375,14 +375,14 @@ var _CPMenuBarWindowBackgroundColor = nil,
else
{
[menuItemView setFrame:CGRectMake(x - CGRectGetWidth(frame), 0.0, CGRectGetWidth(frame), MENUBAR_HEIGHT)];
x = CGRectGetMinX([menuItemView frame]);
}
}
var bounds = [[self contentView] bounds],
titleFrame = [_titleField frame];
if ([_iconImageView isHidden])
[_titleField setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth(titleFrame)) / 2.0, (CGRectGetHeight(bounds) - CGRectGetHeight(titleFrame)) / 2.0)];
else
@@ -390,7 +390,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
var iconFrame = [_iconImageView frame],
iconWidth = CGRectGetWidth(iconFrame),
totalWidth = iconWidth + CGRectGetWidth(titleFrame);
[_iconImageView setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - totalWidth) / 2.0, (CGRectGetHeight(bounds) - CGRectGetHeight(iconFrame)) / 2.0)];
[_titleField setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - totalWidth) / 2.0 + iconWidth, (CGRectGetHeight(bounds) - CGRectGetHeight(titleFrame)) / 2.0)];
}
@@ -505,38 +505,38 @@ var _CPMenuBarWindowBackgroundColor = nil,
for (; index < count; ++index)
{
var item = items[index];
if ([item isSeparatorItem])
{
x = CGRectGetWidth([self frame]) - MENUBAR_RIGHT_MARGIN;
isLeftAligned = NO;
continue;
}
if ([item isHidden])
continue;
var menuItemView = [item _menuItemView],
frame = [menuItemView frame];
if (isLeftAligned)
{
[menuItemView setFrameOrigin:CGPointMake(x, (MENUBAR_HEIGHT - 1.0 - CGRectGetHeight(frame)) / 2.0)];
x += CGRectGetWidth([menuItemView frame]) + MENUBAR_MARGIN;
}
else
{
[menuItemView setFrameOrigin:CGPointMake(x - CGRectGetWidth(frame), (MENUBAR_HEIGHT - 1.0 - CGRectGetHeight(frame)) / 2.0)];
x = CGRectGetMinX([menuItemView frame]) - MENUBAR_MARGIN;
}
}
var bounds = [[self contentView] bounds],
titleFrame = [_titleField frame];
if ([_iconImageView isHidden])
[_titleField setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth(titleFrame)) / 2.0, (CGRectGetHeight(bounds) - CGRectGetHeight(titleFrame)) / 2.0)];
else
@@ -544,7 +544,7 @@ var _CPMenuBarWindowBackgroundColor = nil,
var iconFrame = [_iconImageView frame],
iconWidth = CGRectGetWidth(iconFrame),
totalWidth = iconWidth + CGRectGetWidth(titleFrame);
[_iconImageView setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - totalWidth) / 2.0, (CGRectGetHeight(bounds) - CGRectGetHeight(iconFrame)) / 2.0)];
[_titleField setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - totalWidth) / 2.0 + iconWidth, (CGRectGetHeight(bounds) - CGRectGetHeight(titleFrame)) / 2.0)];
}
+359 -53
View File
@@ -1,17 +1,17 @@
@import <Foundation/CPObject.j>
_CPMenuManagerScrollingStateUp = -1,
_CPMenuManagerScrollingStateDown = 1,
_CPMenuManagerScrollingStateUp = -1;
_CPMenuManagerScrollingStateDown = 1;
_CPMenuManagerScrollingStateNone = 0;
var STICKY_TIME_INTERVAL = 500;
var SharedMenuManager = nil;
var STICKY_TIME_INTERVAL = 500,
SharedMenuManager = nil;
@implementation _CPMenuManager: CPObject
{
CPTimeInterval _startTime;
BOOL _hasMouseGoneUpAfterStartedTracking;
int _scrollingState;
CGPoint _lastGlobalLocation;
@@ -21,6 +21,11 @@ var SharedMenuManager = nil;
CPMutableArray _menuContainerStack;
Function _trackingCallback;
CPString _keyBuffer;
CPMenuItem _previousActiveItem;
int _showTimerID;
}
+ (_CPMenuManager)sharedMenuManager
@@ -36,7 +41,7 @@ var SharedMenuManager = nil;
if (SharedMenuManager)
return SharedMenuManager;
return [super init];
return [super init];
}
- (id)trackingMenuContainer
@@ -56,6 +61,9 @@ var SharedMenuManager = nil;
{
var menu = [aMenuContainer menu];
if ([menu numberOfItems] <= 0)
return;
CPApp._activeMenu = menu;
_startTime = [anEvent timestamp];//new Date();
@@ -67,13 +75,13 @@ var SharedMenuManager = nil;
if (menu === [CPApp mainMenu])
{
var globalLocation = [anEvent globalLocation];
var globalLocation = [anEvent globalLocation],
// Find which menu window the mouse is currently on top of
var menuLocation = [aMenuContainer convertGlobalToBase:globalLocation];
// Find which menu window the mouse is currently on top of
menuLocation = [aMenuContainer convertGlobalToBase:globalLocation],
// Find out the item the mouse is currently on top of
var activeItemIndex = [aMenuContainer itemIndexAtPoint:menuLocation],
// Find out the item the mouse is currently on top of
activeItemIndex = [aMenuContainer itemIndexAtPoint:menuLocation],
activeItem = activeItemIndex !== CPNotFound ? [menu itemAtIndex:activeItemIndex] : nil;
_menuBarButtonItemIndex = activeItemIndex;
@@ -83,6 +91,8 @@ var SharedMenuManager = nil;
return [self trackMenuBarButtonEvent:anEvent];
}
_hasMouseGoneUpAfterStartedTracking = NO;
[self trackEvent:anEvent];
}
@@ -95,7 +105,34 @@ var SharedMenuManager = nil;
if (type === CPAppKitDefined)
return [self completeTracking];
[CPApp setTarget:self selector:@selector(trackEvent:) forNextEventMatchingMask:CPPeriodicMask | CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPAppKitDefinedMask untilDate:nil inMode:nil dequeue:YES];
[CPApp setTarget:self selector:@selector(trackEvent:) forNextEventMatchingMask:CPKeyDownMask | CPPeriodicMask | CPMouseMovedMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask | CPRightMouseUpMask | CPAppKitDefinedMask | CPScrollWheelMask untilDate:nil inMode:nil dequeue:YES];
if (type === CPKeyDown)
{
var menu = trackingMenu,
submenu = [[menu highlightedItem] submenu];
// get the current active menu
while (submenu && [submenu._menuWindow isVisible])
{
menu = submenu;
submenu = [[menu highlightedItem] submenu];
}
if ([menu numberOfItems])
[self interpretKeyEvent:anEvent forMenu:menu];
return;
}
if (_keyBuffer)
{
if (([CPDate date] - _startTime) > (STICKY_TIME_INTERVAL + [activeMenu numberOfItems] / 2))
[self selectNextItemBeginningWith:_keyBuffer inMenu:menu clearBuffer:YES];
if (type === CPPeriodic)
return;
}
// Periodic events don't have a valid location.
var globalLocation = type === CPPeriodic ? _lastGlobalLocation : [anEvent globalLocation];
@@ -103,13 +140,16 @@ var SharedMenuManager = nil;
// Remember this for the next periodic event.
_lastGlobalLocation = globalLocation;
if (!_lastGlobalLocation)
return;
// Find which menu window the mouse is currently on top of
var activeMenuContainer = [self menuContainerForPoint:globalLocation],
activeMenu = [activeMenuContainer menu],
menuLocation = [activeMenuContainer convertGlobalToBase:globalLocation];
menuLocation = [activeMenuContainer convertGlobalToBase:globalLocation],
// Find out the item the mouse is currently on top of
var activeItemIndex = activeMenuContainer ? [activeMenuContainer itemIndexAtPoint:menuLocation] : CPNotFound,
// Find out the item the mouse is currently on top of
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.
@@ -121,11 +161,13 @@ var SharedMenuManager = nil;
var mouseOverMenuView = [activeItem view];
if (type === CPScrollWheel)
[activeMenuContainer scrollByDelta:[anEvent deltaY]];
if (type === CPPeriodic)
{
if (_scrollingState === _CPMenuManagerScrollingStateUp)
[activeMenuContainer scrollUp];
else if (_scrollingState === _CPMenuManagerScrollingStateDown)
[activeMenuContainer scrollDown];
}
@@ -135,13 +177,13 @@ var SharedMenuManager = nil;
{
if (!_lastMouseOverMenuView)
[activeMenu _highlightItemAtIndex:CPNotFound];
if (_lastMouseOverMenuView != mouseOverMenuView)
{
[mouseOverMenuView mouseExited:anEvent];
// FIXME: Possibly multiple of these?
[_lastMouseOverMenuView mouseEntered:anEvent];
_lastMouseOverMenuView = mouseOverMenuView;
}
@@ -151,13 +193,15 @@ var SharedMenuManager = nil;
menuContainerWindow = [menuContainerWindow window];
[menuContainerWindow
sendEvent:[CPEvent mouseEventWithType:type location:menuLocation modifierFlags:[anEvent modifierFlags]
timestamp:[anEvent timestamp]
windowNumber:menuContainerWindow
context:nil
eventNumber:0
clickCount:[anEvent clickCount]
pressure:[anEvent pressure]]];
sendEvent:[CPEvent mouseEventWithType:type
location:menuLocation
modifierFlags:[anEvent modifierFlags]
timestamp:[anEvent timestamp]
windowNumber:menuContainerWindow
context:nil
eventNumber:0
clickCount:[anEvent clickCount]
pressure:[anEvent pressure]]];
}
else
{
@@ -166,10 +210,10 @@ var SharedMenuManager = nil;
[_lastMouseOverMenuView mouseExited:anEvent];
_lastMouseOverMenuView = nil;
}
[activeMenu _highlightItemAtIndex:activeItemIndex];
if (type === CPMouseMoved || type === CPLeftMouseDragged || type === CPLeftMouseDown)
if (type === CPMouseMoved || type === CPLeftMouseDragged || type === CPLeftMouseDown || type === CPPeriodic)
{
var oldScrollingState = _scrollingState;
@@ -179,34 +223,71 @@ var SharedMenuManager = nil;
{
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];
else if (type === CPLeftMouseUp || type === CPRightMouseUp)
{
if (_hasMouseGoneUpAfterStartedTracking)
{
// Don't close the menu if the current item has a submenu
// and did not override it's default action
if ([activeItem action] === @selector(submenuAction:))
return;
[trackingMenu cancelTracking];
}
else
_hasMouseGoneUpAfterStartedTracking = YES;
}
}
// Prevent previous selected menu items from opening by stopping the timer if a
// new item is selected before the timer runs out
if (_previousActiveItem !== activeItem)
{
clearTimeout(_showTimerID);
_showTimerID = undefined;
}
// If the item has a submenu, show it.
if ([activeItem hasSubmenu])// && [activeItem action] === @selector(submenuAction:))
{
var activeItemRect = [activeMenuContainer rectForItemAtIndex:activeItemIndex];
var activeItemRect = [activeMenuContainer rectForItemAtIndex:activeItemIndex],
newMenuOrigin;
if ([activeMenuContainer isMenuBar])
var newMenuOrigin = CGPointMake(CGRectGetMinX(activeItemRect), CGRectGetMaxY(activeItemRect));
newMenuOrigin = CGPointMake(CGRectGetMinX(activeItemRect), CGRectGetMaxY(activeItemRect));
else
var newMenuOrigin = CGPointMake(CGRectGetMaxX(activeItemRect), CGRectGetMinY(activeItemRect));
newMenuOrigin = CGPointMake(CGRectGetMaxX(activeItemRect), CGRectGetMinY(activeItemRect));
newMenuOrigin = [activeMenuContainer convertBaseToGlobal:newMenuOrigin];
[self showMenu:[activeItem submenu] fromMenu:[activeItem menu] atPoint:newMenuOrigin];
// Only start a new timer if the previous was cancelled
if (_showTimerID === undefined)
{
// Close the current menu item because we are going to select a new one after a short delay
[self showMenu:nil fromMenu:activeMenu atPoint:CGPointMakeZero()];
if (![activeMenuContainer isMenuBar])
{
_showTimerID = setTimeout(function()
{
[self showMenu:[activeItem submenu] fromMenu:[activeItem menu] atPoint:newMenuOrigin];
}, 250);
}
else
[self showMenu:[activeItem submenu] fromMenu:[activeItem menu] atPoint:newMenuOrigin];
}
}
// This handles both the case where we've moved away from the menu, and where
// This handles both the case where we've moved away from the menu, and where
// we've moved to an item without a submenu.
else
[self showMenu:nil fromMenu:activeMenu atPoint:CGPointMakeZero()];
_previousActiveItem = activeItem;
}
- (void)trackMenuBarButtonEvent:(CPEvent)anEvent
@@ -216,16 +297,15 @@ var SharedMenuManager = nil;
if (type === CPAppKitDefined)
return [self completeTracking];
var globalLocation = [anEvent globalLocation];
var globalLocation = [anEvent globalLocation],
// Find which menu window the mouse is currently on top of
var menu = [self trackingMenu],
// Find which menu window the mouse is currently on top of
menu = [self trackingMenu],
trackingMenuContainer = [self trackingMenuContainer],
menuLocation = [trackingMenuContainer convertGlobalToBase:globalLocation];
if ([trackingMenuContainer itemIndexAtPoint:menuLocation] === _menuBarButtonItemIndex)
[menu _highlightItemAtIndex:_menuBarButtonItemIndex];
else
[menu _highlightItemAtIndex:CPNotFound];
@@ -242,23 +322,15 @@ var SharedMenuManager = nil;
// 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];
[trackingMenu _menuDidClose];
if (_trackingCallback)
_trackingCallback([self trackingMenuContainer], trackingMenu);
[[CPNotificationCenter defaultCenter]
postNotificationName:CPMenuDidEndTrackingNotification
object:trackingMenu];
[[CPNotificationCenter defaultCenter] postNotificationName:CPMenuDidEndTrackingNotification
object:trackingMenu];
CPApp._activeMenu = nil;
}
@@ -321,6 +393,8 @@ var SharedMenuManager = nil;
var count = _menuContainerStack.length,
index = count;
[newMenu _menuWillOpen];
// Hide all menus up to the base menu...
while (index--)
{
@@ -340,6 +414,8 @@ var SharedMenuManager = nil;
[_CPMenuWindow poolMenuWindow:menuContainer];
[_menuContainerStack removeObjectAtIndex:index];
[menu _menuDidClose];
}
if (!newMenu)
@@ -358,10 +434,240 @@ var SharedMenuManager = nil;
if (baseMenu === [self trackingMenu] && [[self trackingMenuContainer] isMenuBar])
[menuWindow setBackgroundStyle:_CPMenuWindowMenuBarBackgroundStyle];
else
[menuWindow setBackgroundStyle:_CPMenuWindowPopUpBackgroundStyle];
[menuWindow setBackgroundStyle:_CPMenuWindowPopUpBackgroundStyle];
[menuWindow setFrameOrigin:aGlobalLocation];
[menuWindow orderFront:self];
}
/// handle keyboard navigation
- (void)interpretKeyEvent:(CPEvent)anEvent forMenu:(CPMenu)menu
{
var modifierFlags = [anEvent modifierFlags],
character = [anEvent charactersIgnoringModifiers],
selectorNames = [CPKeyBinding selectorsForKey:character modifierFlags:modifierFlags];
if (selectorNames)
{
var iter = [selectorNames objectEnumerator],
obj;
while (obj = [iter nextObject])
{
var aSelector = CPSelectorFromString(obj);
if ([self respondsToSelector:aSelector])
[self performSelector:aSelector withObject:menu];
}
}
else if (!(modifierFlags & (CPCommandKeyMask | CPControlKeyMask)))
{
if (!_keyBuffer)
{
_startTime = [CPDate date];
_keyBuffer = character;
[CPEvent stopPeriodicEvents];
[CPEvent startPeriodicEventsAfterDelay:0.1 withPeriod:0.1];
}
else
_keyBuffer += character;
[self selectNextItemBeginningWith:_keyBuffer inMenu:menu clearBuffer:NO];
_lastGlobalLocation = Nil;
}
}
- (void)selectNextItemBeginningWith:(CPString)characters inMenu:(CPMenu)menu clearBuffer:(BOOL)shouldClear
{
var iter = [[menu itemArray] objectEnumerator],
obj;
while (obj = [iter nextObject])
{
if ([obj isHidden] || ![obj isEnabled])
continue;
if ([[[obj title] commonPrefixWithString:characters options:CPCaseInsensitiveSearch] length] == [characters length])
{
[menu _highlightItemAtIndex:iter._index];
break;
}
}
if (shouldClear)
{
[CPEvent stopPeriodicEvents];
_keyBuffer = Nil;
}
else
_startTime = [CPDate date];
}
- (void)scrollToBeginningOfDocument:(CPMenu)menu
{
[menu _highlightItemAtIndex:0];
}
- (void)scrollToEndOfDocument:(CPMenu)menu
{
[menu _highlightItemAtIndex:[menu numberOfItems] - 1];
}
- (void)scrollPageDown:(CPMenu)menu
{
var menuWindow = menu._menuWindow,
menuClipView = menuWindow._menuClipView,
bottom = [menuClipView bounds].size.height,
first = [menuWindow itemIndexAtPoint:CGPointMake(1, 10)],
last = [menuWindow itemIndexAtPoint:CGPointMake(1, bottom)],
current = [menu indexOfItem:[menu highlightedItem]];
if (current == CPNotFound)
{
[menu _highlightItemAtIndex:0];
return;
}
next = current + (last - first);
if (next < [menu numberOfItems])
[menu _highlightItemAtIndex:next];
else
[menu _highlightItemAtIndex:[menu numberOfItems] - 1];
var item = [menu highlightedItem];
if ([item isSeparatorItem] || [item isHidden] || ![item isEnabled])
[self moveDown:menu];
}
- (void)scrollPageUp:(CPMenu)menu
{
var menuWindow = menu._menuWindow,
menuClipView = menuWindow._menuClipView,
bottom = [menuClipView bounds].size.height,
first = [menuWindow itemIndexAtPoint:CGPointMake(1, 10)],
last = [menuWindow itemIndexAtPoint:CGPointMake(1, bottom)],
current = [menu indexOfItem:[menu highlightedItem]];
if (current == CPNotFound)
{
[menu _highlightItemAtIndex:0];
return;
}
next = current - (last - first);
if (next < 0)
[menu _highlightItemAtIndex:0];
else
[menu _highlightItemAtIndex:next];
var item = [menu highlightedItem];
if ([item isSeparatorItem] || [item isHidden] || ![item isEnabled])
[self moveUp:menu];
}
- (void)moveLeft:(CPMenu)menu
{
if ([menu supermenu])
{
if ([menu supermenu] == [CPApp mainMenu])
{
[self showMenu:nil fromMenu:[menu supermenu] atPoint:CGPointMakeZero()];
[self moveUp:[CPApp mainMenu]];
var activeItem = [[CPApp mainMenu] highlightedItem],
menuLocation = CGPointMake([[activeItem _menuItemView] frameOrigin].x , [[activeItem _menuItemView] frameSize].height);
[self showMenu:[activeItem submenu] fromMenu:[activeItem menu] atPoint:menuLocation];
}
else
[self showMenu:nil fromMenu:[menu supermenu] atPoint:CGPointMakeZero()];
}
}
- (void)moveRight:(CPMenu)menu
{
var activeItem = [menu highlightedItem];
if ([activeItem hasSubmenu])
{
if ([[activeItem submenu] numberOfItems])
{
var activeItemIndex = [menu indexOfItem:activeItem],
activeMenuContainer = menu._menuWindow,
activeItemRect = [activeMenuContainer rectForItemAtIndex:activeItemIndex],
newMenuOrigin;
if ([activeMenuContainer isMenuBar])
newMenuOrigin = CGPointMake(CGRectGetMinX(activeItemRect), CGRectGetMaxY(activeItemRect));
else
newMenuOrigin = CGPointMake(CGRectGetMaxX(activeItemRect), CGRectGetMinY(activeItemRect));
newMenuOrigin = [activeMenuContainer convertBaseToGlobal:newMenuOrigin];
[self showMenu:[activeItem submenu] fromMenu:[activeItem menu] atPoint:newMenuOrigin];
[self moveDown:[activeItem submenu]];
}
}
else if ([self trackingMenu] == [CPApp mainMenu])
{
[self showMenu:nil fromMenu:menu atPoint:CGPointMakeZero()];
[self moveDown:[CPApp mainMenu]];
var activeItem = [[CPApp mainMenu] highlightedItem],
menuLocation = CGPointMake([[activeItem _menuItemView] frameOrigin].x , [[activeItem _menuItemView] frameSize].height);
[self showMenu:[activeItem submenu] fromMenu:[activeItem menu] atPoint:menuLocation];
}
}
- (void)moveDown:(CPMenu)menu
{
var index = menu._highlightedIndex + 1;
if (index < [menu numberOfItems])
{
[menu _highlightItemAtIndex:index];
var item = [menu highlightedItem];
if ([item isSeparatorItem] || [item isHidden] || ![item isEnabled])
[self moveDown:menu];
}
}
- (void)moveUp:(CPMenu)menu
{
var index = menu._highlightedIndex - 1;
if (index < 0)
return;
[menu _highlightItemAtIndex:index];
var item = [menu highlightedItem];
if ([item isSeparatorItem] || [item isHidden] || ![item isEnabled])
[self moveUp:menu];
}
- (void)insertNewline:(CPMenu)menu
{
if ([[menu highlightedItem] hasSubmenu])
[self moveRight:menu];
else
[menu cancelTracking]
}
- (void)cancelOperation:(CPMenu)menu
{
[menu _highlightItemAtIndex:CPNotFound];
[CPEvent stopPeriodicEvents];
[[self trackingMenu] cancelTracking];
}
@end
+69 -54
View File
@@ -3,9 +3,9 @@
var _CPMenuWindowPool = [],
_CPMenuWindowPoolCapacity = 5,
_CPMenuWindowBackgroundColors = [];
_CPMenuWindowMenuBarBackgroundStyle = 0;
_CPMenuWindowPopUpBackgroundStyle = 1;
_CPMenuWindowAttachedMenuBackgroundStyle = 2;
@@ -16,7 +16,7 @@ var STICKY_TIME_INTERVAL = 500,
LEFT_MARGIN = 1.0,
RIGHT_MARGIN = 1.0,
BOTTOM_MARGIN = 5.0,
SCROLL_INDICATOR_HEIGHT = 16.0;
/*
@@ -26,10 +26,10 @@ var STICKY_TIME_INTERVAL = 500,
{
_CPMenuView _menuView;
CPClipView _menuClipView;
CPImageView _moreAboveView;
CPImageView _moreBelowView;
CGRect _unconstrainedFrame;
CGRect _constraintRect;
}
@@ -67,9 +67,9 @@ var STICKY_TIME_INTERVAL = 500,
{
if (self != [_CPMenuWindow class])
return;
var bundle = [CPBundle bundleForClass:self];
_CPMenuWindowMoreAboveImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowMoreAbove.png"] size:CGSizeMake(38.0, 18.0)];
_CPMenuWindowMoreBelowImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowMoreBelow.png"] size:CGSizeMake(38.0, 18.0)];
}
@@ -89,31 +89,31 @@ var STICKY_TIME_INTERVAL = 500,
[self setAcceptsMouseMovedEvents:YES];
var contentView = [self contentView];
_menuView = [[_CPMenuView alloc] initWithFrame:CGRectMakeZero()];
_menuClipView = [[CPClipView alloc] initWithFrame:CGRectMake(LEFT_MARGIN, TOP_MARGIN, 0.0, 0.0)];
[_menuClipView setDocumentView:_menuView];
[contentView addSubview:_menuClipView];
_moreAboveView = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
[_moreAboveView setImage:_CPMenuWindowMoreAboveImage];
[_moreAboveView setFrameSize:[_CPMenuWindowMoreAboveImage size]];
[contentView addSubview:_moreAboveView];
_moreBelowView = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
[_moreBelowView setImage:_CPMenuWindowMoreBelowImage];
[_moreBelowView setFrameSize:[_CPMenuWindowMoreBelowImage size]];
[contentView addSubview:_moreBelowView];
[self setShadowStyle:CPWindowShadowStyleMenu];
}
return self;
}
@@ -135,7 +135,7 @@ var STICKY_TIME_INTERVAL = 500,
+ (CPColor)backgroundColorForBackgroundStyle:(_CPMenuWindowBackgroundStyle)aBackgroundStyle
{
var color = _CPMenuWindowBackgroundColors[aBackgroundStyle];
if (!color)
{
var bundle = [CPBundle bundleForClass:[self class]];
@@ -146,32 +146,32 @@ var STICKY_TIME_INTERVAL = 500,
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded0.png"] size:CGSizeMake(4.0, 4.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow1.png"] size:CGSizeMake(1.0, 4.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded2.png"] size:CGSizeMake(4.0, 4.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow3.png"] size:CGSizeMake(4.0, 1.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow4.png"] size:CGSizeMake(1.0, 1.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow5.png"] size:CGSizeMake(4.0, 1.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded6.png"] size:CGSizeMake(4.0, 4.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow7.png"] size:CGSizeMake(1.0, 4.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded8.png"] size:CGSizeMake(4.0, 4.0)]
]]];
else if (aBackgroundStyle == _CPMenuWindowMenuBarBackgroundStyle)
color = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow3.png"] size:CGSizeMake(4.0, 0.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow4.png"] size:CGSizeMake(1.0, 0.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow5.png"] size:CGSizeMake(4.0, 0.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow3.png"] size:CGSizeMake(4.0, 1.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow4.png"] size:CGSizeMake(1.0, 1.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow5.png"] size:CGSizeMake(4.0, 1.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded6.png"] size:CGSizeMake(4.0, 4.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindow7.png"] size:CGSizeMake(1.0, 4.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"_CPMenuWindow/_CPMenuWindowRounded8.png"] size:CGSizeMake(4.0, 4.0)]
]]];
_CPMenuWindowBackgroundColors[aBackgroundStyle] = color;
}
@@ -187,11 +187,11 @@ var STICKY_TIME_INTERVAL = 500,
{
[aMenu _setMenuWindow:self];
[_menuView setMenu:aMenu];
var menuViewSize = [_menuView frame].size;
[self setFrameSize:CGSizeMake(LEFT_MARGIN + menuViewSize.width + RIGHT_MARGIN, TOP_MARGIN + menuViewSize.height + BOTTOM_MARGIN)];
[_menuView scrollPoint:CGPointMake(0.0, 0.0)];
[_menuClipView setFrame:CGRectMake(LEFT_MARGIN, TOP_MARGIN, menuViewSize.width, menuViewSize.height)];
}
@@ -208,10 +208,16 @@ var STICKY_TIME_INTERVAL = 500,
return [_menuView menu];
}
- (_CPMenuView)_menuView
{
return _menuView;
}
- (void)orderFront:(id)aSender
{
[[self menu] update];
[self setFrame:_unconstrainedFrame];
[super orderFront:aSender];
}
@@ -270,16 +276,16 @@ var STICKY_TIME_INTERVAL = 500,
topMargin = TOP_MARGIN,
bottomMargin = BOTTOM_MARGIN,
contentView = [self contentView],
bounds = [contentView bounds];
if (moreAbove)
{
topMargin += SCROLL_INDICATOR_HEIGHT;
var frame = [_moreAboveView frame];
[_moreAboveView setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth(frame)) / 2.0, (TOP_MARGIN + SCROLL_INDICATOR_HEIGHT - CGRectGetHeight(frame)) / 2.0)];
}
@@ -288,13 +294,18 @@ var STICKY_TIME_INTERVAL = 500,
if (moreBelow)
{
bottomMargin += SCROLL_INDICATOR_HEIGHT;
[_moreBelowView setFrameOrigin:CGPointMake((CGRectGetWidth(bounds) - CGRectGetWidth([_moreBelowView frame])) / 2.0, CGRectGetHeight(bounds) - SCROLL_INDICATOR_HEIGHT - BOTTOM_MARGIN)];
}
[_moreBelowView setHidden:!moreBelow];
var clipFrame = CGRectMake(LEFT_MARGIN, topMargin, CGRectGetWidth(constrainedFrame) - LEFT_MARGIN - RIGHT_MARGIN, CGRectGetHeight(constrainedFrame) - topMargin - bottomMargin)
var clipFrame = CGRectMakeZero();
clipFrame.origin.x = LEFT_MARGIN;
clipFrame.origin.y = topMargin;
clipFrame.size.width = CGRectGetWidth(constrainedFrame) - LEFT_MARGIN - RIGHT_MARGIN;
clipFrame.size.height = CGRectGetHeight(constrainedFrame) - topMargin - bottomMargin;
[_menuClipView setFrame:clipFrame];
[_menuView setFrameSize:CGSizeMake(CGRectGetWidth(clipFrame), CGRectGetHeight([_menuView frame]))];
@@ -347,24 +358,29 @@ var STICKY_TIME_INTERVAL = 500,
return [self canScrollUp] || [self canScrollDown];
}
- (void)scrollUp
- (void)scrollByDelta:(float)theDelta
{
if (CGRectGetMinY(_unconstrainedFrame) >= CGRectGetMinY(_constraintRect))
if (theDelta === 0.0)
return;
_unconstrainedFrame.origin.y += 10;
if (theDelta > 0.0 && ![self canScrollDown])
return;
if (theDelta < 0.0 && ![self canScrollUp])
return;
_unconstrainedFrame.origin.y -= theDelta;
[self setFrame:_unconstrainedFrame];
}
- (void)scrollUp
{
[self scrollByDelta:-10.0];
}
- (void)scrollDown
{
if (CGRectGetMaxY(_unconstrainedFrame) <= CGRectGetHeight(_constraintRect))
return;
_unconstrainedFrame.origin.y -= 10;
[self setFrame:_unconstrainedFrame];
[self scrollByDelta:10.0];
}
@end
@@ -384,16 +400,15 @@ var STICKY_TIME_INTERVAL = 500,
- (_CPManagerScrollingState)scrollingStateForPoint:(CGPoint)aGlobalLocation
{
var frame = [self frame];
if (![self canScroll])
if (!CPRectContainsPoint(frame,aGlobalLocation) || ![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)
if (aGlobalLocation.y < CGRectGetMinY(frame) + TOP_MARGIN + SCROLL_INDICATOR_HEIGHT && ![_moreAboveView isHidden])
return _CPMenuManagerScrollingStateUp;
// If we're at or below the bottom scroll indicator...
if (aGlobalLocation.y > CGRectGetMaxY(frame) - BOTTOM_MARGIN - SCROLL_INDICATOR_HEIGHT)
if (aGlobalLocation.y > CGRectGetMaxY(frame) - BOTTOM_MARGIN - SCROLL_INDICATOR_HEIGHT && ![_moreBelowView isHidden])
return _CPMenuManagerScrollingStateDown;
return _CPMenuManagerScrollingStateNone;
@@ -428,7 +443,7 @@ var STICKY_TIME_INTERVAL = 500,
{
CPArray _menuItemViews;
CPArray _visibleMenuItemInfos;
CPFont _font @accessors(property=font);
}
@@ -462,7 +477,7 @@ var STICKY_TIME_INTERVAL = 500,
while (low <= high)
{
var middle = FLOOR(low + (high - low) / 2),
info = _visibleMenuItemInfos[middle]
info = _visibleMenuItemInfos[middle],
frame = [info.view frame];
if (y < CGRectGetMinY(frame))
@@ -480,7 +495,7 @@ var STICKY_TIME_INTERVAL = 500,
- (void)tile
{
[_menuItemViews makeObjectsPerformSelector:@selector(removeFromSuperview)];
[_menuItemViews makeObjectsPerformSelector:@selector(removeFromSuperview)];
_menuItemViews = [];
_visibleMenuItemInfos = [];
@@ -500,15 +515,15 @@ var STICKY_TIME_INTERVAL = 500,
for (; index < count; ++index)
{
var item = items[index],
view = [item _menuItemView];
view = [item _menuItemView];
_menuItemViews.push(view);
if ([item isHidden])
continue;
_visibleMenuItemInfos.push({ view:view, index:index });
[view setFont:_font];
[view setShowsStateColumn:showsStateColumn];
[view synchronizeWithMenuItem];
+36 -9
View File
@@ -30,6 +30,25 @@
@import "_CPMenuItemView.j"
var CPMenuItemStringRepresentationDictionary = [CPDictionary dictionary];
[CPMenuItemStringRepresentationDictionary setObject:"\u238B" forKey:CPEscapeFunctionKey];
[CPMenuItemStringRepresentationDictionary setObject:"\u21E5" forKey:CPTabCharacter];
[CPMenuItemStringRepresentationDictionary setObject:"\u21E4" forKey:CPBackTabCharacter];
[CPMenuItemStringRepresentationDictionary setObject:"\u2423" forKey:CPSpaceFunctionKey];
[CPMenuItemStringRepresentationDictionary setObject:"\u23CE" forKey:CPCarriageReturnCharacter];
[CPMenuItemStringRepresentationDictionary setObject:"\u232B" forKey:CPBackspaceCharacter];
[CPMenuItemStringRepresentationDictionary setObject:"\u232B" forKey:CPDeleteFunctionKey];
[CPMenuItemStringRepresentationDictionary setObject:"\u2326" forKey:CPDeleteCharacter];
[CPMenuItemStringRepresentationDictionary setObject:"\u21F1" forKey:CPHomeFunctionKey];
[CPMenuItemStringRepresentationDictionary setObject:"\u21F2" forKey:CPEndFunctionKey];
[CPMenuItemStringRepresentationDictionary setObject:"\u21DE" forKey:CPPageUpFunctionKey];
[CPMenuItemStringRepresentationDictionary setObject:"\u21DF" forKey:CPPageDownFunctionKey];
[CPMenuItemStringRepresentationDictionary setObject:"\u2191" forKey:CPUpArrowFunctionKey];
[CPMenuItemStringRepresentationDictionary setObject:"\u2193" forKey:CPDownArrowFunctionKey];
[CPMenuItemStringRepresentationDictionary setObject:"\u2190" forKey:CPLeftArrowFunctionKey];
[CPMenuItemStringRepresentationDictionary setObject:"\u2192" forKey:CPRightArrowFunctionKey];
[CPMenuItemStringRepresentationDictionary setObject:"\u2327" forKey:CPClearDisplayFunctionKey];
/*!
@ingroup appkit
@class CPMenuItem
@@ -130,13 +149,12 @@
*/
- (void)setEnabled:(BOOL)isEnabled
{
if ([_menu autoenablesItems])
if (_isEnabled === isEnabled)
return;
_isEnabled = isEnabled;
_isEnabled = !!isEnabled;
[_menuItemView setDirty];
[_menu itemChanged:self];
}
@@ -449,7 +467,7 @@ CPOffState
return _mixedStateImage;
}
// Managing Subemenus
// Managing Submenus
/*!
Sets the submenu for this item
@param aMenu the submenu
@@ -470,6 +488,7 @@ CPOffState
if (_submenu)
{
[_submenu setSupermenu:_menu];
[_submenu setTitle:[self title]]
[self setTarget:_menu];
[self setAction:@selector(submenuAction:)];
@@ -599,19 +618,22 @@ CPControlKeyMask
needsShift = _keyEquivalentModifierMask & CPShiftKeyMask ||
(string === _keyEquivalent && _keyEquivalent.toLowerCase() !== _keyEquivalent.toUpperCase());
if ([CPMenuItemStringRepresentationDictionary objectForKey:string])
string = [CPMenuItemStringRepresentationDictionary objectForKey:string];
if (CPBrowserIsOperatingSystem(CPMacOperatingSystem))
{
if (_keyEquivalentModifierMask & CPCommandKeyMask)
string = "" + string;
string = "\u2318" + string;
if (needsShift)
string = "" + string;
string = "\u21E7" + string;
if (_keyEquivalentModifierMask & CPAlternateKeyMask)
string = "" + string;
string = "\u2325" + string;
if (_keyEquivalentModifierMask & CPControlKeyMask)
string = "^" + string;
string = "\u2303" + string;
}
else
{
@@ -648,7 +670,7 @@ CPControlKeyMask
}
/*!
Sets the title of the menu item and the mnemonic character. The mnemonic chracter should be preceded by an '&'.
Sets the title of the menu item and the mnemonic character. The mnemonic character should be preceded by an '&'.
@param aTitle the title string with a denoted mnemonic
*/
- (void)setTitleWithMnemonicLocation:(CPString)aTitle
@@ -851,6 +873,11 @@ CPControlKeyMask
return ![self submenu] && [self menu] === [CPApp mainMenu];
}
- (CPString)description
{
return [super description] + @" target: " + [self target] + @" action: " + CPStringFromSelector([self action]);
}
@end
var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
+8 -8
View File
@@ -9,7 +9,7 @@ var SelectionColor = nil,
SUBMENU_INDICATOR_COLOR = nil,
_CPMenuItemSelectionColor = nil,
_CPMenuItemTextShadowColor = nil,
_CPMenuItemDefaultStateImages = [],
_CPMenuItemDefaultStateHighlightedImages = [];
@@ -40,7 +40,7 @@ var SelectionColor = nil,
_CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0];
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0];
_CPMenuItemDefaultStateImages[CPOffState] = nil;
_CPMenuItemDefaultStateHighlightedImages[CPOffState] = nil;
@@ -141,7 +141,7 @@ var SelectionColor = nil,
imageAndTextViewFrame.origin.y = FLOOR((height - CGRectGetHeight(imageAndTextViewFrame)) / 2.0);
[_imageAndTextView setFrame:imageAndTextViewFrame];
if (hasSubmenuIndicator)
{
submenuViewFrame.origin.y = FLOOR((height - CGRectGetHeight(submenuViewFrame)) / 2.0) + 1.0;
@@ -149,7 +149,7 @@ var SelectionColor = nil,
}
_minSize = CGSizeMake(x + HORIZONTAL_MARGIN, height);
[self setAutoresizesSubviews:NO];
[self setFrameSize:_minSize];
[self setAutoresizesSubviews:YES];
@@ -218,19 +218,19 @@ var SelectionColor = nil,
{
var context = [[CPGraphicsContext currentContext] graphicsPort],
bounds = [self bounds];
bounds.size.height -= 1.0;
bounds.size.width -= 2.0;
bounds.origin.x += 1.0;
CGContextBeginPath(context);
CGContextMoveToPoint(context, CGRectGetMinX(bounds), CGRectGetMinY(bounds));
CGContextAddLineToPoint(context, CGRectGetMaxX(bounds), CGRectGetMinY(bounds));
CGContextAddLineToPoint(context, CGRectGetMidX(bounds), CGRectGetMaxY(bounds));
CGContextClosePath(context);
CGContextSetShadowWithColor(context, CGSizeMake(0.0, 1.0), 1.1, _shadowColor || [CPColor whiteColor]);
CGContextSetFillColor(context, _color || [CPColor blackColor]);
CGContextFillPath(context);
+2 -2
View File
@@ -27,10 +27,10 @@
bounds = [self bounds];
CGContextBeginPath(context);
CGContextMoveToPoint(context, CGRectGetMinX(bounds), FLOOR(CGRectGetMidY(bounds)) - 0.5);
CGContextAddLineToPoint(context, CGRectGetMaxX(bounds), FLOOR(CGRectGetMidY(bounds)) - 0.5);
CGContextSetStrokeColor(context, [CPColor lightGrayColor]);
CGContextStrokePath(context);
}
+17 -18
View File
@@ -11,10 +11,10 @@ var LEFT_MARGIN = 3.0,
STATE_COLUMN_WIDTH = 14.0,
INDENTATION_WIDTH = 17.0,
VERTICAL_MARGIN = 4.0;
var _CPMenuItemSelectionColor = nil,
_CPMenuItemTextShadowColor = nil,
_CPMenuItemDefaultStateImages = [],
_CPMenuItemDefaultStateHighlightedImages = [];
@@ -34,7 +34,6 @@ var _CPMenuItemSelectionColor = nil,
BOOL _isDirty;
BOOL _showsStateColumn;
CPImageView _stateView;
_CPImageAndTextView _imageAndTextView;
CPView _submenuView;
}
@@ -43,12 +42,12 @@ var _CPMenuItemSelectionColor = nil,
{
if (self != [_CPMenuItemView class])
return;
_CPMenuItemSelectionColor = [CPColor colorWithCalibratedRed:95.0 / 255.0 green:131.0 / 255.0 blue:185.0 / 255.0 alpha:1.0];
_CPMenuItemTextShadowColor = [CPColor colorWithCalibratedRed:26.0 / 255.0 green: 73.0 / 255.0 blue:109.0 / 255.0 alpha:1.0];
var bundle = [CPBundle bundleForClass:self];
_CPMenuItemDefaultStateImages[CPOffState] = nil;
_CPMenuItemDefaultStateHighlightedImages[CPOffState] = nil;
@@ -73,12 +72,12 @@ var _CPMenuItemSelectionColor = nil,
_menuItem = aMenuItem;
_showsStateColumn = YES;
_isDirty = YES;
[self setAutoresizingMask:CPViewWidthSizable];
[self synchronizeWithMenuItem];
}
return self;
}
@@ -112,7 +111,7 @@ var _CPMenuItemSelectionColor = nil,
_view = menuItemView;
}
}
else if ([_menuItem menu] == [CPApp mainMenu])
{
if (![_view isKindOfClass:[_CPMenuItemMenuBarView class]])
@@ -130,7 +129,7 @@ var _CPMenuItemSelectionColor = nil,
[_view removeFromSuperview];
_view = [_CPMenuItemStandardView view];
}
[_view setMenuItem:_menuItem];
}
@@ -161,7 +160,7 @@ var _CPMenuItemSelectionColor = nil,
{
if (![_menuItem hasSubmenu])
return NO;
return CGRectContainsPoint([_submenuView frame], [self convertPoint:[anEvent locationInWindow] fromView:nil]);
}
@@ -192,7 +191,7 @@ var _CPMenuItemSelectionColor = nil,
{
if (_textColor == aColor)
return;
_textColor = aColor;
[_imageAndTextView setTextColor:[self textColor]];
@@ -208,7 +207,7 @@ var _CPMenuItemSelectionColor = nil,
{
if (_textShadowColor == aColor)
return;
_textShadowColor = aColor;
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
@@ -233,23 +232,23 @@ var _CPMenuItemSelectionColor = nil,
return;
_color = aColor;
[self setNeedsDisplay:YES];
}
- (void)drawRect:(CGRect)aRect
{
var context = [[CPGraphicsContext currentContext] graphicsPort];
CGContextBeginPath(context);
CGContextMoveToPoint(context, 1.0, 4.0);
CGContextAddLineToPoint(context, 9.0, 4.0);
CGContextAddLineToPoint(context, 5.0, 8.0);
CGContextAddLineToPoint(context, 1.0, 4.0);
CGContextClosePath(context);
CGContextSetFillColor(context, _color);
CGContextFillPath(context);
}
+48 -7
View File
@@ -1,3 +1,24 @@
/*
* CPObjectController.j
* AppKit
*
* Created by Ross Boucher.
* Copyright 2009, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPDictionary.j>
@import <Foundation/CPCountedSet.j>
@@ -73,7 +94,7 @@
/*!
Inits and returns a CPObjectController object with the given content.
@param id aContent - The object the conroller will use.
@param id aContent - The object the controller will use.
@return id the CPObjectConroller instance.
*/
- (id)initWithContent:(id)aContent
@@ -110,8 +131,8 @@
_contentObject = aContent;
[self didChangeValueForKey:@"contentObject"];
[self _selectionDidChange];
[self didChangeValueForKey:@"contentObject"];
}
/*!
@@ -152,7 +173,7 @@
}
/*!
Overridden by a subclass that require control over the creation of new objects.
Overridden by a subclass that require control over the creation of new objects.
*/
- (void)prepareContent
{
@@ -209,7 +230,7 @@
/*!
Removes a given object from the controller.
@param id anObject - The object to remove from the reciver.
@param id anObject - The object to remove from the receiver.
*/
- (void)removeObject:(id)anObject
{
@@ -258,7 +279,7 @@
/*!
Sets whether the controller allows for the editing of the content.
@param BOOL shouldBeEditable - YES if the content should be editable, otherwise NO.
@param BOOL shouldBeEditable - YES if the content should be editable, otherwise NO.
*/
- (void)setEditable:(BOOL)shouldBeEditable
{
@@ -372,6 +393,12 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
[aCoder encodeBool:[self automaticallyPreparesContent] forKey:CPObjectControllerAutomaticallyPreparesContentKey];
}
- (void)awakeFromCib
{
if (![self content] && [self automaticallyPreparesContent])
[self prepareContent];
}
@end
@implementation _CPObservationProxy : CPObject
@@ -471,7 +498,7 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
- (CPString)description
{
return "<_CPObservableArray: "+[super description]+" >";
return "<_CPObservableArray: " + [super description] + " >";
}
- (id)initWithArray:(CPArray)anArray
@@ -636,7 +663,7 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
- (id)_controllerMarkerForValues:(CPArray)theValues
{
var count = [theValues count];
var count = [theValues count];
if (!count)
value = CPNoSelectionMarker;
@@ -658,6 +685,9 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
}
}
if (value === nil || value.isa && [value isEqual:[CPNull null]])
value = CPNullMarker;
return value;
}
@@ -680,6 +710,17 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
{
[[_controller selectedObjects] setValue:theValue forKeyPath:theKeyPath];
[_cachedValues removeObjectForKey:theKeyPath];
// Allow handlesContentAsCompoundValue to work, based on observation of Cocoa's
// NSArrayController - when handlesContentAsCompoundValue and setValue:forKey:@"selection.X"
// is called, the array controller causes the compound value to be rewritten if
// handlesContentAsCompoundValue == YES. Note that
// A) this doesn't use observation (observe: X is not visible in backtraces)
// B) it only happens through the selection proxy and not on arrangedObject.X, content.X
// or even selectedObjects.X.
// FIXME The main code for this should somehow be in CPArrayController and also work
// for table based row edits.
[[CPBinder getBinding:@"contentArray" forObject:_controller] _contentArrayDidChange];
}
- (void)setValue:(id)theValue forKey:(CPString)theKeyPath
+21
View File
@@ -1,3 +1,24 @@
/*
* CPOpenPanel.j
* AppKit
*
* Created by Ross Boucher.
* Copyright 2009, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPPanel.j"
+238 -127
View File
@@ -71,7 +71,8 @@ var CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_
CPOutlineViewDelegate_outlineView_typeSelectStringForTableColumn_item_ = 1 << 21,
CPOutlineViewDelegate_outlineView_willDisplayOutlineView_forTableColumn_item_ = 1 << 22,
CPOutlineViewDelegate_outlineView_willDisplayView_forTableColumn_item_ = 1 << 23,
CPOutlineViewDelegate_selectionShouldChangeInOutlineView_ = 1 << 24;
CPOutlineViewDelegate_selectionShouldChangeInOutlineView_ = 1 << 24,
CPOutlineViewDelegate_outlineView_menuForTableColumn_item_ = 1 << 25;
CPOutlineViewDropOnItemIndex = -1;
@@ -83,12 +84,16 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
@ingroup appkit
@class CPOutlineView
CPOutlineView is a subclass of CPTableView that inherates the row and column format to display hierarchial data.
The outlineview adds the ability to expand and collapse items. This is useful for browsing a tree like structure such as directories or a filesystem.
CPOutlineView is a subclass of CPTableView that inherits the row and
column format to display hierarchical data. The outlineview adds the
ability to expand and collapse items. This is useful for browsing a tree
like structure such as directories or a filesystem.
Like the tableview, an outlineview uses a data source to supply its data. For this reason you must implement a couple data source methods (documented in setDataSource:)
Like the tableview, an outlineview uses a data source to supply its data.
For this reason you must implement a couple data source methods
(documented in setDataSource:).
Theme states for custom data views are documented in CPTableView
Theme states for custom data views are documented in CPTableView.
*/
@implementation CPOutlineView : CPTableView
{
@@ -156,53 +161,55 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
return self;
}
/*!
<pre>
In addition to standard delegation, the outline view also supports data source delegation. This method sets the data source object.
Just like the TableView you have CPTableColumns but instead of rows you deal with items.
In addition to standard delegation, the outline view also supports data
source delegation. This method sets the data source object. Just like the
TableView you have CPTableColumns but instead of rows you deal with items.
You must implement these data source methods:
@section required You must implement these data source methods:
- (id)outlineView:(CPOutlineView)outlineView child:(CPInteger)index ofItem:(id)item;
Returns the child item at an index of a given item. if item is nil you should return the appropriate root item.
Returns the child item at an index of a given item. if item is nil you should return the appropriate root item.
@code - (id)outlineView:(CPOutlineView)outlineView child:(CPInteger)index ofItem:(id)item; @endcode
- (BOOL)outlineView:(CPOutlineView)outlineView isItemExpandable:(id)item;
Returns YES if the item is expandable, otherwise NO.
Returns YES if the item is expandable, otherwise NO.
@code - (BOOL)outlineView:(CPOutlineView)outlineView isItemExpandable:(id)item; @endcode
- (int)outlineView:(CPOutlineView)outlineView numberOfChildrenOfItem:(id)item;
Returns the number of child items of a given item. If item is nil you should return the number of top level (root) items.
Returns the number of child items of a given item. If item is nil you should return the number of top level (root) items.
@code - (int)outlineView:(CPOutlineView)outlineView numberOfChildrenOfItem:(id)item; @endcode
- (id)outlineView:(CPOutlineView)outlineView objectValueForTableColumn:(CPTableColumn)tableColumn byItem:(id)item;
Returns the object value of the item in a given column.
Returns the object value of the item in a given column.
@code - (id)outlineView:(CPOutlineView)outlineView objectValueForTableColumn:(CPTableColumn)tableColumn byItem:(id)item; @endcode
---------
@section optional The following methods are optional:
@section editin Editing:
Sets the data object value for an item in a given column. This needs to be implemented if you want inline editing support.
@code - (void)outlineView:(CPOutlineView)outlineView setObjectValue:(id)object forTableColumn:(CPTableColumn)tableColumn byItem:(id)item; @endcode
The following methods are optional:
@section sorting Sorting:
The outlineview will call this method if you click the table header. You should sort the datasource based off of the new sort descriptors and reload the data
@code - (void)outlineView:(CPOutlineView)outlineView sortDescriptorsDidChange:(CPArray)oldDescriptors; @endcode
Editing:
- (void)outlineView:(CPOutlineView)outlineView setObjectValue:(id)object forTableColumn:(CPTableColumn)tableColumn byItem:(id)item;
Sets the data object value for an item in a given column. This needs to be implemented if you want inline editing support.
@section draganddrop Drag and Drop:
@note In order for the outlineview to receive drops don't forget to first
register the tableview for drag types like you do with every other view @endnote
Return YES if the operation was successful otherwise return NO.
The data source should incorporate the data from the dragging pasteboard in this method implementation.
To get this data use the draggingPasteboard method on the CPDraggingInfo object.
@code - (BOOL)outlineView:(CPOutlineView)outlineView acceptDrop:(id < CPDraggingInfo >)info item:(id)item childIndex:(CPInteger)index; @endcode
Sorting:
- (void)outlineView:(CPOutlineView)outlineView sortDescriptorsDidChange:(CPArray)oldDescriptors;
The outlineview will call this method if you click the tableheader. You should sort the datasource based off of the new sort descriptors and reload the data
Return the drag operation (move, copy, etc) that should be performed if a registered drag type is over the tableview
The data source can retarget a drop if you want by calling <pre>-(void)setDropItem:(id)anItem dropChildIndex:(int)anIndex;</pre>
@code - (CPDragOperation)outlineView:(CPOutlineView)outlineView validateDrop:(id < CPDraggingInfo >)info proposedItem:(id)item proposedChildIndex:(CPInteger)index; @endcode
Drag and Drop:
In order for the outlineview to recieve drops dont forget to first register the tableview for drag types like you do with every other view
- (BOOL)outlineView:(CPOutlineView)outlineView acceptDrop:(id < CPDraggingInfo >)info item:(id)item childIndex:(CPInteger)index;
Return YES if the operation was successful otherwise return NO.
The data source should incorporate the data from the dragging pasteboard in this method implementation.
To get this data use the draggingPasteboard method on the CPDraggingInfo object.
- (CPDragOperation)outlineView:(CPOutlineView)outlineView validateDrop:(id < CPDraggingInfo >)info proposedItem:(id)item proposedChildIndex:(CPInteger)index;
Return the drag operation (move, copy, etc) that should be performaned if a registered drag type is over the tableview
The data source can retarget a drop if you want by calling -(void)setDropItem:(id)anItem dropChildIndex:(int)anIndex;
- (BOOL)outlineView:(CPOutlineView)outlineView writeItems:(CPArray)items toPasteboard:(CPPasteboard)pboard;
Returns YES if the drop operation is allowed otherwise NO.
This method is invoked by the outlineview after a drag should begin, but before it is started. If you dont want the drag to being return NO.
If you want the drag to begin you should return YES and place the drag data on the pboard.
</pre>
Returns YES if the drop operation is allowed otherwise NO.
This method is invoked by the outlineview after a drag should begin, but before it is started. If you don't want the drag to being return NO.
If you want the drag to begin you should return YES and place the drag data on the pboard.
@code - (BOOL)outlineView:(CPOutlineView)outlineView writeItems:(CPArray)items toPasteboard:(CPPasteboard)pboard; @endcode
*/
- (void)setDataSource:(id)aDataSource
{
@@ -259,6 +266,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
/*!
Returns the datasource object.
@return id - The data source object
*/
- (id)dataSource
@@ -287,7 +295,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
}
/*!
Used to find if an item is already expanded.
Used to find if an item is already expanded.
@param anItem - the item you are interest in.
@@ -307,7 +315,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
}
/*!
Expends a given item.
Expands a given item.
@param anItem - the item to expand.
*/
@@ -335,8 +343,8 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
return;
// When shouldExpandChildren is YES, we need to make sure we're collecting
// selection notifications so that exactly one IsChanging and one DidChange
// is sent as needed, for the totallity of the operation.
// selection notifications so that exactly one IsChanging and one
// DidChange is sent as needed, for the totality of the operation.
var isTopLevel = NO;
if (!_coalesceSelectionNotificationState)
{
@@ -344,7 +352,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
_coalesceSelectionNotificationState = CPOutlineViewCoalesceSelectionNotificationStateOn;
}
// to prevent items which are already expanded from firing notifications
// To prevent items which are already expanded from firing notifications.
if (!itemInfo.isExpanded)
{
[self _noteItemWillExpand:anItem];
@@ -486,7 +494,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
/*!
Returns the item at a given row index. If no item exists nil is returned.
@param aRow - The rown index you want to find the item at.
@param aRow - The row index you want to find the item at.
@return id - The item at a given index.
*/
- (id)itemAtRow:(CPInteger)aRow
@@ -514,8 +522,9 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
}
/*!
Sets the table column you want to display the disclosure button in.
If you do not want an outline column pass nil.
Sets the table column you want to display the disclosure button in. If you
do not want an outline column pass nil.
@param aTableColumn - The CPTableColumn you want to use for hierarchical data.
*/
- (void)setOutlineTableColumn:(CPTableColumn)aTableColumn
@@ -540,7 +549,9 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
}
/*!
Returns the indentation level of a given item. If the item is nil (the top level root item) CPNotFound is returned. Indentation levels are zero based, thus items that are not indented return 0.
Returns the indentation level of a given item. If the item is nil (the top
level root item) CPNotFound is returned. Indentation levels are zero
based, thus items that are not indented return 0.
@param anItem - The item you want the indentation level for.
@return int - the indentation level of anItem.
@@ -559,9 +570,10 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
}
/*!
Returns the indentation level for a given row. If the row is invalid CPNotFound is returned. Rows that are nto indented return 0.
Returns the indentation level for a given row. If the row is invalid
CPNotFound is returned. Rows that are not indented return 0.
@param aRow - the row of the reciever
@param aRow - the row of the receiver
@return int - the indentation level of aRow.
*/
- (CPInteger)levelForRow:(CPInteger)aRow
@@ -596,7 +608,9 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
}
/*!
Sets the layout behaviour of disclosure button. If you pass NO the disclosure button will always align itself to the left of the outline column.
Sets the layout behavior of disclosure button. If you pass NO the
disclosure button will always align itself to the left of the outline
column.
@param indentationMarkerShouldFollowDataView - Pass YES if the disclosure control should be indented along with the dataview, otherwise NO.
*/
@@ -612,9 +626,11 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
}
/*!
Returns the layout behaviour of the disclosure buttons.
Returns the layout behavior of the disclosure buttons.
@return BOOL - YES if the disclosure control indents itself with the dataview, otherwise NO if the control is always aligned to the left of the outline column
@return BOOL - YES if the disclosure control indents itself with the
dataview, otherwise NO if the control is always aligned to the left of
the outline column
*/
- (BOOL)indentationMarkerFollowsDataView
{
@@ -624,8 +640,9 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
/*!
Returns the parent item for a given item. If the item is a top level root object nil is returned.
@param anItem - The item of the reciver.
@return id - The parent item of anItem. If no parent exists (the item is a root item) nil is returned.
@param anItem - The item of the receiver.
@return id - The parent item of anItem. If no parent exists (the item is a
root item) nil is returned.
*/
- (id)parentForItem:(id)anItem
{
@@ -649,7 +666,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
/*!
@ignore
Returns the frame of the dataview at the row given for the outline column
Returns the frame of the dataview at the row given for the outline column.
*/
- (CGRect)_frameOfOutlineDataViewAtRow:(CPInteger)aRow
{
@@ -664,11 +681,11 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
}
/*!
Returns the frame of the disclosure button for the outline column.
If the item is not expandable a CGZeroRect is returned.
Subclasses can return a CGZeroRect to prevent the disclosure control from being displayed.
Returns the frame of the disclosure button for the outline column. If the
item is not expandable a CGZeroRect is returned. Subclasses can return a
CGZeroRect to prevent the disclosure control from being displayed.
@param aRow - The row of the reciever
@param aRow - The row of the receiver
@return CGRect - The rect of the disclosure button at aRow.
*/
- (CGRect)frameOfOutlineDisclosureControlAtRow:(CPInteger)aRow
@@ -684,7 +701,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
/*!
@ignore
Select or deselect rows, this is overridden because we need to change the color or the outline control
Select or deselect rows, this is overridden because we need to change the color or the outline control.
*/
- (void)_performSelection:(BOOL)select forRow:(CPInteger)rowIndex context:(id)context
{
@@ -697,68 +714,80 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
}
/*!
<pre>
Sets the delegate for the outlineview.
The following methods can be implemented:
@param aDelegate - the delegate object you wish to set for the receiver.
User Interaction Notifications:
- (void)outlineViewColumnDidMove:(CPNotification)notification;
Called when the user moves a column in the outlineview.
@section notifications User Interaction Notifications:
- (void)outlineViewColumnDidResize:(CPNotification)notification;
Called when the user resizes a column in the outlineview.
Called when the user moves a column in the outlineview.
@code - (void)outlineViewColumnDidMove:(CPNotification)notification; @endcode
- (void)outlineViewItemDidCollapse:(CPNotification)notification;
Called when the user collapses an item in teh outlineview.
Called when the user resizes a column in the outlineview.
@code - (void)outlineViewColumnDidResize:(CPNotification)notification; @endcode
- (void)outlineViewItemDidExpand:(CPNotification)notification;
Called when the user expands an item in the outlineview.
Called when the user collapses an item in the outlineview.
@code - (void)outlineViewItemDidCollapse:(CPNotification)notification; @endcode
- (void)outlineViewItemWillCollapse:(CPNotification)notification;
Called when the user collapses an item in the outlineview, but before the item is actually collapsed.
Called when the user expands an item in the outlineview.
@code - (void)outlineViewItemDidExpand:(CPNotification)notification; @endcode
- (void)outlineViewItemWillExpand:(CPNotification)notification;
Called when the used expands an item, but before the item is actually expanded.
Called when the user collapses an item in the outlineview, but before the item is actually collapsed.
@code - (void)outlineViewItemWillCollapse:(CPNotification)notification; @endcode
- (void)outlineViewSelectionDidChange:(CPNotification)notification;
Called when the user changes the selection of the outlineview.
Called when the used expands an item, but before the item is actually expanded.
@code - (void)outlineViewItemWillExpand:(CPNotification)notification; @endcode
- (void)outlineViewSelectionIsChanging:(CPNotification)notification
Called when the user changes the selection of the outlineview, but before the change is made.
Called when the user changes the selection of the outlineview.
@code - (void)outlineViewSelectionDidChange:(CPNotification)notification; @endcode
Expanding and collapsing items:
- (BOOL)outlineView:(CPOutlineView)outlineView shouldExpandItem:(id)item;
Return YES if the item should be given permission to expand, otherwise NO.
Called when the user changes the selection of the outlineview, but before the change is made.
@code - (void)outlineViewSelectionIsChanging:(CPNotification)notification; @endcode
- (BOOL)outlineView:(CPOutlineView)outlineView shouldCollapseItem:(id)item;
Return YES if the item should be given permission to collapse, otherwise NO.
@section expandingandcollapsing Expanding and collapsing items:
Selection:
- (BOOL)outlineView:(CPOutlineView)outlineView shouldSelectTableColumn:(CPTableColumn)tableColumn;
Return YES to allow the selection of tableColumn, otherwise NO.
Return YES if the item should be given permission to expand, otherwise NO.
@code - (BOOL)outlineView:(CPOutlineView)outlineView shouldExpandItem:(id)item; @endcode
- (BOOL)outlineView:(CPOutlineView)outlineView shouldSelectItem:(id)item;
Return YES to allow the selection of an item, otherwise NO.
Return YES if the item should be given permission to collapse, otherwise NO.
@code - (BOOL)outlineView:(CPOutlineView)outlineView shouldCollapseItem:(id)item; @endcode
- (BOOL)selectionShouldChangeInOutlineView:(CPOutlineView)outlineView;
Return YES to allow the selection of the outlineview to be changed, otherwise NO.
@section selection Selection:
Return YES to allow the selection of tableColumn, otherwise NO.
@code- (BOOL)outlineView:(CPOutlineView)outlineView shouldSelectTableColumn:(CPTableColumn)tableColumn; @endcode
Displaying DataViews:
- (void)outlineView:(CPOutlineView)outlineView willDisplayView:(id)dataView forTableColumn:(CPTableColumn)tableColumn item:(id)item;
Called when a dataView is about to be displayed. This gives you the ability to alter the dataView if needed.
Return YES to allow the selection of an item, otherwise NO.
@code- (BOOL)outlineView:(CPOutlineView)outlineView shouldSelectItem:(id)item; @endcode
Editing:
- (BOOL)outlineView:(CPOutlineView)outlineView shouldEditTableColumn:(CPTableColumn)tableColumn item:(id)item;
Return YES to allow for editing of a dataview at given item and tableColumn, otherwise NO to prevent the edit.
Return YES to allow the selection of the outlineview to be changed, otherwise NO.
@code - (BOOL)selectionShouldChangeInOutlineView:(CPOutlineView)outlineView; @endcode
Group Items:
- (BOOL)outlineView:(CPOutlineView)outlineView isGroupItem:(id)item;
Implement this to indicate whether a given item should be rendered using the group item style.
Return YES if the item is a group item, otherwise NO.
@section dataviews Displaying DataViews:
Called when a dataView is about to be displayed. This gives you the ability to alter the dataView if needed.
@code - (void)outlineView:(CPOutlineView)outlineView willDisplayView:(id)dataView forTableColumn:(CPTableColumn)tableColumn item:(id)item; @endcode
@section editin Editing:
Return YES to allow for editing of a dataview at given item and tableColumn, otherwise NO to prevent the edit.
@code - (BOOL)outlineView:(CPOutlineView)outlineView shouldEditTableColumn:(CPTableColumn)tableColumn item:(id)item; @endcode
@section groups Group Items:
Implement this to indicate whether a given item should be rendered using the group item style.
Return YES if the item is a group item, otherwise NO.
@code - (BOOL)outlineView:(CPOutlineView)outlineView isGroupItem:(id)item; @endcode
@section variableitems Variable Item Heights
Implement this method to get custom heights of rows based on the item.
This delegate method will be passed your 'item' object and expects you to return an integer height.
@note This should only be implemented if rows will be different heights, if you want to set a height for ALL of your rows see -setRowHeight:@endnote
@code - (int)outlineView:(CPOutlineView)outlineView heightOfRowByItem:(id)anItem; @endcode
@param aDelegate - the delegate object you wish to set for the reciever.
<pre>
*/
- (void)setDelegate:(id)aDelegate
{
@@ -850,7 +879,8 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
CPOutlineViewDelegate_outlineView_typeSelectStringForTableColumn_item_ , @selector(outlineView:typeSelectStringForTableColumn:item:),
CPOutlineViewDelegate_outlineView_willDisplayOutlineView_forTableColumn_item_ , @selector(outlineView:willDisplayOutlineView:forTableColumn:item:),
CPOutlineViewDelegate_outlineView_willDisplayView_forTableColumn_item_ , @selector(outlineView:willDisplayView:forTableColumn:item:),
CPOutlineViewDelegate_selectionShouldChangeInOutlineView_ , @selector(selectionShouldChangeInOutlineView:)
CPOutlineViewDelegate_selectionShouldChangeInOutlineView_ , @selector(selectionShouldChangeInOutlineView:),
CPOutlineViewDelegate_outlineView_menuForTableColumn_item_ , @selector(outlineView:menuForTableColumn:item:)
],
delegateCount = [delegateMethods count];
@@ -922,6 +952,17 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
}
- (BOOL)_sendDelegateDeleteKeyPressed
{
if ([[self delegate] respondsToSelector: @selector(outlineViewDeleteKeyPressed:)])
{
[[self delegate] outlineViewDeleteKeyPressed:self];
return YES;
}
return NO;
}
/*!
Returns the delegate object for the outlineview.
*/
@@ -931,8 +972,9 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
}
/*!
Sets the prototype of the disclosure control. This is used if you want to set a special type of button, instead of the default triangle.
The control must implement CPCoding.
Sets the prototype of the disclosure control. This is used if you want to
set a special type of button, instead of the default triangle. The control
must implement CPCoding.
@param aControl - the control to be used to expand and collapse items.
*/
@@ -942,7 +984,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
_disclosureControlData = nil;
_disclosureControlQueue = [];
// fIXME: reall?
// fIXME: really?
[self reloadData];
}
@@ -955,9 +997,13 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
}
/*!
Adds a new table column to the reciever. If this is the first column added it will automatically be set to the outline column.
Also see -setOutlineTableColumn:
NOTE: This behavior deviates from cocoa slightly.
Adds a new table column to the receiver. If this is the first column added
it will automatically be set to the outline column.
Also see -setOutlineTableColumn:.
@note This behavior deviates from cocoa slightly.
@param CPTableColumn aTableColumn - The table column to add.
*/
- (void)addTableColumn:(CPTableColumn)aTableColumn
@@ -979,7 +1025,8 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
}
/*!
@ignore
We overide this because we need a special behaviour for the outline column
We override this because we need a special behavior for the outline
column.
*/
- (CGRect)frameOfDataViewAtColumn:(CPInteger)aColumn row:(CPInteger)aRow
{
@@ -993,7 +1040,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
/*!
@ignore
we need to offset the dataview and add the dislosure triangle
We need to offset the dataview and add the disclosure triangle.
*/
- (CPView)_dragViewForColumn:(int)theColumnIndex event:(CPEvent)theDragEvent offset:(CPPointPointer)theDragViewOffset
{
@@ -1053,9 +1100,15 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
/*!
Retargets the drop item for the outlineview.
To specify a drop on theItem, you specify item as theItem and index as CPOutlineViewDropOnItemIndex.
To specify a drop between child 1 and 2 of theItem, you specify item as theItem and index as 2.
To specify a drop on an item that can't be expanded theItem, you specify item as someOutlineItem and index as CPOutlineViewDropOnItemIndex.
To specify a drop on theItem, you specify item as theItem and index as
CPOutlineViewDropOnItemIndex.
To specify a drop between child 1 and 2 of theItem, you specify item as
theItem and index as 2.
To specify a drop on an item that can't be expanded theItem, you specify
item as someOutlineItem and index as CPOutlineViewDropOnItemIndex.
@param theItem - The item you want to retarget the drop on.
@param theIndex - The index of the child item you want to retarget the drop between. Pass CPOutlineViewDropOnItemIndex if you want to drop on theItem.
@@ -1165,7 +1218,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
/*!
@ignore
We need to move the disclosure control too
We need to move the disclosure control too.
*/
- (void)_layoutDataViewsInRows:(CPIndexSet)rows columns:(CPIndexSet)columns
{
@@ -1405,6 +1458,44 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
userInfo:[CPDictionary dictionaryWithObject:item forKey:"CPObject"]];
}
- (void)keyDown:(CPEvent)anEvent
{
var character = [anEvent charactersIgnoringModifiers],
modifierFlags = [anEvent modifierFlags];
// Check for the key events manually, as opposed to waiting for CPWindow to sent the actual action message
// in _processKeyboardUIKey:, because we might not want to handle the arrow events.
if (character !== CPRightArrowFunctionKey && character !== CPLeftArrowFunctionKey)
return [super keyDown:anEvent];
var rows = [self selectedRowIndexes],
indexes = [],
items = [];
[rows getIndexes:indexes maxCount:-1 inIndexRange:nil];
var i = 0,
c = [indexes count];
for (; i < c; i++)
items.push([self itemAtRow:indexes[i]]);
if (character === CPRightArrowFunctionKey)
{
for (var i = 0; i < c; i++)
[self expandItem:items[i]];
}
else if (character === CPLeftArrowFunctionKey)
{
for (var i = 0; i < c; i++)
[self collapseItem:items[i]];
}
[super keyDown:anEvent];
}
@end
// FIX ME: We're using with() here because Safari fails if we use anOutlineView._itemInfosForItems or whatever...
@@ -1588,14 +1679,14 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_writeItems_toPasteboard_))
return NO;
var rowIndexes = [];
[theIndexes getIndexes:rowIndexes maxCount:[theIndexes count] inIndexRange:nil];
var items = [],
index = [theIndexes firstIndex];
var rowIndex = [rowIndexes count],
items = [];
while (rowIndex--)
[items addObject:[_outlineView itemAtRow:[rowIndexes objectAtIndex:rowIndex]]];
while (index !== CPNotFound)
{
[items addObject:[_outlineView itemAtRow:index]]
index = [theIndexes indexGreaterThanIndex:index];
}
return [_outlineView._outlineViewDataSource outlineView:_outlineView writeItems:items toPasteboard:thePasteboard];
}
@@ -1670,6 +1761,15 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
return [_outlineView._outlineViewDataSource outlineView:_outlineView acceptDrop:theInfo item:parentItem childIndex:childIndex];
}
- (void)tableView:(CPTableView)aTableView sortDescriptorsDidChange:(CPArray)oldSortDescriptors
{
if ((_outlineView._implementedOutlineViewDataSourceMethods &
CPOutlineViewDataSource_outlineView_sortDescriptorsDidChange_))
{
[[_outlineView dataSource] outlineView:_outlineView sortDescriptorsDidChange:oldSortDescriptors];
}
}
@end
@implementation _CPOutlineViewTableViewDelegate : CPObject
@@ -1718,13 +1818,13 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
return NO;
}
/*- (float)tableView:(CPTableView)theTableView heightOfRow:(int)theRow
- (float)tableView:(CPTableView)theTableView heightOfRow:(int)theRow
{
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_heightOfRowByItem_))
return [_outlineView._outlineViewDelegate outlineView:_outlineView heightOfRowByItem:[_outlineView itemAtRow:theRow]];
return [theTableView rowHeight];
}*/
}
- (void)tableView:(CPTableView)aTableView willDisplayView:(id)aView forTableColumn:(CPTableColumn)aTableColumn row:(int)aRowIndex
{
@@ -1743,6 +1843,17 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
return NO;
}
- (CPMenu)tableView:(CPTableView)aTableView menuForTableColumn:(CPTableColumn)aTableColumn row:(int)aRow
{
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_menuForTableColumn_item_))
{
var item = [_outlineView itemAtRow:aRow];
return [_outlineView._outlineViewDelegate outlineView:_outlineView menuForTableColumn:aTableColumn item:item]
}
return nil;
}
@end
@implementation CPDisclosureButton : CPButton
+78 -68
View File
@@ -26,7 +26,7 @@
@import "CPMenuItem.j"
var VISIBLE_MARGIN = 7.0;
var VISIBLE_MARGIN = 7.0;
CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
@@ -47,9 +47,19 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
return "popup-button";
}
+ (CPSet)keyPathsForValuesAffectingSelectedIndex
{
return [CPSet setWithObject:@"objectValue"];
}
+ (CPSet)keyPathsForValuesAffectingSelectedTag
{
return [CPSet setWithObject:@"selectedIndex"];
return [CPSet setWithObject:@"objectValue"];
}
+ (CPSet)keyPathsForValuesAffectingSelectedItem
{
return [CPSet setWithObject:@"objectValue"];
}
/*!
@@ -64,7 +74,8 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
if (self)
{
_selectedIndex = CPNotFound;
[self selectItemAtIndex:CPNotFound];
_preferredEdge = CPMaxYEdge;
[self setValue:CPImageLeft forThemeAttribute:@"image-position"];
@@ -75,10 +86,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
[self setPullsDown:shouldPullDown];
var options = CPKeyValueObservingOptionNew |
CPKeyValueObservingOptionOld;/* |
CPKeyValueObservingOptionInitial;
*/
var options = CPKeyValueObservingOptionNew | CPKeyValueObservingOptionOld; // | CPKeyValueObservingOptionInitial;
[self addObserver:self forKeyPath:@"menu.items" options:options context:nil];
[self addObserver:self forKeyPath:@"_firstItem.changeCount" options:options context:nil];
[self addObserver:self forKeyPath:@"selectedItem.changeCount" options:options context:nil];
@@ -96,6 +104,9 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
/*!
Specifies whether the object is a pull-down or a pop-up menu.
If the button pulls down the menu items represent actions, not states.
So the text in the button will NOT change when the user selects something different.
@param shouldPullDown \c YES makes the pop-up button
a pull-down menu. \c NO makes it a pop-up menu.
*/
@@ -139,7 +150,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
/*!
Adds a new menu item with the specified title.
@param the new menu item's tite
@param the new menu item's title
*/
- (void)addItemWithTitle:(CPString)aTitle
{
@@ -148,7 +159,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
/*!
Adds multiple new menu items with the titles specified in the provided array.
@param titles an arry of names for the new items
@param titles an array of names for the new items
*/
- (void)addItemsWithTitles:(CPArray)titles
{
@@ -161,7 +172,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
/*!
Inserts a new item with the specified title and index location.
@param aTitle the new itme's title
@param aTitle the new item's title
@param anIndex the item's index in the menu
*/
- (void)insertItemWithTitle:(CPString)aTitle atIndex:(int)anIndex
@@ -181,11 +192,8 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (void)removeAllItems
{
var menu = [self menu],
count = [menu numberOfItems];
while (count--)
[menu removeItemAtIndex:0];
[[self menu] removeAllItems];
[self synchronizeTitleAndSelectedItem];
}
/*!
@@ -238,15 +246,6 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
return _selectedIndex;
}
// For us, CPNumber is toll-free bridged to Number, so just return the selected index.
/*!
Returns the selected item's index. If no item is selected, it returns CPNotFound.
*/
- (id)objectValue
{
return _selectedIndex;
}
/*!
@ignore
*/
@@ -277,26 +276,48 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
Selects the item at the specified index
@param anIndex the index of the item to select
*/
- (void)selectItemAtIndex:(int)anIndex
- (void)selectItemAtIndex:(CPUInteger)anIndex
{
anIndex = +anIndex;
[self setObjectValue:anIndex];
}
if (_selectedIndex === anIndex)
- (void)setSelectedIndex:(CPUInteger)anIndex
{
[self setObjectValue:anIndex];
}
- (CPUInteger)selectedIndex
{
return [self objectValue];
}
/*!
Selects the item at the specified index
@param anIndex the index of the item to select
*/
- (void)setObjectValue:(int)anIndex
{
var indexOfSelectedItem = [self objectValue];
anIndex = parseInt(+anIndex, 10);
if (indexOfSelectedItem === anIndex)
return;
[self willChangeValueForKey:@"selectedIndex"];
if (_selectedIndex >= 0 && ![self pullsDown])
if (indexOfSelectedItem >= 0 && ![self pullsDown])
[[self selectedItem] setState:CPOffState];
_selectedIndex = anIndex;
if (_selectedIndex >= 0 && ![self pullsDown])
if (indexOfSelectedItem >= 0 && ![self pullsDown])
[[self selectedItem] setState:CPOnState];
[self synchronizeTitleAndSelectedItem];
}
[self didChangeValueForKey:@"selectedIndex"];
- (id)objectValue
{
return _selectedIndex;
}
/*!
@@ -317,15 +338,6 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
[self selectItemAtIndex:[self indexOfItemWithTitle:aTitle]];
}
/*!
Sets the object for the selected item. If no item is selected, then this method has no effect.
@param the object set for the selected item
*/
- (void)setObjectValue:(id)aValue
{
[self selectItemAtIndex:[aValue intValue]];
}
// Getting Menu Items
/*!
@@ -384,9 +396,13 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (CPMenuItem)itemWithTitle:(CPString)aTitle
{
var menu = [self menu];
var menu = [self menu],
itemIndex = [menu indexOfItemWithTitle:aTitle];
return [menu itemAtIndex:[menu indexOfItemWithTitle:aTitle]];
if (itemIndex === CPNotFound)
return nil;
return [menu itemAtIndex:itemIndex];
}
/*!
@@ -418,7 +434,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
/*!
Returns the index of the item with the specified title or CPNotFound.
@param aTitle the item's titel
@param aTitle the item's title
*/
- (int)indexOfItemWithTitle:(CPString)aTitle
{
@@ -460,7 +476,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
}
/*!
Sets the preffered edge of the button to display the
Sets the preferred edge of the button to display the
pop-up when there is a limited amount of screen space.
By default, the pop-up should draw on top of the button.
*/
@@ -608,7 +624,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
{
[self _firstItemDidChange];
_selectedIndex = -2;
[self selectItemAtIndex:CPNotFound];
[self selectItemAtIndex:MIN([newItems count] - 1, indexOfSelectedItem)];
}
@@ -723,7 +739,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
- (void)rightMouseDown:(CPEvent)anEvent
{
// Disable standard CPView behaviour which incorrectly displays the menu as a 'context menu'.
// Disable standard CPView behavior which incorrectly displays the menu as a 'context menu'.
}
- (void)_popUpItemAction:(id)aSender
@@ -762,8 +778,8 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
@end
var CPPopUpButtonSelectedIndexKey = @"CPPopUpButtonSelectedIndexKey",
CPPopUpButtonPullsDownKey = @"CPPopUpButtonPullsDownKey";
var DEPRECATED_CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey",
DEPRECATED_CPPopUpButtonSelectedIndexKey = @"CPPopUpButtonSelectedIndexKey";
@implementation CPPopUpButton (CPCoding)
/*!
@@ -779,15 +795,21 @@ var CPPopUpButtonSelectedIndexKey = @"CPPopUpButtonSelectedIndexKey",
if (self)
{
// Nothing is currently selected
_selectedIndex = CPNotFound;
// FIXME: (or not?) _title is nulled in - [CPButton initWithCoder:],
// so we need to do this again.
[self synchronizeTitleAndSelectedItem];
[self selectItemAtIndex:[aCoder decodeObjectForKey:CPPopUpButtonSelectedIndexKey]];
// FIXME: Remove deprecation leniency for 1.0
if ([aCoder containsValueForKey:DEPRECATED_CPPopUpButtonMenuKey])
{
CPLog.warn(self + " was encoded with an older version of Cappuccino. Please nib2cib the original nib again or open and re-save in Atlas.");
[self setMenu:[aCoder decodeObjectForKey:DEPRECATED_CPPopUpButtonMenuKey]];
[self setObjectValue:[aCoder decodeObjectForKey:DEPRECATED_CPPopUpButtonSelectedIndexKey]];
}
var options = CPKeyValueObservingOptionNew | CPKeyValueObservingOptionOld;/* | CPKeyValueObservingOptionInitial */
var options = CPKeyValueObservingOptionNew |
CPKeyValueObservingOptionOld;/* |
CPKeyValueObservingOptionInitial;
*/
[self addObserver:self forKeyPath:@"menu.items" options:options context:nil];
[self addObserver:self forKeyPath:@"_firstItem.changeCount" options:options context:nil];
[self addObserver:self forKeyPath:@"selectedItem.changeCount" options:options context:nil];
@@ -796,16 +818,4 @@ var CPPopUpButtonSelectedIndexKey = @"CPPopUpButtonSelectedIndexKey",
return self;
}
/*!
Encodes the data of the pop-up button into a coder
@param aCoder the coder to which the data
will be written
*/
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeInt:_selectedIndex forKey:CPPopUpButtonSelectedIndexKey];
}
@end
+325
View File
@@ -0,0 +1,325 @@
/*
* CPPopover.j
* AppKit
*
* Created by Antoine Mercadal.
* Copyright 2011 Antoine Mercadal.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPObject.j>
@import "CPButton.j"
@import "CPColor.j"
@import "CPImage.j"
@import "CPImageView.j"
@import "CPResponder.j"
@import "CPView.j"
@import "_CPAttachedWindow.j"
CPPopoverBehaviorApplicationDefined = 0;
CPPopoverBehaviorTransient = 1;
CPPopoverBehaviorSemitransient = 2;
var CPPopoverDelegate_popover_willShow_ = 1 << 0,
CPPopoverDelegate_popover_didShow_ = 1 << 1,
CPPopoverDelegate_popover_shouldClose_ = 1 << 2,
CPPopoverDelegate_popover_willClose_ = 1 << 3,
CPPopoverDelegate_popover_didClose_ = 1 << 4;
/*! @ingroup appkit
@class CPPopover
This class represent a widget that displays a attached
view relative to another one.
Delegate can implement:
popoverShouldClose:(CPPopover)aPopOver
popoverWillShow:(CPPopover)aPopOver
popoverDidShow:(CPPopover)aPopOver
popoverWillClose:(CPPopover)aPopOver
popoverDidClose:(CPPopover)aPopOver
*/
@implementation CPPopover : CPResponder
{
@outlet CPViewController _contentViewController @accessors(property=contentViewController);
@outlet id _delegate @accessors(getter=delegate);
BOOL _animates @accessors(property=animates);
BOOL _shown @accessors(getter=shown);
int _appearance @accessors(property=appearance);
int _behavior @accessors(getter=behavior);
BOOL _needsCompute;
_CPAttachedWindow _attachedWindow;
int _implementedDelegateMethods;
}
#pragma mark -
#pragma mark Initialization
/*!
Initialize the CPPopover witn default values
@returns anInitialized CPPopover
*/
- (CPPopover)init
{
if (self = [super init])
{
_animates = YES;
_appearance = CPPopoverAppearanceMinimal;
_behavior = CPPopoverBehaviorApplicationDefined;
_needsCompute = YES;
_shown = NO;
}
return self;
}
#pragma mark -
#pragma mark Getters / Setters
/*!
Returns the current rect of the popover
@return CPRect represeting the frame of the popover
*/
- (CPRect)positioningRect
{
if (!_attachedWindow || ![_attachedWindow isVisible])
return nil;
return [_attachedWindow frame];
}
/*! Sets the frame of the popover
@param aRect the desired frame
*/
- (void)setPositioningRect:(CPRect)aRect
{
if (!_attachedWindow || ![_attachedWindow isVisible])
return;
[_attachedWindow setFrame:aRect];
}
/*!
Returns the size of the popover's view
@return CPSize represeting the size of the popover's view
*/
- (CPRect)contentSize
{
if (!_attachedWindow || ![_attachedWindow isVisible])
return nil;
return [[_contentViewController view] frameSize];
}
/*!
Sets the size of of the popover's view
@param aSize the desired size
*/
- (void)setContentSize:(CPSize)aSize
{
[[_contentViewController view] setFrameSize:aSize];
}
/*!
Indicates if CPPopover is visible
@returns YES if visible
*/
- (BOOL)shown
{
if (!_attachedWindow)
return NO;
return [_attachedWindow isVisible];
}
/*!
Set the behaviour of the CPPopover. It can be
- CPPopoverBehaviorTransient: the popover will be close if another control outside the popover become the responder
- CPPopoverBehaviorApplicationDefined: (DEFAULT) the application is responsible for closing the popover
@param aBehaviour the desired behaviour
*/
- (void)setBehaviour:(int)aBehaviour
{
if (_behavior == aBehaviour)
return;
_behavior = aBehaviour;
_needsCompute = YES;
}
- (void)setDelegate:(id)aDelegate
{
if (_delegate === aDelegate)
return;
_delegate = aDelegate;
_implementedDelegateMethods = 0;
if ([_delegate respondsToSelector:@selector(popoverWillShow:)])
_implementedDelegateMethods |= CPPopoverDelegate_popover_willShow_;
if ([_delegate respondsToSelector:@selector(popoverDidShow:)])
_implementedDelegateMethods |= CPPopoverDelegate_popover_didShow_;
if ([_delegate respondsToSelector:@selector(popoverShouldClose:)])
_implementedDelegateMethods |= CPPopoverDelegate_popover_shouldClose_;
if ([_delegate respondsToSelector:@selector(popoverWillClose:)])
_implementedDelegateMethods |= CPPopoverDelegate_popover_willClose_;
if ([_delegate respondsToSelector:@selector(popoverDidClose:)])
_implementedDelegateMethods |= CPPopoverDelegate_popover_didClose_;
}
#pragma mark -
#pragma mark Positioning
/*!
Show the popover
@param positioningRect if set, the popover will be positionned to a random rect relative to the window
@param positioningView if set, the popover will be positioned relative to this view
@param preferredEdge: CPRectEdge representing the preferred positioning.
*/
- (void)showRelativeToRect:(CPRect)positioningRect ofView:(CPView)positioningView preferredEdge:(CPRectEdge)preferredEdge
{
if (_implementedDelegateMethods & CPPopoverDelegate_popover_willShow_)
[_delegate popoverWillShow:self];
if (!_contentViewController)
[CPException raise:CPInternalInconsistencyException reason:@"contentViewController must not be nil"];
if (_needsCompute || !_attachedWindow)
{
var styleMask = (_behavior == CPPopoverBehaviorTransient) ? CPClosableOnBlurWindowMask : nil;
_attachedWindow = [[_CPAttachedWindow alloc] initWithContentRect:CPRectMakeZero() styleMask:styleMask];
}
[_attachedWindow setAppearance:_appearance];
[_attachedWindow setAnimates:_animates];
[_attachedWindow setDelegate:self];
[_attachedWindow setMovableByWindowBackground:NO];
[_attachedWindow setFrame:[_attachedWindow frameRectForContentRect:[[_contentViewController view] frame]]];
[_attachedWindow setContentView:[_contentViewController view]];
if (positioningRect)
[_attachedWindow positionRelativeToRect:positioningRect preferredEdge:preferredEdge];
else if (positioningView)
[_attachedWindow positionRelativeToView:positioningView preferredEdge:preferredEdge];
else
[CPException raise:CPInvalidArgumentException reason:@"a value must be passed for positioningRect or positioningView"];
if (_implementedDelegateMethods & CPPopoverDelegate_popover_didShow_)
[_delegate popoverDidShow:self];
}
/*!
Closes the popover
*/
- (void)close
{
if (_implementedDelegateMethods & CPPopoverDelegate_popover_shouldClose_)
if (![_delegate popoverShouldClose:self])
return;
if (_implementedDelegateMethods & CPPopoverDelegate_popover_willClose_)
[_delegate popoverWillClose:self];
[_attachedWindow close];
if (_implementedDelegateMethods & CPPopoverDelegate_popover_didClose_)
[_delegate popoverDidClose:self];
}
#pragma mark -
#pragma mark Action
/*!
Close the popover
@param aSender the sender of the action
*/
- (IBAction)performClose:(id)aSender
{
[self close];
}
#pragma mark -
#pragma mark Delegates
/*! @ignore */
- (BOOL)attachedWindowShouldClose:(_CPAttachedWindow)anAttachedWindow
{
[self close];
// we return NO, because we want the CPPopover to compute
// if the attached can be close in order to send delegate messages
return NO;
}
@end
var CPPopoverNeedsComputeKey = @"CPPopoverNeedsComputeKey",
CPPopoverAppearanceKey = @"CPPopoverAppearanceKey",
CPPopoverAnimatesKey = @"CPPopoverAnimatesKey",
CPPopoverContentViewControllerKey = @"CPPopoverContentViewControllerKey",
CPPopoverDelegateKey = @"CPPopoverDelegateKey",
CPPopoverBehaviorKey = @"CPPopoverBehaviorKey";
@implementation CPPopover (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
_needsCompute = [aCoder decodeIntForKey:CPPopoverNeedsComputeKey];
_appearance = [aCoder decodeIntForKey:CPPopoverAppearanceKey];
_animates = [aCoder decodeBoolForKey:CPPopoverAnimatesKey];
_contentViewController = [aCoder decodeObjectForKey:CPPopoverContentViewControllerKey];
[self setDelegate:[aCoder decodeObjectForKey:CPPopoverDelegateKey]];
[self setBehaviour:[aCoder decodeIntForKey:CPPopoverBehaviorKey]];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeBool:_needsCompute forKey:CPPopoverNeedsComputeKey];
[aCoder encodeInt:_appearance forKey:CPPopoverAppearanceKey];
[aCoder encodeObject:_animates forKey:CPPopoverAnimatesKey];
[aCoder encodeObject:_contentViewController forKey:CPPopoverContentViewControllerKey];
[aCoder encodeObject:_delegate forKey:CPPopoverDelegateKey];
[aCoder encodeInt:_behavior forKey:CPPopoverBehaviorKey];
}
@end
+40 -2
View File
@@ -120,7 +120,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
CPProgressIndicatorStyleSizes = [];
// Bar Sttyle
// Bar Style
var prefixes = [
CPProgressIndicatorClassName + @"BezelBorder" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle],
CPProgressIndicatorClassName + @"Bar" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle],
@@ -290,7 +290,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
}
/*
Not yet impemented.
Not yet implemented.
*/
- (CPControlTint)controlTint
{
@@ -464,3 +464,41 @@ var CPProgressIndicatorSpinningStyleColors = nil,
}
@end
@implementation CPProgressIndicator (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
if (self = [super initWithCoder:aCoder])
{
_minValue = [aCoder decodeObjectForKey:@"_minValue"];
_maxValue = [aCoder decodeObjectForKey:@"_maxValue"];
_doubleValue = [aCoder decodeObjectForKey:@"_doubleValue"];
_controlSize = [aCoder decodeObjectForKey:@"_controlSize"];
_isIndeterminate = [aCoder decodeObjectForKey:@"_isIndeterminate"];
_style = [aCoder decodeObjectForKey:@"_style"];
_isAnimating = [aCoder decodeObjectForKey:@"_isAnimating"];
_isDisplayedWhenStoppedSet = [aCoder decodeObjectForKey:@"_isDisplayedWhenStoppedSet"];
_isDisplayedWhenStopped = [aCoder decodeObjectForKey:@"_isDisplayedWhenStopped"];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:_minValue forKey:@"_minValue"];
[aCoder encodeObject:_maxValue forKey:@"_maxValue"];
[aCoder encodeObject:_doubleValue forKey:@"_doubleValue"];
[aCoder encodeObject:_controlSize forKey:@"_controlSize"];
[aCoder encodeObject:_isIndeterminate forKey:@"_isIndeterminate"];
[aCoder encodeObject:_style forKey:@"_style"];
[aCoder encodeObject:_isAnimating forKey:@"_isAnimating"];
[aCoder encodeObject:_isDisplayedWhenStoppedSet forKey:@"_isDisplayedWhenStoppedSet"];
[aCoder encodeObject:_isDisplayedWhenStopped forKey:@"_isDisplayedWhenStopped"];
}
@end
+8 -2
View File
@@ -150,6 +150,14 @@ CPRadioImageOffset = 4.0;
[_radioGroup _setSelectedRadio:self];
}
- (void)sendAction:(SEL)anAction to:(id)anObject
{
[super sendAction:anAction to:anObject];
if (_radioGroup)
[CPApp sendAction:[_radioGroup action] to:[_radioGroup target] from:_radioGroup];
}
@end
var CPRadioRadioGroupKey = @"CPRadioRadioGroupKey";
@@ -220,8 +228,6 @@ var CPRadioRadioGroupKey = @"CPRadioRadioGroupKey";
[_selectedRadio setState:CPOffState];
_selectedRadio = aRadio;
[CPApp sendAction:_action to:_target from:self];
}
- (CPRadio)selectedRadio
+12 -5
View File
@@ -231,11 +231,18 @@ CPDeleteForwardKeyCode = 46;
[_nextResponder performSelector:_cmd withObject:anEvent];
}
/*
FIXME This description is bad.
Based on \c anEvent, the receiver should simulate the event.
@param anEvent the event to simulate
@return \c YES if the event receiver simulated the event
/*!
Overridden by subclasses to handle a key equivalent.
If the character code or codes in \c anEvent match the receivers key equivalent,
the receiver should respond to the event and return \c YES. The default implementation
does nothing and returns \c NO.
You should extract the characters for a key equivalent using
\ref CPEvent::charactersIgnoringModifiers "[anEvent charactersIgnoringModifiers]".
@param anEvent An event object that represents the key equivalent pressed
@return \c YES if theEvent is a key equivalent that the receiver handled, \c NO if it is not a key equivalent that it should handle.
*/
- (BOOL)performKeyEquivalent:(CPEvent)anEvent
{
+504
View File
@@ -0,0 +1,504 @@
/*
* CPPredicateEditor.j
* AppKit
*
* Created by cacaodev.
* Copyright 2011, cacaodev.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPRuleEditor.j"
@import "_CPPredicateEditorTree.j"
@import "_CPPredicateEditorRowNode.j"
@import "CPPredicateEditorRowTemplate.j"
@implementation CPPredicateEditor : CPRuleEditor
{
CPArray _allTemplates;
CPArray _rootTrees;
CPArray _rootHeaderTrees;
id _predicateTarget @accessors(property=target);
SEL _predicateAction @accessors(property=action);
}
#pragma mark public methods
/*!
@ingroup appkit
@class CPPredicateEditor
@brief CPPredicateEditor is a subclass of CPRuleEditor that is specialized for editing CPPredicate objects.
CPPredicateEditor provides a CPPredicate property—objectValue (inherited from CPControl)—that you can get and set directly, and that you can bind using bindings (you typically configure a predicate editor in Interface Builder). CPPredicateEditor depends on another class, CPPredicateEditorRowTemplate, that describes the available predicates and how to display them.
Unlike CPRuleEditor, CPPredicateEditor does not depend on its delegate to populate its rows (and does not call the populating delegate methods). Instead, its rows are populated from its objectValue property (an instance of CPPredicate). CPPredicateEditor relies on instances CPPredicateEditorRowTemplate, which are responsible for mapping back and forth between the displayed view values and various predicates.
CPPredicateEditor exposes one property, rowTemplates, which is an array of CPPredicateEditorRowTemplate objects.
*/
/*!
@brief Returns the row templates for the receiver.
@return The row templates for the receiver.
@discussion Until otherwise set, this contains a single compound CPPredicateEditorRowTemplate object.
@see setRowTemplates:
*/
- (CPArray)rowTemplates
{
return _allTemplates;
}
/*!
@brief Sets the row templates for the receiver.
@param rowTemplates An array of CPPredicateEditorRowTemplate objects.
@see rowTemplates
*/
- (void)setRowTemplates:(id)rowTemplates
{
if (_allTemplates == rowTemplates)
return;
_allTemplates = rowTemplates;
[self _updateItemsByCompoundTemplates];
[self _updateItemsBySimpleTemplates];
if ([self numberOfRows] > 0)
{
var predicate = [super predicate];
[self _reflectPredicate:predicate];
}
}
/*! @cond */
- (void)_initRuleEditorShared
{
[super _initRuleEditorShared];
_rootTrees = [CPArray array];
_rootHeaderTrees = [CPArray array];
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self != nil)
{
var initialTemplate = [[CPPredicateEditorRowTemplate alloc] initWithCompoundTypes:[CPAndPredicateType, CPOrPredicateType]];
_allTemplates = [CPArray arrayWithObject:initialTemplate];
}
return self;
}
- (id)objectValue
{
return [super predicate];
}
- (void)_updateItemsBySimpleTemplates
{
var templates = [CPMutableArray array],
count = [_allTemplates count],
t;
while (count--)
{
var t = _allTemplates[count];
if ([t _rowType] == CPRuleEditorRowTypeSimple)
[templates insertObject:t atIndex:0];
}
var trees = [self _constructTreesForTemplates:templates];
if ([trees count] > 0)
_rootTrees = [self _mergeTree:trees];
}
- (void)_updateItemsByCompoundTemplates
{
var templates = [CPMutableArray array],
count = [_allTemplates count],
t;
while (count--)
{
var t = _allTemplates[count];
if ([t _rowType] == CPRuleEditorRowTypeCompound)
[templates insertObject:t atIndex:0];
}
var trees = [self _constructTreesForTemplates:templates];
if ([trees count] > 0)
_rootHeaderTrees = [self _mergeTree:trees];
}
- (CPArray)_constructTreesForTemplates:(id)templates
{
var trees = [CPMutableArray array],
count = [templates count];
for (var i = 0; i < count; i++)
{
var tree = [self _constructTreeForTemplate:templates[i]];
[trees addObjectsFromArray:tree];
}
return trees;
}
- (id)_mergeTree:(id)tree
{
var merged = [CPMutableArray array],
titles = [CPMutableArray array],
count = [tree count];
for (var i = 0; i < count; i++)
{
var t = tree[i],
title = [CPString stringWithString:[t title]];
if ([titles containsObject:title])
{
CPLogConsole("CPPredicateEditor does not support templates merging yet. Ignoring duplicate template: " + [t description]);
continue;
}
[merged addObject:t];
[titles addObject:title];
}
return merged;
}
- (id)_constructTreeForTemplate:(CPPredicateEditorRowTemplate)aTemplate
{
var tree = [CPArray array],
templateViews = [aTemplate templateViews],
count = [templateViews count];
while (count--)
{
var children = [CPArray array],
itemsCount = 0,
menuIndex = -1,
itemsArray,
templateView = [templateViews objectAtIndex:count],
isPopup = [templateView isKindOfClass:[CPPopUpButton class]];
if (isPopup)
{
itemArray = [[templateView itemArray] valueForKey:@"title"];
itemsCount = [itemArray count];
menuIndex = 0;
}
for (; menuIndex < itemsCount; menuIndex++)
{
var item = [_CPPredicateEditorTree new];
[item setIndexIntoTemplate:count];
[item setTemplate:aTemplate];
[item setMenuItemIndex:menuIndex];
if (isPopup)
[item setTitle:[itemArray objectAtIndex:menuIndex]];
[children addObject:item];
}
[children makeObjectsPerformSelector:@selector(setChildren:) withObject:tree];
tree = children;
}
return tree;
}
#pragma mark Set the Predicate
- (void)setObjectValue:(id)objectValue
{
if (![[objectValue predicateFormat] isEqualToString:[[super predicate] predicateFormat]]) // ??
[self _reflectPredicate:objectValue];
}
- (void)_reflectPredicate:(id)predicate
{
var animation = _currentAnimation;
_currentAnimation = nil;
if (predicate != nil)
{
if ((_nestingMode == CPRuleEditorNestingModeSimple || _nestingMode == CPRuleEditorNestingModeCompound)
&& [predicate isKindOfClass:[CPComparisonPredicate class]])
predicate = [[CPCompoundPredicate alloc] initWithType:[self _compoundPredicateTypeForRootRows] subpredicates:[CPArray arrayWithObject:predicate]];
var row = [self _rowObjectFromPredicate:predicate];
if (row != nil)
[_boundArrayOwner setValue:[CPArray arrayWithObject:row] forKey:_boundArrayKeyPath];
}
[self setAnimation:animation];
}
- (id)_rowObjectFromPredicate:(CPPredicate)predicate
{
var quality, // TODO: We should use this ref somewhere !
type,
matchedTemplate = [CPPredicateEditorRowTemplate _bestMatchForPredicate:predicate inTemplates:[self rowTemplates] quality:quality];
if (matchedTemplate == nil)
return nil;
var copyTemplate = [matchedTemplate copy],
subpredicates = [matchedTemplate displayableSubpredicatesOfPredicate:predicate];
if (subpredicates == nil)
{
[copyTemplate _setComparisonPredicate:predicate];
type = CPRuleEditorRowTypeSimple;
}
else
{
[copyTemplate _setCompoundPredicate:predicate];
type = CPRuleEditorRowTypeCompound;
}
var row = [self _rowFromTemplate:copyTemplate originalTemplate:matchedTemplate withRowType:type];
if (subpredicates == nil)
return row;
var count = [subpredicates count],
subrows = [CPMutableArray array];
for (var i = 0; i < count; i++)
{
var subrow = [self _rowObjectFromPredicate:subpredicates[i]];
if (subrow != nil)
[subrows addObject:subrow];
}
[row setValue:subrows forKey:[super subrowsKeyPath]];
return row;
}
- (id)_rowFromTemplate:(CPPredicateEditorRowTemplate)aTemplate originalTemplate:(CPPredicateEditorRowTemplate)originalTemplate withRowType:(CPRuleEditorRowType)rowType
{
var criteria = [CPArray array],
values = [CPArray array],
templateViews = [aTemplate templateViews],
rootItems,
count;
rootItems = (rowType == CPRuleEditorRowTypeSimple) ? _rootTrees : _rootHeaderTrees;
while ((count = [rootItems count]) > 0)
{
var treeChild;
for (var i = 0; i < count; i++)
{
treeChild = [rootItems objectAtIndex:i];
var currentView = [templateViews objectAtIndex:[treeChild indexIntoTemplate]],
menuItemIndex = [treeChild menuItemIndex];
if (menuItemIndex == -1 || [[treeChild title] isEqual:[currentView titleOfSelectedItem]])
{
var node = [_CPPredicateEditorRowNode rowNodeFromTree:treeChild];
[node applyTemplate:aTemplate withViews:templateViews forOriginalTemplate:originalTemplate];
[criteria addObject:node];
[values addObject:[node displayValue]];
break;
}
}
rootItems = [treeChild children];
}
var row = [CPDictionary dictionaryWithObjectsAndKeys:criteria, @"criteria", values, @"displayValues", rowType, @"rowType"];
return row;
}
#pragma mark Get the predicate
- (void)_updatePredicate
{
[self willChangeValueForKey:@"objectValue"];
[self _updatePredicateFromRows];
[self didChangeValueForKey:@"objectValue"];
}
- (void)_updatePredicateFromRows
{
var rootRowsArray = [super _rootRowsArray],
subpredicates = [CPMutableArray array],
count = count2 = [rootRowsArray count],
predicate;
while (count--)
{
var item = [rootRowsArray objectAtIndex:count],
subpredicate = [self _predicateFromRowItem:item];
if (subpredicate != nil)
[subpredicates insertObject:subpredicate atIndex:0];
}
if (_nestingMode != CPRuleEditorNestingModeList && count2 == 1)
predicate = [subpredicates lastObject];
else
predicate = [[CPCompoundPredicate alloc] initWithType:[self _compoundPredicateTypeForRootRows] subpredicates:subpredicates];
[super _setPredicate:predicate];
}
- (id)_predicateFromRowItem:(id)rowItem
{
var subpredicates = [CPArray array],
rowType = [rowItem valueForKey:_typeKeyPath];
if (rowType == CPRuleEditorRowTypeCompound)
{
var subrows = [rowItem valueForKey:_subrowsArrayKeyPath],
count = [subrows count];
for (var i = 0; i < count; i++)
{
var subrow = [subrows objectAtIndex:i];
var predicate = [self _predicateFromRowItem:subrow];
[subpredicates addObject:predicate];
}
}
var criteria = [rowItem valueForKey:_itemsKeyPath],
displayValues = [rowItem valueForKey:_valuesKeyPath],
count = [criteria count],
lastItem = [criteria lastObject],
template = [lastItem templateForRow],
templateViews = [template templateViews];
for (var j = 0; j < count; j++)
{
var view = [templateViews objectAtIndex:j],
value = [displayValues objectAtIndex:j];
[[criteria objectAtIndex:j] setTemplateViews:templateViews];
if ([view isKindOfClass:[CPPopUpButton class]])
[view selectItemWithTitle:value];
else if ([view respondsToSelector:@selector(setObjectValue:)])
[view setObjectValue:[value objectValue]];
}
return [template predicateWithSubpredicates:subpredicates];
}
- (CPCompoundPredicateType)_compoundPredicateTypeForRootRows
{
return CPAndPredicateType;
}
#pragma mark Control delegate
- (void)_sendRuleAction
{
[self _updatePredicate];
[super _sendRuleAction];
}
- (BOOL)_sendsActionOnIncompleteTextChange
{
return NO;
}
/*
- (void)_setDefaultTargetAndActionOnView:(CPView)view
{
if ([view isKindOfClass:[CPControl class]])
{
[view setTarget:self];
[view setAction:@selector(_templateControlValueDidChange:)];
}
}
- (void)_templateControlValueDidChange:(id)sender
{
}
- (void)controlTextDidBeginEditing:(CPNotification)notification
{
}
- (void)controlTextDidEndEditing:(CPNotification)notification
{
}
- (void)controlTextDidChange:(CPNotification)notification
{
}
*/
#pragma mark RuleEditor delegate methods
- (int)_queryNumberOfChildrenOfItem:(id)rowItem withRowType:(int)type
{
if (rowItem == nil)
{
var trees = (type == CPRuleEditorRowTypeSimple) ? _rootTrees : _rootHeaderTrees;
return [trees count];
}
return [[rowItem children] count];
}
- (id)_queryChild:(int)childIndex ofItem:(id)rowItem withRowType:(int)type
{
if (rowItem == nil)
{
var trees = (type == CPRuleEditorRowTypeSimple) ? _rootTrees : _rootHeaderTrees;
return [_CPPredicateEditorRowNode rowNodeFromTree:trees[childIndex]];
}
return [[rowItem children] objectAtIndex:childIndex];
}
- (id)_queryValueForItem:(id)rowItem inRow:(int)rowIndex
{
return [rowItem displayValue];
}
@end
var CPPredicateTemplatesKey = @"CPPredicateTemplates";
@implementation CPPredicateEditor (CPCoding)
- (id)initWithCoder:(id)aCoder
{
self = [super initWithCoder:aCoder];
if (self != nil)
{
var nibTemplates = [aCoder decodeObjectForKey:CPPredicateTemplatesKey];
if (nibTemplates != nil)
[self setRowTemplates:nibTemplates];
}
return self;
}
- (void)encodeWithCoder:(id)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:_allTemplates forKey:CPPredicateTemplatesKey];
}
@end
/*! @endcond */
@@ -0,0 +1,788 @@
/*
* CPPredicateEditorRowTemplate.j
* AppKit
*
* Created by cacaodev.
* Copyright 2011, cacaodev.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
CPUndefinedAttributeType = 0;
CPInteger16AttributeType = 100;
CPInteger32AttributeType = 200;
CPInteger64AttributeType = 300;
CPDecimalAttributeType = 400;
CPDoubleAttributeType = 500;
CPFloatAttributeType = 600;
CPStringAttributeType = 700;
CPBooleanAttributeType = 800;
CPDateAttributeType = 900;
CPBinaryDataAttributeType = 1000;
CPTransformableAttributeType = 1800;
@implementation CPPredicateEditorRowTemplate : CPObject
{
int _templateType @accessors(readwrite, getter=_templateType, setter=_setTemplateType:);
unsigned _predicateOptions @accessors(readwrite, setter=_setOptions:);
unsigned _predicateModifier @accessors(readwrite, setter=_setModifier:);
unsigned _leftAttributeType @accessors(readwrite, getter=leftAttributeType, setter=_setLeftAttributeType:);
unsigned _rightAttributeType @accessors(readwrite, getter=rightAttributeType, setter=_setRightAttributeType:);
BOOL _leftIsWildcard @accessors(property=leftIsWildcard);
BOOL _rightIsWildcard @accessors(property=rightIsWildcard);
CPArray _views @accessors(setter=setTemplateViews:);
}
/*!
@ingroup appkit
@class CPPredicateEditorRowTemplate
@brief CPPredicateEditorRowTemplate describes available predicates and how to display them.
You can create instances of CPPredicateEditorRowTemplate programmatically or in Interface Builder. By default, a non-compound row template has three views: a popup (or static text field) on the left, a popup or static text field for operators, and either a popup or other view on the right. You can subclass CPPredicateEditorRowTemplate to create a row template with different numbers or types of views.
CPPredicateEditorRowTemplate is a concrete class, but it has five primitive methods which are called by CPPredicateEditor: -#templateViews, -#matchForPredicate:, -#setPredicate:, -#displayableSubpredicatesOfPredicate:, and -#predicateWithSubpredicates:. CPPredicateEditorRowTemplate implements all of them, but you can override them for custom templates. The primitive methods are used by an instance of CPPredicateEditor as follows.
First, an instance of CPPredicateEditor is created, and some row templates are set on it—either through a nib file or programmatically. The first thing predicate editor does is ask each of the templates for their views, using templateViews.
After setting up the predicate editor, you typically send it a CPPredicateEditor#setObjectValue: message to restore a saved predicate. CPPredicateEditor needs to determine which of its templates should display each predicate in the predicate tree. It does this by sending each of its row templates a matchForPredicate: message and choosing the one that returns the highest value.
After finding the best match for a predicate, CPPredicateEditor copies that template to get fresh views, inserts them into the proper row, and then sets the predicate on the template using setPredicate:. Within that method, the CPPredicateEditorRowTemplate object must set its views' values to represent that predicate.
CPPredicateEditorRowTemplate next asks the template for the “displayable sub-predicates” of the predicate by sending a -#displayableSubpredicatesOfPredicate: message. If a template represents a predicate in its entirety, or if the predicate has no subpredicates, it can return nil for this. Otherwise, it should return a list of predicates to be made into sub-rows of that template's row. The whole process repeats for each sub-predicate.
At this point, the user sees the predicate that was saved. If the user then makes some changes to the views of the templates, this causes CPPredicateEditor to recompute its predicate by asking each of the templates to return the predicate represented by the new view values, passing in the subpredicates represented by the sub-rows (an empty array if there are none, or nil if they aren't supported by that predicate type).
*/
/*!
@name Initializing a Template
*/
/*!
@brief Initializes and returns a “pop-up-pop-up-pop-up”-style row template.
@param leftExpressions An array of CPExpression objects that represent the left hand side of a predicate.
@param rightExpressions An array of CPExpression objects that represent the right hand side of a predicate.
@param modifier A modifier for the predicate (see @c CPComparisonPredicateModifier for possible values).
@param operators An array of CPNumber objects specifying the operator type (see @c CPPredicateOperatorType for possible values).
@param options Options for the predicate (see @c CPComparisonPredicateOptions for possible values).
@return A row template of the “pop-up-pop-up-pop-up”-form, with the left and right popups representing the left and right expression arrays -#leftExpressions and -#rightExpressions, and the center popup representing the operators.
*/
- (id)initWithLeftExpressions:(CPArray)leftExpressions rightExpressions:(CPArray)rightExpressions modifier:(int)modifier operators:(CPArray)operators options:(int)options
{
self = [super init];
if (self != nil)
{
_templateType = 1;
_leftIsWildcard = NO;
_rightIsWildcard = NO;
_leftAttributeType = 0;
_rightAttributeType = 0;
_predicateModifier = modifier;
_predicateOptions = options;
var leftView = [self _viewFromExpressions:leftExpressions],
rightView = [self _viewFromExpressions:rightExpressions],
middleView = [self _viewFromOperatorTypes:operators];
_views = [[CPArray alloc] initWithObjects:leftView, middleView, rightView];
}
return self;
}
/*!
@brief Initializes and returns a “pop-up-pop-up-view”-style row template.
@param leftExpressions An array of CPExpression objects that represent the left hand side of a predicate.
@param attributeType An attribute type for the right hand side of a predicate. This value dictates the type of view created, and how the controls object value is coerced before putting it into a predicate.
@param modifier A modifier for the predicate (see @c CPComparisonPredicateModifier for possible values).
@param operators An array of CPNumber objects specifying the operator type (see @c CPPredicateOperatorType for possible values).
@param options Options for the predicate (see CPComparisonPredicateOptions for possible values).
@return A row template initialized using the given arguments.
*/
- (id)initWithLeftExpressions:(CPArray )leftExpressions rightExpressionAttributeType:(CPAttributeType)attributeType modifier:(CPComparisonPredicateModifier)modifier operators:(CPArray )operators options:(int)options
{
self = [super init];
if (self != nil)
{
var leftView = [self _viewFromExpressions:leftExpressions],
middleView = [self _viewFromOperatorTypes:operators],
rightView = [self _viewFromAttributeType:attributeType];
_templateType = 1;
_leftIsWildcard = NO;
_rightIsWildcard = YES;
_leftAttributeType = 0;
_rightAttributeType = attributeType;
_predicateModifier = modifier;
_predicateOptions = options;
_views = [[CPArray alloc] initWithObjects:leftView, middleView, rightView];
}
return self;
}
/*!
@brief Initializes and returns a row template suitable for displaying compound predicates.
@param compoundTypes An array of CPNumber objects specifying compound predicate types. See @c CPCompoundPredicateTypes for possible values.
@return A row template initialized for displaying compound predicates of the types specified by @a compoundTypes.
@discussion CPPredicateEditor contains such a template by default.
*/
- (id)initWithCompoundTypes:(CPArray )compoundTypes
{
self = [super init];
if (self != nil)
{
var leftView = [self _viewFromCompoundTypes:compoundTypes],
rightView = [[CPPopUpButton alloc] init];
[rightView addItemWithTitle:@"of the following are true"];
_templateType = 2;
_leftIsWildcard = NO;
_rightIsWildcard = NO;
_rightAttributeType = 0;
_views = [[CPArray alloc] initWithObjects:leftView, rightView];
}
return self;
}
/*!
@name Primitive Methods
*/
/*!
@brief Returns a positive number if the receiver can represent a given predicate, and 0 if it cannot.
@return A positive number if the template can represent predicate, and @c 0 if it cannot.
@discussion By default, returns values in the range @c 0 to @c 1.
The highest match among all the templates determines which template is responsible for displaying the predicate. You can override this to determine which predicates your custom template handles.
*/
- (double)matchForPredicate:(CPPredicate)predicate
{
// How exactly this value (float 0-1) is computed ?
if ([self _templateType] == 2 && [predicate isKindOfClass:[CPCompoundPredicate class]])
{
if ([[self compoundTypes] containsObject:[predicate compoundPredicateType]])
return 1;
}
else if ([self _templateType] == 1 && [predicate isKindOfClass:[CPComparisonPredicate class]])
{
if (!_leftIsWildcard && ![[self leftExpressions] containsObject:[predicate leftExpression]])
return 0;
if (![[self operators] containsObject:[predicate predicateOperatorType]])
return 0;
if (!_rightIsWildcard && ![[self rightExpressions] containsObject:[predicate rightExpression]]) return 0;
return 1;
}
return 0;
}
/*!
@brief Returns the views for the receiver.
@return The views for the receiver.
@discussion Instances of CPPopUpButton are treated specially by CPPredicateEditor; their menu items are merged into a single popup button, and matching menu item titles are combined. In this way, a single tree is built from the separate templates.
*/
- (CPArray)templateViews
{
return _views;
}
/*!
@brief Sets the value of the views according to the given predicate.
@param predicate The predicate value for the receiver.
@discussion This method is only called if -#matchForPredicate: returned a positive value for the receiver.
You can override this to set the values of custom views.
*/
- (void)setPredicate:(CPPredicate)predicate
{
if (_templateType == 2)
[self _setCompoundPredicate:predicate];
else
[self _setComparisonPredicate:predicate];
}
/*!
@brief Returns the subpredicates that should be made sub-rows of a given predicate.
@param predicate A predicate object.
@return The subpredicates that should be made sub-rows of @a predicate. For compound predicates (instances of CPCompoundPredicate), the array of subpredicates; for other types of predicate, returns @c nil. If a template represents a predicate in its entirety, or if the predicate has no subpredicates, returns @c nil.
@discussion You can override this method to create custom templates that handle complicated compound predicates.
*/
- (CPArray)displayableSubpredicatesOfPredicate:(CPPredicate)predicate
{
if ([predicate isKindOfClass:[CPCompoundPredicate class]])
{
var subpredicates = [predicate subpredicates];
if ([subpredicates count] == 0)
return nil;
return subpredicates;
}
return nil;
}
/*!
@brief Returns the predicate represented by the receivers views' values and the given sub-predicates.
@param subpredicates An array of predicates.
@return The predicate represented by the values of the template's views and the given @a subpredicates. You can override this method to return the predicate represented by your custom views.
@discussion This method is only called if -#matchForPredicate: returned a positive value for the receiver.
You can override this method to return the predicate represented by a custom view.
*/
- (CPPredicate)predicateWithSubpredicates:(CPArray)subpredicates
{
if (_templateType == 2)
{
var type = [[_views[0] selectedItem] representedObject];
return [[CPCompoundPredicate alloc] initWithType:type subpredicates:subpredicates];
}
if (_templateType == 1)
{
var lhs = [self _leftExpression],
rhs = [self _rightExpression],
operator = [[_views[1] selectedItem] representedObject];
return [CPComparisonPredicate predicateWithLeftExpression:lhs
rightExpression:rhs
modifier:[self modifier]
type:operator
options:[self options]];
}
return nil;
}
/*!
@name Information About a Row Template
*/
/*!
@brief Returns the left hand expressions for the receiver.
@return The left hand expressions for the receiver.
*/
- (CPArray)leftExpressions
{
if (_templateType ==1 && !_leftIsWildcard)
{
var view = [_views objectAtIndex:0];
return [[view itemArray] valueForKey:@"representedObject"];
}
return nil;
}
/*!
@brief Returns the right hand expressions for the receiver.
@return The right hand expressions for the receiver.
*/
- (CPArray)rightExpressions
{
if (_templateType == 1 && !_rightIsWildcard)
{
var view = [_views objectAtIndex:2];
return [[view itemArray] valueForKey:@"representedObject"];
}
return nil;
}
/*!
@brief Returns the compound predicate types for the receiver.
@return An array of CPNumber objects specifying compound predicate types. See @c CompoundPredicateTypes for possible values.
*/
- (CPArray)compoundTypes
{
if (_templateType == 2)
{
var view = [_views objectAtIndex:0];
return [[view itemArray] valueForKey:@"representedObject"];
}
return nil;
}
/*!
@brief Returns the comparison predicate modifier for the receiver.
@return The comparison predicate modifier for the receiver.
*/
- (CPComparisonPredicateModifier)modifier
{
if (_templateType == 1)
return _predicateModifier;
return nil;
}
/*!
@brief Returns Returns the array of operators for the receiver.
@return The array of operators for the receiver.
*/
- (CPArray)operators
{
if (_templateType == 1)
{
var view = [_views objectAtIndex:1];
return [[view itemArray] valueForKey:@"representedObject"];
}
return nil;
}
/*!
@brief Returns the comparison predicate options for the receiver.
@return The comparison predicate options for the receiver. See @c CPComparisonPredicateOptions for possible values. Returns @c 0 if this does not apply (for example, for a compound template initialized with -#initWithCompoundTypes:).
*/
- (int)options
{
if (_templateType == 1)
return _predicateOptions;
return nil;
}
/*!
@brief Returns the attribute type of the receivers right expression.
@return The attribute type of the receivers right expression.
*/
- (CPAttributeType)rightExpressionAttributeType
{
return _rightAttributeType;
}
/*!
@brief Returns the attribute type of the receivers left expression.
@return The attribute type of the receivers left expression.
*/
- (CPAttributeType)leftExpressionAttributeType
{
return _leftAttributeType;
}
/*! @cond */
+ (id)_bestMatchForPredicate:(CPPredicate)predicate inTemplates:(CPArray)templates quality:(double)quality
{
var count = [templates count],
match_value = 0,
templateIndex = CPNotFound,
i;
for (i = 0; i < count; i++)
{
var template = [templates objectAtIndex:i],
amatch = [template matchForPredicate:predicate];
if (amatch > match_value)
{
templateIndex = i;
match_value = amatch;
}
}
if (templateIndex == CPNotFound)
{
[CPException raise:CPRangeException reason:@"Unable to find template matching predicate: " + [predicate predicateFormat]];
return nil;
}
return [templates objectAtIndex:templateIndex];
}
- (void)_setCompoundPredicate:(CPCompoundPredicate)predicate
{
var left = [_views objectAtIndex:0],
type = [predicate compoundPredicateType],
index = [left indexOfItemWithRepresentedObject:type];
[left selectItemAtIndex:index];
}
- (void)_setComparisonPredicate:(CPComparisonPredicate)predicate
{
var left = [_views objectAtIndex:0],
middle = [_views objectAtIndex:1],
right = [_views objectAtIndex:2],
leftExpression = [predicate leftExpression],
rightExpression = [predicate rightExpression],
operator = [predicate predicateOperatorType];
if (_leftIsWildcard)
[left setObjectValue:[leftExpression constantValue]];
else
{
var index = [left indexOfItemWithRepresentedObject:leftExpression];
[left selectItemAtIndex:index];
}
var op_index = [middle indexOfItemWithRepresentedObject:operator];
[middle selectItemAtIndex:op_index];
if (_rightIsWildcard)
[right setObjectValue:[rightExpression constantValue]];
else
{
var index = [right indexOfItemWithRepresentedObject:rightExpression];
[right selectItemAtIndex:index];
}
}
- (CPExpression)_leftExpression
{
return [self _expressionFromView:_views[0] forAttributeType:_leftAttributeType];
}
- (CPExpression)_rightExpression
{
return [self _expressionFromView:_views[2] forAttributeType:_rightAttributeType];
}
- (CPExpression)_expressionFromView:(CPView)aView forAttributeType:(CPAttributeType)attributeType
{
if (attributeType == 0)
return [[aView selectedItem] representedObject];
var value;
if (attributeType >= CPInteger16AttributeType && attributeType <= CPFloatAttributeType)
value = [aView intValue];
else if (attributeType == CPBooleanAttributeType)
value = [aView state];
else
value = [aView stringValue];
return [CPExpression expressionForConstantValue:value];
}
- (int)_rowType
{
return (_templateType - 1);
}
- (id)copy
{
return [CPKeyedUnarchiver unarchiveObjectWithData:[CPKeyedArchiver archivedDataWithRootObject:self]];
}
+ (id)_operatorsForAttributeType:(CPAttributeType)attributeType
{
var operators_array = [CPMutableArray array];
switch (attributeType)
{
case CPInteger16AttributeType : [operators_array addObjects:4,5,0,2,1,3];
break;
case CPInteger32AttributeType : [operators_array addObjects:4,5,0,2,1,3];
break;
case CPInteger64AttributeType : [operators_array addObjects:4,5,0,2,1,3];
break;
case CPDecimalAttributeType : [operators_array addObjects:4,5,0,2,1,3];
break;
case CPDoubleAttributeType : [operators_array addObjects:4,5,0,2,1,3];
break;
case CPFloatAttributeType : [operators_array addObjects:4,5,0,2,1,3];
break;
case CPStringAttributeType : [operators_array addObjects:99,4,5,8,9];
break;
case CPBooleanAttributeType : [operators_array addObjects:4,5];
break;
case CPDateAttributeType : [operators_array addObjects:4,5,0,2,1,3];
break;
default : CPLogConsole("Cannot create operators for an CPAttributeType " + attributeType);
break;
}
return operators_array;
}
- (int)_templateType
{
return _templateType;
}
- (id)_displayValueForPredicateOperator:(int)operator
{
var value;
switch (operator)
{
case CPLessThanPredicateOperatorType : value = @"is less than";
break;
case CPLessThanOrEqualToPredicateOperatorType : value = @"is less than or equal to";
break;
case CPGreaterThanPredicateOperatorType : value = @"is greater than";
break;
case CPGreaterThanOrEqualToPredicateOperatorType : value = @"is greater than or equal to";
break;
case CPEqualToPredicateOperatorType : value = @"is";
break;
case CPNotEqualToPredicateOperatorType : value = @"is not";
break;
case CPMatchesPredicateOperatorType : value = @"matches";
break;
case CPLikePredicateOperatorType : value = @"is like";
break;
case CPBeginsWithPredicateOperatorType : value = @"begins with";
break;
case CPEndsWithPredicateOperatorType : value = @"ends with";
break;
case CPInPredicateOperatorType : value = @"in";
break;
case CPContainsPredicateOperatorType : value = @"contains";
break;
case CPBetweenPredicateOperatorType : value = @"between";
break;
default : CPLogConsole(@"unknown predicate operator %d" + operator);
}
return value;
}
- (id)_displayValueForCompoundPredicateType:(unsigned int)predicateType
{
var value;
switch (predicateType)
{
case CPNotPredicateType: value = @"None";
break;
case CPAndPredicateType: value = @"All";
break;
case CPOrPredicateType: value = @"Any";
break;
default : value = [CPString stringWithFormat:@"unknown compound predicate type %d",predicateType];
}
return value;
}
- (id)_displayValueForConstantValue:(id)value
{
return [value description]; // number, date, string, ... localize
}
- (id)_displayValueForKeyPath:(CPString)keyPath
{
return keyPath; // localize
}
- (CPPopUpButton)_viewFromExpressions:(CPArray)expressions
{
var popup = [[CPPopUpButton alloc] initWithFrame:CPMakeRect(0, 0, 100, 18)],
count = [expressions count];
for (var i = 0; i < count; i++)
{
var exp = expressions[i],
type = [exp expressionType],
title;
switch (type)
{
case CPKeyPathExpressionType: title = [self _displayValueForKeyPath:[exp keyPath]];
break;
case CPConstantValueExpressionType: title = [self _displayValueForConstantValue:[exp constantValue]];
break;
default: [CPException raise:CPInvalidArgumentException reason:@"Invalid Expression type " + type];
break;
}
var item = [[CPMenuItem alloc] initWithTitle:title action:nil keyEquivalent:@""];
[item setRepresentedObject:exp];
[popup addItem:item];
}
[popup sizeToFit];
return popup;
}
- (CPPopUpButton)_viewFromOperatorTypes:(CPArray)operators
{
var popup = [[CPPopUpButton alloc] initWithFrame:CGRectMake(0, 0, 100, 18)],
count = [operators count];
for (var i = 0; i < count; i++)
{
var op = operators[i],
title = [self _displayValueForPredicateOperator:op],
item = [[CPMenuItem alloc] initWithTitle:title action:nil keyEquivalent:@""];
[item setRepresentedObject:op];
[popup addItem:item];
}
[popup sizeToFit];
return popup;
}
- (CPView)_viewFromCompoundTypes:(CPArray)compoundTypes
{
var popup = [[CPPopUpButton alloc] initWithFrame:CGRectMake(0, 0, 100, 18)],
count = [compoundTypes count];
for (var i = 0; i < count; i++)
{
var type = compoundTypes[i],
title = [self _displayValueForCompoundPredicateType:type],
item = [[CPMenuItem alloc] initWithTitle:title action:nil keyEquivalent:@""];
[item setRepresentedObject:type];
[popup addItem:item];
}
[popup sizeToFit];
return popup;
}
- (CPView)_viewFromAttributeType:(CPAttributeType)attributeType
{
var view;
if (attributeType >= CPInteger16AttributeType && attributeType <= CPFloatAttributeType)
{
view = [self _textFieldWithFrame:CGRectMake(0, 0, 50, 26)];
}
else if (attributeType == CPStringAttributeType)
{
view = [self _textFieldWithFrame:CGRectMake(0, 0, 150, 26)];
}
else if (attributeType == CPBooleanAttributeType)
{
view = [[CPCheckBox alloc] initWithFrame:CGRectMake(0, 0, 50, 26)];
}
else if (attributeType == CPDateAttributeType)
view = [[CPDatePicker alloc] initWithFrame:CGRectMake(0, 0, 150, 26)];
else
return nil;
[view setTag:attributeType];
return view;
}
- (CPTextField)_textFieldWithFrame:(CGRect)frame
{
var textField = [[CPTextField alloc] initWithFrame:frame];
[textField setBezeled:YES];
[textField setBezelStyle:CPTextFieldSquareBezel];
[textField setBordered:YES];
[textField setEditable:YES];
[textField setFont:[CPFont systemFontOfSize:10]];
return textField;
}
- (void)_setOptions:(unsigned int)options
{
_predicateOptions = options;
}
- (void)_setModifier:(unsigned int)modifier
{
_predicateModifier = modifier;
}
- (CPString)description
{
if (_templateType == 2)
return [CPString stringWithFormat:@"<%@ %p %@>",[self className],self,[[self compoundTypes] componentsJoinedByString:@", "]];
else if (_templateType == 1 && _rightIsWildcard)
return [CPString stringWithFormat:@"<%@ %p [%@] [%@] %d>",[self className],self,[[self leftExpressions] componentsJoinedByString:@", "],[[self operators] componentsJoinedByString:@", "],[self rightExpressionAttributeType]];
else
return [CPString stringWithFormat:@"<%@ %p [%@] [%@] [%@]>",[self className],self,[[self leftExpressions] componentsJoinedByString:@", "],[[self operators] componentsJoinedByString:@", "],[[self rightExpressions] componentsJoinedByString:@", "]];
}
/*
- (void)_setLeftExpressionObject:(id)object
{
}
- (void)_setRightExpressionObject:(id)object
{
}
- (BOOL)_predicateIsNoneAreTrue:(id)predicate
{
}
- (id)_viewFromExpressionObject:(id)object
{
}
*/
@end
var CPPredicateTemplateTypeKey = @"CPPredicateTemplateType",
CPPredicateTemplateOptionsKey = @"CPPredicateTemplateOptions",
CPPredicateTemplateModifierKey = @"CPPredicateTemplateModifier",
CPPredicateTemplateLeftAttributeTypeKey = @"CPPredicateTemplateLeftAttributeType",
CPPredicateTemplateRightAttributeTypeKey = @"CPPredicateTemplateRightAttributeType",
CPPredicateTemplateLeftIsWildcardKey = @"CPPredicateTemplateLeftIsWildcard",
CPPredicateTemplateRightIsWildcardKey = @"CPPredicateTemplateRightIsWildcard",
CPPredicateTemplateViewsKey = @"CPPredicateTemplateViews";
@implementation CPPredicateEditorRowTemplate (CPCoding)
- (id)initWithCoder:(CPCoder)coder
{
self = [super init];
if (self != nil)
{
_templateType = [coder decodeIntForKey:CPPredicateTemplateTypeKey];
_predicateOptions = [coder decodeIntForKey:CPPredicateTemplateOptionsKey];
_predicateModifier = [coder decodeIntForKey:CPPredicateTemplateModifierKey];
_leftAttributeType = [coder decodeIntForKey:CPPredicateTemplateLeftAttributeTypeKey];
_rightAttributeType = [coder decodeIntForKey:CPPredicateTemplateRightAttributeTypeKey];
_leftIsWildcard = [coder decodeBoolForKey:CPPredicateTemplateLeftIsWildcardKey];
_rightIsWildcard = [coder decodeBoolForKey:CPPredicateTemplateRightIsWildcardKey];
_views = [coder decodeObjectForKey:CPPredicateTemplateViewsKey];
// In Xcode 4, when the menu item title == template's expression keypath, representedObject is empty.
// So we need to regenerate expressions from titles.
if (_templateType == 1 && _leftIsWildcard == NO)
{
var itemArray = [_views[0] itemArray],
count = [itemArray count];
for (var i = 0; i < count; i++)
{
var item = itemArray[i];
if ([item representedObject] == nil)
{
var exp = [CPExpression expressionForKeyPath:[item title]];
[item setRepresentedObject:exp];
}
}
}
}
return self;
}
- (void)encodeWithCoder:(CPCoder)coder
{
[coder encodeInt:_templateType forKey:CPPredicateTemplateTypeKey];
[coder encodeInt:_predicateOptions forKey:CPPredicateTemplateOptionsKey];
[coder encodeInt:_predicateModifier forKey:CPPredicateTemplateModifierKey];
[coder encodeInt:_leftAttributeType forKey:CPPredicateTemplateLeftAttributeTypeKey];
[coder encodeInt:_rightAttributeType forKey:CPPredicateTemplateRightAttributeTypeKey];
[coder encodeBool:_leftIsWildcard forKey:CPPredicateTemplateLeftIsWildcardKey];
[coder encodeBool:_rightIsWildcard forKey:CPPredicateTemplateRightIsWildcardKey];
[coder encodeObject:_views forKey:CPPredicateTemplateViewsKey];
}
@end
/*! @endcond */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,132 @@
/*
* Created by cacaodev@gmail.com.
* Copyright (c) 2011 Pear, Inc. All rights reserved.
*/
@class _CPPredicateEditorTree;
@implementation _CPPredicateEditorRowNode : CPObject
{
_CPPredicateEditorTree tree @accessors;
CPMutableArray templateViews @accessors;
CPMutableArray copiedTemplateContainer @accessors;
CPArray children @accessors(copy);
}
+ (id)rowNodeFromTree:(id)aTree
{
var mapTable = {};
return [_CPPredicateEditorRowNode _rowNodeFromTree:aTree withTemplateTable:mapTable];
}
+ (id)_rowNodeFromTree:(id)aTree withTemplateTable:(id)templateTable
{
var node,
views,
copiedContainer;
node = [[_CPPredicateEditorRowNode alloc] init];
node.tree = aTree;
var template = [aTree template],
uuid = [template UID];
var cachedNode = templateTable[uuid];
if (cachedNode == nil)
{
views = [CPMutableArray array];
copiedContainer = [CPMutableArray array];
templateTable[uuid] = node;
}
else
{
views = [cachedNode templateViews];
copiedContainer = [cachedNode copiedTemplateContainer];
}
node.templateViews = views;
node.copiedTemplateContainer = copiedContainer;
var nodeChildren = [CPMutableArray array],
treeChildren = [aTree children],
count = [treeChildren count];
for (var i = 0; i < count; i++)
{
var treeChild = treeChildren[i],
child = [_CPPredicateEditorRowNode _rowNodeFromTree:treeChild withTemplateTable:templateTable];
[nodeChildren addObject:child];
}
[node setChildren:nodeChildren];
return node;
}
- (BOOL)applyTemplate:(id)template withViews:(id)views forOriginalTemplate:(id)originalTemplate
{
var t = [tree template];
if (t !== template)
{
[templateViews setArray:views];
[copiedTemplateContainer removeAllObjects];
[copiedTemplateContainer addObject:template];
}
var count = [children count];
for (var i; i < count; i++)
[children[i] applyTemplate:template withViews:views forOriginalTemplate:originalTemplate];
}
- (BOOL)isEqual:(id)node
{
if (![node isKindOfClass:[_CPPredicateEditorRowNode class]])
return NO;
return (tree === [node tree]);
}
- (void)copyTemplateIfNecessary
{
if ([copiedTemplateContainer count] == 0)
{
CPLogConsole("COPYING TEMPLATE");
var copy = [[tree template] copy];
[copiedTemplateContainer addObject:copy];
[templateViews addObjectsFromArray:[copy templateViews]];
}
}
- (CPView)templateView
{
[self copyTemplateIfNecessary];
return [templateViews objectAtIndex:[tree indexIntoTemplate]];
}
- (id)templateForRow
{
[self copyTemplateIfNecessary];
return [copiedTemplateContainer lastObject];
}
- (CPString)title
{
return [tree title];
}
- (id)displayValue
{
var title = [self title];
if (title != nil)
return title;
return [self templateView];
}
- (CPString)description
{
return [CPString stringWithFormat:@"<%@ %@ %@ tree:%@ tviews:%@", [self className],[self UID], [self title], [tree UID], [templateViews description]];
}
@end
@@ -0,0 +1,33 @@
/*
* Created by cacaodev@gmail.com.
* Copyright (c) 2011 Pear, Inc. All rights reserved.
*/
@implementation _CPPredicateEditorTree : CPObject
{
CPPredicateEditorRowTemplate template @accessors;
CPString title @accessors(copy);
CPArray children @accessors(copy);
CPInteger indexIntoTemplate @accessors;
CPInteger menuItemIndex @accessors;
}
- (id)copy
{
var tree = [[_CPPredicateEditorTree alloc] init];
[tree setTemplate:template];
[tree setTitle:title];
[tree setMenuItemIndex:menuItemIndex];
[tree setIndexIntoTemplate:indexIntoTemplate];
[tree setChildren:children];
return tree;
}
- (CPString)description
{
return [CPString stringWithFormat:@"<%@: %p (%@) [%d-%d] T:%p at:%d> [\r%@\r]", [self className], self, title, indexIntoTemplate, menuItemIndex, template, [template rightExpressionAttributeType], children];
}
@end
@@ -0,0 +1,75 @@
/*
* Created by cacaodev@gmail.com.
* Copyright (c) 2011 Pear, Inc. All rights reserved.
*/
@import <Foundation/CPObject.j>
@import <Foundation/CPDictionary.j>
@import <Foundation/CPString.j>
var regex = new RegExp("\"(.+)\"\\s*=\\s*\"(.+)\"\\s*;\\s*(//.+)?");
@implementation _CPRuleEditorLocalizer : CPObject
{
CPDictionary _dictionary @accessors(property=dictionary);
CPURLConnection connection;
CPURLRequest resquest;
}
- (void)loadContentOfURL:(CPURL)aURL
{
request = [CPURLRequest requestWithURL:aURL];
connection = [CPURLConnection connectionWithRequest:request delegate:self];
}
- (void)reloadIfNeeded
{
if (connection != nil) // Connection waiting
{
connection = nil;
var data = [CPURLConnection sendSynchronousRequest:request returningResponse:NULL];
[self loadContent:[data rawString]];
}
}
- (void)connection:(CPURLConnection)aConnection didReceiveData:(CPString)rawString
{
if (connection != nil && rawString != nil)
[self loadContent:rawString];
connection = nil;
}
- (void)loadContent:(CPString)aContent
{
var dict = [CPDictionary dictionary],
lines = [aContent componentsSeparatedByString:"\n"],
count = [lines count];
for (var i = 0 ; i < count ; i++)
{
var line = [lines objectAtIndex:i];
if (line.length > 1)
{
var match = regex.exec(line);
if (match.length >= 3)
[dict setObject:match[2] forKey:match[1]];
}
}
_dictionary = [CPDictionary dictionaryWithDictionary:dict];
}
- (CPString)localizedStringForString:(CPString)aString
{
[self reloadIfNeeded];
if (_dictionary != nil && aString != nil)
{
var localized = [_dictionary objectForKey:aString];
if (localized != nil)
return localized;
}
return aString;
}
@@ -0,0 +1,157 @@
/*
* Created by cacaodev@gmail.com.
* Copyright (c) 2011 Pear, Inc. All rights reserved.
*/
var GRADIENT_NORMAL,
GRADIENT_HIGHLIGHTED,
IE_FILTER = "progid:DXImageTransform.Microsoft.gradient(startColorstr='#fcfcfc', endColorstr='#dfdfdf')";
@implementation _CPRuleEditorPopUpButton : CPPopUpButton
{
CPInteger radius;
}
+ (void)initialize
{
if (CPBrowserIsEngine(CPWebKitBrowserEngine))
{
GRADIENT_NORMAL = "-webkit-gradient(linear, left top, left bottom, from(rgb(252, 252, 252)), to(rgb(223, 223, 223)))";
GRADIENT_HIGHLIGHTED = "-webkit-gradient(linear, left top, left bottom, from(rgb(223, 223, 223)), to(rgb(252, 252, 252)))";
}
else if (CPBrowserIsEngine(CPGeckoBrowserEngine))
{
GRADIENT_NORMAL = "-moz-linear-gradient(top, rgb(252, 252, 252), rgb(223, 223, 223))";
GRADIENT_HIGHLIGHTED = "-moz-linear-gradient(top, rgb(223, 223, 223), rgb(252, 252, 252))";
}
}
- (id)initWithFrame:(CGRect)aFrame
{
if (self = [super initWithFrame:aFrame])
{
var style = _DOMElement.style;
style.backgroundImage = GRADIENT_NORMAL;
style.border = "1px solid rgb(189, 189, 189)";
style.filter = IE_FILTER;
[self setTextColor:[CPColor colorWithWhite:101 / 255 alpha:1]];
[self setBordered:NO];
}
return self;
}
- (id)hitTest:(CPPoint)point
{
var slice = [self superview];
if (!CPRectContainsPoint([self frame], point) || ![self sliceIsEditable])
return nil;
return self;
}
- (void)setHighlighted:(BOOL)shouldHighlight
{
_DOMElement.style.backgroundImage = (shouldHighlight) ? GRADIENT_HIGHLIGHTED : GRADIENT_NORMAL;
}
- (BOOL)sliceIsEditable
{
return [[self superview] isEditable];
}
- (BOOL)trackMouse:(CPEvent)theEvent
{
if (![self sliceIsEditable])
return NO;
return [super trackMouse:theEvent];
}
- (CGRect)contentRectForBounds:(CGRect)bounds
{
var contentRect = [super contentRectForBounds:bounds];
contentRect.origin.x += radius;
contentRect.size.width -= 2 * radius;
return contentRect;
}
- (void)layoutSubviews
{
radius = FLOOR(CGRectGetHeight([self bounds])/2);
var style = _DOMElement.style,
radiusCSS = radius + "px";
//style.webkitBorderRadius = radiusCSS;
//style.mozBorderRadius = radiusCSS;
style.borderRadius = radiusCSS;
[super layoutSubviews];
}
- (void)drawRect:(CGRect)aRect
{
var bounds = [self bounds],
context = [[CPGraphicsContext currentContext] graphicsPort];
var arrow_width = FLOOR(CGRectGetHeight(bounds)/3.5);
CGContextTranslateCTM(context, CGRectGetWidth(bounds) - radius - arrow_width, CGRectGetHeight(bounds) / 2);
var arrowsPath = [CPBezierPath bezierPath];
[arrowsPath moveToPoint:CGPointMake(0, 1)];
[arrowsPath lineToPoint:CGPointMake(arrow_width, 1)];
[arrowsPath lineToPoint:CGPointMake(arrow_width/2, arrow_width + 1)];
[arrowsPath closePath];
CGContextSetFillColor(context, [CPColor colorWithWhite:101/255 alpha:1]);
[arrowsPath fill];
CGContextScaleCTM(context, 1 , -1);
[arrowsPath fill];
}
@end
@implementation _CPRuleEditorButton : CPButton
{
CPInteger radius;
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
[self setFont:[CPFont boldFontWithName:@"Apple Symbol" size:12.0]];
[self setTextColor:[CPColor colorWithWhite:150/255 alpha:1]];
[self setAlignment:CPCenterTextAlignment];
[self setAutoresizingMask:CPViewMinXMargin];
[self setImagePosition:CPImageOnly];
[self setBordered:NO];
var style = _DOMElement.style;
style.border = "1px solid rgb(189, 189, 189)";
style.filter = IE_FILTER;
}
return self;
}
- (void)layoutSubviews
{
radius = FLOOR(CGRectGetHeight([self bounds])/2);
var style = _DOMElement.style,
radiusCSS = radius + "px";
style.borderRadius = radiusCSS;
style.backgroundImage = ([self isHighlighted]) ? GRADIENT_HIGHLIGHTED : GRADIENT_NORMAL;
[super layoutSubviews];
}
@end
@@ -0,0 +1,109 @@
/*
* Created by cacaodev@gmail.com.
* Copyright (c) 2011 Pear, Inc. All rights reserved.
*/
@implementation _CPRuleEditorViewSlice : CPView
{
CPRuleEditor _ruleEditor;
int _indentation @accessors(property=indentation);
int _rowIndex @accessors(property=rowIndex);
CPRect _animationTargetRect @accessors(property=_animationTargetRect);
BOOL _selected @accessors(getter=_isSelected, setter=_setSelected:);
BOOL _lastSelected @accessors(getter=_isLastSelected, setter=_setLastSelected:);
CPColor _backgroundColor @accessors(property=backgroundColor);
}
- (void)removeFromSuperview
{
[super removeFromSuperview];
}
- (id)initWithFrame:(CGRect)frame ruleEditorView:(id)editor
{
if (self = [super initWithFrame:frame])
{
_ruleEditor = editor;
_selected = NO;
_lastSelected = NO;
}
return self;
}
- (void)_setSelected:(BOOL)select
{
if (select == _selected)
return;
var selector = select ? @"setThemeState:" : @"unsetThemeState:";
[[self subviews] makeObjectsPerformSelector:CPSelectorFromString(selector) withObject:CPThemeStateSelectedDataView];
_selected = select;
}
- (void)drawRect:(CPRect)rect
{
var context = [[CPGraphicsContext currentContext] graphicsPort],
bounds = [self bounds],
maxX = CGRectGetWidth(bounds) - 2,
maxY = CGRectGetHeight(bounds);
// Draw background
if ([self _isSelected])
_backgroundColor = [_ruleEditor _selectedRowColor];
else
{
var colors = [_ruleEditor _backgroundColors],
count = [colors count];
_backgroundColor = [colors objectAtIndex:(_rowIndex % count)];
}
CGContextSetFillColor(context, _backgroundColor);
CGContextFillRect(context, rect);
// Draw Top Border
CGContextBeginPath(context);
CGContextMoveToPoint(context, 1, 0);
CGContextAddLineToPoint(context, maxX, 0);
CGContextClosePath(context);
CGContextSetStrokeColor(context, [_ruleEditor _sliceTopBorderColor]);
CGContextStrokePath(context);
// Draw Bottom Border
CGContextBeginPath(context);
CGContextMoveToPoint(context, 1, maxY - 0.5);
CGContextAddLineToPoint(context, maxX, maxY - 0.5);
CGContextClosePath(context);
var bottomColor = (_rowIndex == [_ruleEditor _lastRow]) ? [_ruleEditor _sliceLastBottomBorderColor] : [_ruleEditor _sliceBottomBorderColor];
CGContextSetStrokeColor(context, bottomColor);
CGContextStrokePath(context);
}
- (void)mouseDown:(CPEvent)theEvent
{
if (editable)
[_ruleEditor _mouseDownOnSlice:self withEvent:theEvent];
}
- (void)mouseUp:(CPEvent)theEvent
{
if (editable)
[_ruleEditor _mouseUpOnSlice:self withEvent:theEvent];
}
/*
- (void)rightMouseDown:(CPEvent)theEvent
{
[_ruleEditor _rightMouseDownOnSlice:self withEvent:theEvent];
}
*/
// =========
// ! DEBUG
// =========
- (CPString)description
{
return [CPString stringWithFormat:@"<%@ %p index:%d indentation:%d>",[self className],self,[self rowIndex],[self indentation]];
}
@end
@@ -0,0 +1,512 @@
/*
* Created by cacaodev@gmail.com.
* Copyright (c) 2011 Pear, Inc. All rights reserved.
*/
@import "_CPRuleEditorViewSlice.j"
@import "_CPRuleEditorPopUpButton.j"
@import "CPRuleEditor.j"
var CONTROL_HEIGHT = 16.,
BUTTON_HEIGHT = 16.;
@implementation _CPRuleEditorViewSliceRow : _CPRuleEditorViewSlice
{
CPMutableArray _ruleOptionViews;
CPMutableArray _ruleOptionFrames;
CPMutableArray _correspondingRuleItems;
CPMutableArray _ruleOptionInitialViewFrames;
CPButton _addButton;
CPButton _subtractButton;
BOOL editable;
CPRuleEditorRowType _rowType @accessors;
CPRuleEditorRowType _plusButtonRowType;
}
- (id)initWithFrame:(CGRect)frame ruleEditorView:(id)editor
{
if (self = [super initWithFrame:frame ruleEditorView:editor])
[self _initShared];
return self;
}
- (void)_initShared
{
_correspondingRuleItems = [[CPMutableArray alloc] init];
_ruleOptionFrames = [[CPMutableArray alloc] init];
_ruleOptionInitialViewFrames = [[CPMutableArray alloc] init];
_ruleOptionViews = [[CPMutableArray alloc] init];
editable = [_ruleEditor isEditable];
_addButton = [self _createAddRowButton];
_subtractButton = [self _createDeleteRowButton];
//[_addButton setToolTip:[_ruleEditor _toolTipForAddSimpleRowButton]];
//[_subtractButton setToolTip:[_ruleEditor _toolTipForDeleteRowButton]];
[_addButton setHidden:!editable];
[_subtractButton setHidden:!editable];
[self addSubview:_addButton];
[self addSubview:_subtractButton];
[self setAutoresizingMask:CPViewWidthSizable];
var center = [CPNotificationCenter defaultCenter];
[center addObserver:self selector:@selector(_textDidChange:) name:CPControlTextDidChangeNotification object:nil];
}
- (CPButton)_createAddRowButton
{
var button = [[_CPRuleEditorButton alloc] initWithFrame:CGRectMakeZero()];
[button setImage:[_ruleEditor _addImage]];
[button setAction:@selector(_addOption:)];
[button setTarget:self];
[button setAutoresizingMask:CPViewMinXMargin];
return button;
}
- (CPButton)_createDeleteRowButton
{
var button = [[_CPRuleEditorButton alloc] initWithFrame:CGRectMakeZero()];
[button setImage:[_ruleEditor _removeImage]];
[button setAction:@selector(_deleteOption:)];
[button setTarget:self];
[button setAutoresizingMask:CPViewMinXMargin];
return button;
}
- (CPMenuItem)_createMenuItemWithTitle:(CPString )title
{
title = [[_ruleEditor standardLocalizer] localizedStringForString:title];
var mItem = [[CPMenuItem alloc] initWithTitle:title action:nil keyEquivalent:@""];
return mItem;
}
- (CPPopUpButton)_createPopUpButtonWithItems:(CPArray)itemsArray selectedItemIndex:(int)index
{
var title = [[itemsArray objectAtIndex:index] title];
var font = [_ruleEditor font],
width = [title sizeWithFont:font].width + 20,
rect = CGRectMake(0, 0, (width - width % 40) + 80, CONTROL_HEIGHT);
var popup = [[_CPRuleEditorPopUpButton alloc] initWithFrame:rect];
[popup setValue:font forThemeAttribute:@"font"];
var count = [itemsArray count];
for (var i = 0; i < count; i++)
[popup addItem:[itemsArray objectAtIndex:i]];
[popup selectItemAtIndex:index];
return popup;
}
- (CPMenuItem)_createMenuSeparatorItem
{
return [CPMenuItem separatorItem];
}
- (_CPRuleEditorTextField)_createStaticTextFieldWithStringValue:(CPString )text
{
text = [[_ruleEditor standardLocalizer] localizedStringForString:text];
var textField = [[_CPRuleEditorTextField alloc] initWithFrame:CPMakeRect(0, 0, 200, CONTROL_HEIGHT)];
var font = [_ruleEditor font];
font = [CPFont fontWithName:font._name size:font._size + 2];
[textField setValue:font forThemeAttribute:@"font"];
[textField setStringValue:text];
[textField sizeToFit];
return textField;
}
- (void)_addOption:(id)sender
{
if (_rowIndex == [_ruleEditor numberOfRows] - 1)
[self setNeedsDisplay:YES];
var type = _plusButtonRowType;
if ([_ruleEditor nestingMode] == CPRuleEditorNestingModeCompound && ([[CPApp currentEvent] modifierFlags] & CPAlternateKeyMask))
type = CPRuleEditorRowTypeCompound;
[_ruleEditor _addOptionFromSlice:self ofRowType:type];
}
- (void)_deleteOption:(id)sender
{
[_ruleEditor _deleteSlice:self];
}
- (void)_ruleOptionPopupChangedAction:(CPMenuItem )sender
{
var layoutdict = [sender representedObject],
newItem = [layoutdict objectForKey:@"item"],
indexInCriteria = [layoutdict objectForKey:@"indexInCriteria"],
oldItem = [_correspondingRuleItems objectAtIndex:indexInCriteria];
if (![newItem isEqual:oldItem])
{
[_correspondingRuleItems replaceObjectAtIndex:indexInCriteria withObject:newItem];
[_ruleEditor _changedItem:oldItem toItem:newItem inRow:_rowIndex atCriteriaIndex:indexInCriteria];
}
}
- (BOOL)validateMenuItem:(CPMenuItem )menuItem
{
return [_ruleEditor _validateItem:menuItem value:[[menuItem representedObject] valueForKey:@"item"] inRow:_rowIndex];
}
- (void)_emptyRulePartSubviews
{
var count = [_ruleOptionViews count];
while (count--)
[_ruleOptionViews[count] removeFromSuperview];
[_ruleOptionViews removeAllObjects];
[_ruleOptionFrames removeAllObjects];
[_ruleOptionInitialViewFrames removeAllObjects];
}
- (void)_reconfigureSubviews
{
var ruleItems,
criteria,
repObject,
menuItem,
ruleView,
criterion,
parent,
numberOfCriteria,
numberOfChildren,
firstResponderIndex;
var ruleItems = [CPMutableArray array];
[self _emptyRulePartSubviews];
criteria = [_ruleEditor criteriaForRow:_rowIndex];
numberOfCriteria = [criteria count];
firstResponderIndex = numberOfCriteria - 1;
var responder = [[self window] firstResponder];
if (responder)
firstResponderIndex = [_ruleOptionViews indexOfObjectIdenticalTo:responder];
for (var i = 0; i < numberOfCriteria; i++)
{
ruleView = nil;
parent = nil;
criterion = [criteria objectAtIndex:i];
if (i > 0)
parent = [criteria objectAtIndex:i - 1];
var childItems = [],
childValues = [];
[_ruleEditor _getAllAvailableItems:childItems values:childValues asChildrenOfItem:parent inRow:_rowIndex];
numberOfChildren = [childItems count];
if (numberOfChildren > 1)
{
var menuItems = [CPMutableArray arrayWithCapacity:numberOfChildren];
var selectedIndex = [childItems indexOfObject:criterion];
if (selectedIndex == CPNotFound)
break;
for (var j = 0; j < numberOfChildren; ++j)
{
var childItem = [childItems objectAtIndex:j];
var childValue = [childValues objectAtIndex:j];
if ([childValue isKindOfClass:[CPMenuItem class]])
{
[[childValue menu] removeItem:childValue];
menuItem = childValue;
}
else
{
if ([childValue isEqualToString:@""])
menuItem = [self _createMenuSeparatorItem];
else
{
menuItem = [self _createMenuItemWithTitle:childValue];
[menuItem setTarget:self];
[menuItem setAction:@selector(_ruleOptionPopupChangedAction:)];
}
}
repObject = [CPDictionary dictionaryWithObjectsAndKeys:childItem, @"item", childValue, @"value", i, @"indexInCriteria"];
[menuItem setRepresentedObject:repObject];
[menuItems addObject:menuItem];
}
ruleView = [self _createPopUpButtonWithItems:menuItems selectedItemIndex:selectedIndex];
}
else
{
var value = [childValues objectAtIndex:0];
var type = [value valueType];
if (type === 0)
ruleView = [self _createStaticTextFieldWithStringValue:value];
else
{
if (type !== 1)
{
[CPException raise:CPInternalInconsistencyException reason:@"Display value must be a string or a menu item"];
continue;
}
ruleView = value;
[ruleView setTarget:self];
[ruleView setAction:@selector(_sendRuleAction:)];
if ([ruleView respondsToSelector:@selector(setDelegate:)])
[ruleView setDelegate:self];
}
}
if (ruleView != nil)
{
[_ruleOptionViews addObject:ruleView];
var frame = [ruleView frame];
[_ruleOptionInitialViewFrames addObject:frame];
[_ruleOptionFrames addObject:frame];
if (!criterion)
criterion = [CPNull null];
[ruleItems addObject:criterion];
}
}
[_correspondingRuleItems setArray:ruleItems];
if (!editable)
[self _updateEnabledStateForSubviews];
[self _relayoutSubviewsWidthChanged:YES];
if (firstResponderIndex != CPNotFound)
{
var aView = [_ruleOptionViews objectAtIndex:firstResponderIndex];
[[self window] makeFirstResponder:aView]; // This is not working. bug in CPPopUpButton firstResponder ?
}
//[self setNeedsDisplay:YES];
}
- (void)_updateEnabledStateForSubviews
{
[_ruleOptionViews makeObjectsPerformSelector:@selector(setEnabled:) withObject:NO];
}
- (void)layoutSubviews
{
// CPLogConsole(_cmd);
[self _relayoutSubviewsWidthChanged:YES];
}
- (void)_relayoutSubviewsWidthChanged:(BOOL)widthChanged
{
var optionViewOriginX,
leftHorizontalPadding,
leftButtonMinX,
rowHeight = [_ruleEditor rowHeight],
count = [_ruleOptionViews count],
sliceFrame = [self frame];
var buttonFrame = CGRectMake(CGRectGetWidth(sliceFrame) - BUTTON_HEIGHT - [self _rowButtonsRightHorizontalPadding], ([_ruleEditor rowHeight] - BUTTON_HEIGHT)/2 - 2, BUTTON_HEIGHT, BUTTON_HEIGHT);
[_addButton setFrame:buttonFrame];
buttonFrame.origin.x -= BUTTON_HEIGHT + [self _rowButtonsInterviewHorizontalPadding];
[_subtractButton setFrame:buttonFrame];
if (widthChanged)
{
optionViewOriginX = [self _leftmostViewFixedHorizontalPadding] + [self _indentationHorizontalPadding] * _indentation;
leftHorizontalPadding = [self _rowButtonsLeftHorizontalPadding];
leftButtonMinX = CGRectGetMinX(buttonFrame);
}
for (var i = 0; i < count; i++)
{
var ruleOptionView = _ruleOptionViews[i],
optionFrame = _ruleOptionFrames[i];
optionFrame.origin.y = (rowHeight - CGRectGetHeight(optionFrame))/2 - 2;
if (widthChanged)
{
optionFrame.origin.x = optionViewOriginX;
if (i == count - 1 && ![self _isRulePopup:ruleOptionView])
{
var initialFrame = _ruleOptionInitialViewFrames[i];
optionFrame.size.width = MIN(CGRectGetWidth(initialFrame), leftButtonMinX - leftHorizontalPadding - optionViewOriginX);
}
}
[ruleOptionView setFrame:optionFrame];
[self addSubview:ruleOptionView];
if (widthChanged)
optionViewOriginX += CGRectGetWidth(optionFrame) + [self _interviewHorizontalPadding];
}
}
- (void)_updateButtonVisibilities
{
[_addButton setHidden:[_ruleEditor _shouldHideAddButtonForSlice:self]];
[_subtractButton setHidden:[_ruleEditor _shouldHideSubtractButtonForSlice:self]];
}
- (void)_configurePlusButtonByRowType:(CPRuleEditorRowType)type
{
[self _setRowTypeToAddFromPlusButton:type];
}
- (BOOL)isEditable
{
return editable;
}
- (void)setEditable:(BOOL)value
{
editable = value;
// [self _updateEnabledStateForSubviews];
[self _updateButtonVisibilities];
}
- (float)_alignmentGridWidth
{
return [_ruleEditor _alignmentGridWidth];
}
- (float)_indentationHorizontalPadding
{
return 30.;
}
- (float)_interviewHorizontalPadding
{
return 6.;
}
- (float)_leftmostViewFixedHorizontalPadding
{
return 7.;
}
- (float)_minimumVerticalPopupPadding
{
return 2.;
}
- (float)_rowButtonsInterviewHorizontalPadding
{
return 6.;
}
- (float)_rowButtonsLeftHorizontalPadding
{
return 10.;
}
- (float)_rowButtonsRightHorizontalPadding
{
return 10.;
}
- (void)_setRowTypeToAddFromPlusButton:(int)type
{
_plusButtonRowType = type;
}
- (void)setNeedsDisplay:(BOOL)flag
{
[super setNeedsDisplay:flag];
}
- (BOOL)_nestingModeShouldHideAddButton
{
return [_ruleEditor _applicableNestingMode] == CPRuleEditorNestingModeSingle;
}
- (BOOL)_nestingModeShouldHideSubtractButton
{
return [_ruleEditor _applicableNestingMode] == CPRuleEditorNestingModeSingle;
}
- (BOOL)containsDisplayValue:(id)value
{
return [[_ruleEditor displayValuesForRow:_rowIndex] containsObject:value];
// Ou alors avec _correspondingRuleItems
}
- (void)viewDidMoveToWindow
{
[self layoutSubviews];
}
- (void)drawRect:(CPRect)rect
{
[super drawRect:rect];
}
- (BOOL)_isRulePopup:(CPView)view
{
if ([view isKindOfClass:[_CPRuleEditorPopUpButton class]])
return YES;
return NO;
}
- (BOOL)_isRuleStaticTextField:(CPView)view
{
if ([view isKindOfClass:[_CPRuleEditorTextField class]])
return YES;
return NO;
}
- (void)_sendRuleAction:(id)sender
{
[_ruleEditor _sendRuleAction];
}
- (void)_textDidChange:(CPNotification)aNotif
{
if ([[aNotif object] superview] == self && [_ruleEditor _sendsActionOnIncompleteTextChange])
[_ruleEditor _sendRuleAction];
}
@end
@implementation _CPRuleEditorTextField : CPTextField
{
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self != nil)
{
[self setBordered:NO];
[self setEditable:NO];
[self setDrawsBackground:NO];
}
return self;
}
- (id)hitTest:(CPPoint)point
{
if (!CPRectContainsPoint([self frame], point))
return nil;
return [self superview];
}
@end
+21
View File
@@ -1,3 +1,24 @@
/*
* CPSavePanel.j
* AppKit
*
* Created by Francisco Tolmasky.
* Copyright 2009, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPPanel.j"
+36 -2
View File
@@ -1,11 +1,45 @@
/*
* CPScreen.j
* AppKit
*
* Created by Francisco Tolmasky.
* Copyright 2009, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPObject.j>
/*!
@ingroup appkit
@class CPScreen
A CPScreen object describes the attributes of a display device available
to Cappuccino.
*/
@implementation CPScreen : CPObject
{
}
/*!
Returns the position and size of the visible area of the receiving screen.
This will normally be smaller than the full size of the screen to account
for system UI elements. For example, on a Mac the top of the visible frame
is placed below the bottom of the menu bar.
@return the visible screen rectangle
*/
- (CGRect)visibleFrame
{
#if PLATFORM(DOM)
@@ -15,4 +49,4 @@
#endif
}
@end
@end
+941 -537
View File
File diff suppressed because it is too large Load Diff
+270 -75
View File
@@ -5,6 +5,9 @@
* Created by Francisco Tolmasky.
* Copyright 2008, 280 North, Inc.
*
* Modified to match Lion style by Antoine Mercadal 2011
* <antoine.mercadal@archipelproject.org>
*
* 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
@@ -22,7 +25,6 @@
@import "CPControl.j"
// CPScroller Constants
CPScrollerNoPart = 0;
CPScrollerDecrementPage = 1;
@@ -54,6 +56,17 @@ NAMES_FOR_PARTS[CPScrollerKnobSlot] = @"knob-slot";
NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
CPScrollerStyleLegacy = 0;
CPScrollerStyleOverlay = 1;
CPScrollerKnobStyleDefault = 0;
CPScrollerKnobStyleDark = 1;
CPScrollerKnobStyleLight = 2;
CPThemeStateScrollViewLegacy = CPThemeState("scroller-style-legacy");
CPThemeStateScrollerKnobLight = CPThemeState("scroller-knob-light");
CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
@implementation CPScroller : CPControl
{
CPControlSize _controlSize;
@@ -68,8 +81,19 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
CPScrollerPart _trackingPart;
float _trackingFloatValue;
CGPoint _trackingStartPoint;
CPViewAnimation _animationScroller;
BOOL _allowFadingOut @accessors(getter=allowFadingOut);
int _style;
CPTimer _timerFadeOut;
BOOL _isMouseOver;
}
#pragma mark -
#pragma mark Class methods
+ (CPString)defaultThemeClass
{
return "scroller";
@@ -78,49 +102,43 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithJSObject:{
@"scroller-width": 15.0,
@"knob-slot-color": [CPColor lightGrayColor],
@"scroller-width": 7.0,
@"knob-slot-color": [CPNull null],
@"decrement-line-color": [CPNull null],
@"increment-line-color": [CPNull null],
@"knob-color": [CPColor grayColor],
@"knob-color": [CPNull null],
@"decrement-line-size":_CGSizeMakeZero(),
@"increment-line-size":_CGSizeMakeZero(),
@"track-inset":_CGInsetMakeZero(),
@"knob-inset": _CGInsetMakeZero(),
@"minimum-knob-length":21.0
}]
@"minimum-knob-length":21.0,
@"track-border-overlay": 9.0
}];
}
// Calculating Layout
- (id)initWithFrame:(CGRect)aFrame
+ (float)scrollerWidth
{
self = [super initWithFrame:aFrame];
if (self)
{
_controlSize = CPRegularControlSize;
_partRects = [];
[self setFloatValue:0.0];
[self setKnobProportion:1.0];
_hitPart = CPScrollerNoPart;
[self _calculateIsVertical];
}
return self;
return [self scrollerWidthInStyle:CPScrollerStyleLegacy];
}
// Determining CPScroller Size
/*!
Returns the CPScroller's width for a CPRegularControlSize.
*/
+ (float)scrollerWidth
+ (float)scrollerWidthInStyle:(int)aStyle
{
return [[[CPScroller alloc] init] currentValueForThemeAttribute:@"scroller-width"];
var scroller = [[self alloc] init];
if (aStyle == CPScrollerStyleLegacy)
return [scroller valueForThemeAttribute:@"scroller-width" inState:CPThemeStateScrollViewLegacy];
return [scroller currentValueForThemeAttribute:@"scroller-width"];
}
/*!
Returns the CPScroller's overlay value.
*/
+ (float)scrollerOverlay
{
return [[[self alloc] init] currentValueForThemeAttribute:@"track-border-overlay"];
}
/*!
@@ -132,6 +150,87 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
return [self scrollerWidth];
}
#pragma mark -
#pragma mark Initialization
- (id)initWithFrame:(CGRect)aFrame
{
if (self = [super initWithFrame:aFrame])
{
_controlSize = CPRegularControlSize;
_partRects = [];
[self setFloatValue:0.0];
[self setKnobProportion:1.0];
_hitPart = CPScrollerNoPart;
_allowFadingOut = YES;
_isMouseOver = NO;
_style = CPScrollerStyleOverlay;
var paramAnimFadeOut = [CPDictionary dictionaryWithObjects:[self, CPViewAnimationFadeOutEffect]
forKeys:[CPViewAnimationTargetKey, CPViewAnimationEffectKey]];
_animationScroller = [[CPViewAnimation alloc] initWithDuration:0.2 animationCurve:CPAnimationEaseInOut];
[_animationScroller setViewAnimations:[paramAnimFadeOut]];
[_animationScroller setDelegate:self];
[self setAlphaValue:0.0];
[self _calculateIsVertical];
}
return self;
}
#pragma mark -
#pragma mark Getters / Setters
/*!
Returns the scroller's style
*/
- (void)style
{
return _style;
}
/*!
Set the scroller's control size
@param aStyle the scroller style: CPScrollerStyleLegacy or CPScrollerStyleOverlay
*/
- (void)setStyle:(id)aStyle
{
if (_style != nil && _style === aStyle)
return;
_style = aStyle;
if (_style === CPScrollerStyleLegacy)
{
[self fadeIn];
[self setThemeState:CPThemeStateScrollViewLegacy];
}
else
{
_allowFadingOut = YES;
[self unsetThemeState:CPThemeStateScrollViewLegacy];
}
[self _adjustScrollerSize];
}
- (void)setObjectValue:(id)aValue
{
[super setObjectValue:MIN(1.0, MAX(0.0, +aValue))];
}
/*!
Returns the scroller's control size
*/
- (CPControlSize)controlSize
{
return _controlSize;
}
/*!
Sets the scroller's size.
@param aControlSize the scroller's size
@@ -148,18 +247,17 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
}
/*!
Returns the scroller's control size
Return's the knob's proportion
*/
- (CPControlSize)controlSize
- (float)knobProportion
{
return _controlSize;
}
- (void)setObjectValue:(id)aValue
{
[super setObjectValue:MIN(1.0, MAX(0.0, +aValue))];
return _knobProportion;
}
/*!
Set the knob's proportion
@param aProportion the desired proportion
*/
- (void)setKnobProportion:(float)aProportion
{
_knobProportion = MIN(1.0, MAX(0.0001, aProportion));
@@ -168,25 +266,35 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
[self setNeedsLayout];
}
/*!
Return's the knob's proportion
*/
- (float)knobProportion
#pragma mark -
#pragma mark Privates
/*! @ignore */
- (void)_adjustScrollerSize
{
return _knobProportion;
var frame = [self frame],
scrollerWidth = [self currentValueForThemeAttribute:@"scroller-width"];
if ([self isVertical] && CGRectGetWidth(frame) !== scrollerWidth)
frame.size.width = scrollerWidth;
if (![self isVertical] && CGRectGetHeight(frame) !== scrollerWidth)
frame.size.height = scrollerWidth;
[self setFrame:frame];
}
- (id)currentValueForThemeAttribute:(CPString)anAttributeName
/*! @ignore */
- (void)_performFadeOut:(CPTimer)aTimer
{
var themeState = _themeState;
if (NAMES_FOR_PARTS[_hitPart] + "-color" !== anAttributeName)
themeState &= ~CPThemeStateHighlighted;
return [self valueForThemeAttribute:anAttributeName inState:themeState];
[self fadeOut];
_timerFadeOut = nil;
}
// Calculating Layout
#pragma mark -
#pragma mark Utilities
- (CGRect)rectForPart:(CPScrollerPart)aPart
{
@@ -208,6 +316,9 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
// The ordering of these tests is important. We check the knob and
// page rects first since they may overlap with the arrows.
if (![self hasThemeState:CPThemeStateSelected])
return CPScrollerNoPart;
if (CGRectContainsPoint([self rectForPart:CPScrollerKnob], aPoint))
return CPScrollerKnob;
@@ -267,16 +378,16 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
incrementLineSize = [self currentValueForThemeAttribute:"increment-line-size"],
effectiveDecrementLineHeight = decrementLineSize.height + trackInset.top,
effectiveIncrementLineHeight = incrementLineSize.height + trackInset.bottom,
slotHeight = height - effectiveDecrementLineHeight - effectiveIncrementLineHeight,
slotSize = height - effectiveDecrementLineHeight - effectiveIncrementLineHeight,
minimumKnobLength = [self currentValueForThemeAttribute:"minimum-knob-length"],
knobWidth = width - knobInset.left - knobInset.right,
knobHeight = MAX(minimumKnobLength, (slotHeight * _knobProportion)),
knobLocation = effectiveDecrementLineHeight + (slotHeight - knobHeight) * [self floatValue];
knobHeight = MAX(minimumKnobLength, (slotSize * _knobProportion)),
knobLocation = effectiveDecrementLineHeight + (slotSize - knobHeight) * [self floatValue];
_partRects[CPScrollerDecrementPage] = _CGRectMake(0.0, effectiveDecrementLineHeight, width, knobLocation - effectiveDecrementLineHeight);
_partRects[CPScrollerKnob] = _CGRectMake(knobInset.left, knobLocation, knobWidth, knobHeight);
_partRects[CPScrollerIncrementPage] = _CGRectMake(0.0, knobLocation + knobHeight, width, height - (knobLocation + knobHeight) - effectiveIncrementLineHeight);
_partRects[CPScrollerKnobSlot] = _CGRectMake(trackInset.left, effectiveDecrementLineHeight, width - trackInset.left - trackInset.right, slotHeight);
_partRects[CPScrollerKnobSlot] = _CGRectMake(trackInset.left, effectiveDecrementLineHeight, width - trackInset.left - trackInset.right, slotSize);
_partRects[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
_partRects[CPScrollerIncrementLine] = _CGRectMake(0.0, height - incrementLineSize.height, incrementLineSize.width, incrementLineSize.height);
@@ -296,16 +407,16 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
incrementLineSize = [self currentValueForThemeAttribute:"increment-line-size"],
effectiveDecrementLineWidth = decrementLineSize.width + trackInset.left,
effectiveIncrementLineWidth = incrementLineSize.width + trackInset.right,
slotWidth = width - effectiveDecrementLineWidth - effectiveIncrementLineWidth,
slotSize = width - effectiveDecrementLineWidth - effectiveIncrementLineWidth,
minimumKnobLength = [self currentValueForThemeAttribute:"minimum-knob-length"],
knobWidth = MAX(minimumKnobLength, (slotWidth * _knobProportion)),
knobWidth = MAX(minimumKnobLength, (slotSize * _knobProportion)),
knobHeight = height - knobInset.top - knobInset.bottom,
knobLocation = effectiveDecrementLineWidth + (slotWidth - knobWidth) * [self floatValue];
knobLocation = effectiveDecrementLineWidth + (slotSize - knobWidth) * [self floatValue];
_partRects[CPScrollerDecrementPage] = _CGRectMake(effectiveDecrementLineWidth, 0.0, knobLocation - effectiveDecrementLineWidth, height);
_partRects[CPScrollerKnob] = _CGRectMake(knobLocation, knobInset.top, knobWidth, knobHeight);
_partRects[CPScrollerIncrementPage] = _CGRectMake(knobLocation + knobWidth, 0.0, width - (knobLocation + knobWidth) - effectiveIncrementLineWidth, height);
_partRects[CPScrollerKnobSlot] = _CGRectMake(effectiveDecrementLineWidth, trackInset.top, slotWidth, height - trackInset.top - trackInset.bottom);
_partRects[CPScrollerKnobSlot] = _CGRectMake(effectiveDecrementLineWidth, trackInset.top, slotSize, height - trackInset.top - trackInset.bottom);
_partRects[CPScrollerDecrementLine] = _CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
_partRects[CPScrollerIncrementLine] = _CGRectMake(width - incrementLineSize.width, 0.0, incrementLineSize.width, incrementLineSize.height);
@@ -316,7 +427,7 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
{
_partRects[CPScrollerIncrementLine] = _CGRectMakeZero();
_partRects[CPScrollerDecrementLine] = _CGRectMakeZero();
_partRects[CPScrollerKnobSlot] = _CGRectMake(0.0, 0.0, width, slotHeight);
_partRects[CPScrollerKnobSlot] = _CGRectMake(0.0, 0.0, width, slotSize);
}
}
}
@@ -330,7 +441,35 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
return _usableParts;
}
// Drawing the Parts
/*!
Display the scroller
*/
- (void)fadeIn
{
if (_isMouseOver && _knobProportion != 1.0)
[self setThemeState:CPThemeStateSelected];
if (_timerFadeOut)
[_timerFadeOut invalidate];
[self setAlphaValue:1.0];
}
/*!
Start the fade out anination
*/
- (void)fadeOut
{
if ([self hasThemeState:CPThemeStateScrollViewLegacy])
return;
[_animationScroller startAnimation];
}
#pragma mark -
#pragma mark Drawing
/*!
Draws the specified arrow and sets the highlight.
@param anArrow the arrow to draw
@@ -458,7 +597,8 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
[CPApp setTarget:self selector:@selector(trackKnob:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
[self sendAction:[self action] to:[self target]];
if (type === CPLeftMouseDragged)
[self sendAction:[self action] to:[self target]];
}
/*!
@@ -564,6 +704,20 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
[self setNeedsLayout];
}
#pragma mark -
#pragma mark Overrides
- (id)currentValueForThemeAttribute:(CPString)anAttributeName
{
var themeState = _themeState;
if (NAMES_FOR_PARTS[_hitPart] + "-color" !== anAttributeName)
themeState &= ~CPThemeStateHighlighted;
return [self valueForThemeAttribute:anAttributeName inState:themeState];
}
- (void)mouseDown:(CPEvent)anEvent
{
if (![self isEnabled])
@@ -582,10 +736,52 @@ NAMES_FOR_PARTS[CPScrollerKnob] = @"knob";
}
}
- (void)mouseEntered:(CPEvent)anEvent
{
[super mouseEntered:anEvent];
if (_timerFadeOut)
[_timerFadeOut invalidate];
if (![self isEnabled])
return;
_allowFadingOut = NO;
_isMouseOver = YES;
if ([self alphaValue] > 0 && _knobProportion != 1.0)
[self setThemeState:CPThemeStateSelected];
}
- (void)mouseExited:(CPEvent)anEvent
{
[super mouseExited:anEvent];
if ([self isHidden] || ![self isEnabled] || !_isMouseOver)
return;
_allowFadingOut = YES;
_isMouseOver = NO;
if (_timerFadeOut)
[_timerFadeOut invalidate];
_timerFadeOut = [CPTimer scheduledTimerWithTimeInterval:1.2 target:self selector:@selector(_performFadeOut:) userInfo:nil repeats:NO];
}
#pragma mark -
#pragma mark Delegates
- (void)animationDidEnd:(CPAnimation)animation
{
[self unsetThemeState:CPThemeStateSelected];
}
@end
var CPScrollerControlSizeKey = "CPScrollerControlSize",
CPScrollerKnobProportionKey = "CPScrollerKnobProportion";
var CPScrollerControlSizeKey = @"CPScrollerControlSize",
CPScrollerKnobProportionKey = @"CPScrollerKnobProportion",
CPScrollerStyleKey = @"CPScrollerStyleKey";
@implementation CPScroller (CPCoding)
@@ -605,20 +801,18 @@ var CPScrollerControlSizeKey = "CPScrollerControlSize",
_hitPart = CPScrollerNoPart;
_allowFadingOut = YES;
_isMouseOver = NO;
var paramAnimFadeOut = [CPDictionary dictionaryWithObjects:[self, CPViewAnimationFadeOutEffect]
forKeys:[CPViewAnimationTargetKey, CPViewAnimationEffectKey]];
_animationScroller = [[CPViewAnimation alloc] initWithDuration:0.2 animationCurve:CPAnimationEaseInOut];
[_animationScroller setViewAnimations:[paramAnimFadeOut]];
[_animationScroller setDelegate:self];
[self setAlphaValue:0.0];
[self _calculateIsVertical];
// Adjust the size of the scroller if the size from cib
// isn't equal to the scrollerWidth
var frame = [self frame],
scrollerWidth = [CPScroller scrollerWidth];
if ([self isVertical] && CGRectGetWidth(frame) !== scrollerWidth)
frame.size.width = scrollerWidth;
if (![self isVertical] && CGRectGetHeight(frame) !== scrollerWidth)
frame.size.height = scrollerWidth;
[self setFrame:frame];
[self setStyle:[aCoder decodeIntForKey:CPScrollerStyleKey]];
}
return self;
@@ -630,6 +824,7 @@ var CPScrollerControlSizeKey = "CPScrollerControlSize",
[aCoder encodeInt:_controlSize forKey:CPScrollerControlSizeKey];
[aCoder encodeFloat:_knobProportion forKey:CPScrollerKnobProportionKey];
[aCoder encodeInt:_style forKey:CPScrollerStyleKey];
}
@end
+19 -7
View File
@@ -109,7 +109,6 @@ var RECENT_SEARCH_PREFIX = @" ";
[self setBezelStyle:CPTextFieldRoundedBezel];
[self setBordered:YES];
[self setEditable:YES];
[self setDelegate:self];
[self setContinuous:YES];
var bounds = [self bounds],
@@ -125,6 +124,18 @@ var RECENT_SEARCH_PREFIX = @" ";
_canResignFirstResponder = YES;
}
- (void)viewWillMoveToSuperview:(CPView)aView
{
[super viewWillMoveToSuperview:aView];
// First we remove any observer that may have been in place to avoid memory leakage.
[[CPNotificationCenter defaultCenter] removeObserver:self name:CPControlTextDidChangeNotification object:self];
// Register the observe here if we need to.
if (aView)
[[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(_searchFieldTextDidChange:) name:CPControlTextDidChangeNotification object:self];
}
// Managing Buttons
/*!
Sets the button used to display the search-button image
@@ -181,7 +192,7 @@ var RECENT_SEARCH_PREFIX = @" ";
[_cancelButton setFrame:[self cancelButtonRectForBounds:[self bounds]]];
[_cancelButton setAutoresizingMask:CPViewMinXMargin];
[_cancelButton setTarget:self];
[_cancelButton setAction:@selector(_searchFieldCancel:)];
[_cancelButton setAction:@selector(cancelOperation:)];
[self _updateCancelButtonVisibility];
[self addSubview:_cancelButton];
}
@@ -198,7 +209,7 @@ var RECENT_SEARCH_PREFIX = @" ";
/*!
Resets the cancel button to its default attributes.
This method resets the target, action, regular image, and pressed image. By default, when users click the cancel button, the delete: action message is sent up the responder chain. This method gives you a way to customize the cancel button for specific situations and then reset the button defaults without having to undo changes individually.
This method resets the target, action, regular image, and pressed image. This method gives you a way to customize the cancel button for specific situations and then reset the button defaults without having to undo changes individually.
*/
- (void)resetCancelButton
{
@@ -209,7 +220,7 @@ var RECENT_SEARCH_PREFIX = @" ";
[button setAlternateImage:CPSearchFieldCancelPressedImage];
[button setAutoresizingMask:CPViewMinXMargin];
[button setTarget:self];
[button setAction:@selector(_searchFieldCancel:)];
[button setAction:@selector(cancelOperation:)];
}
// Custom Layout
@@ -420,7 +431,7 @@ var RECENT_SEARCH_PREFIX = @" ";
[_cancelButton setHidden:([[self stringValue] length] === 0)];
}
- (void)controlTextDidChange:(CPNotification)aNotification
- (void)_searchFieldTextDidChange:(CPNotification)aNotification
{
if (![self sendsWholeSearchString])
{
@@ -677,10 +688,11 @@ var RECENT_SEARCH_PREFIX = @" ";
[_partialStringTimer invalidate];
}
- (void)_searchFieldCancel:(id)sender
- (void)cancelOperation:(id)sender
{
[self setObjectValue:@""];
[self _sendPartialString];
[self textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:self userInfo:nil]];
[self _updateCancelButtonVisibility];
}
+21
View File
@@ -1,3 +1,24 @@
/*
* CPSecureTextField.j
* AppKit
*
* Created by Francisco Tolmasky.
* Copyright 2008, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPTextField.j"
+2 -2
View File
@@ -361,9 +361,9 @@ CPSegmentSwitchTrackingMomentary = 2;
}
/*!
Enables/diables the specified segment.
Enables/disables the specified segment.
@param isEnabled \c YES enables the segment
@param aSegment the segment to enable/disble
@param aSegment the segment to enable/disable
@throws CPRangeException if \c aSegment is out of bounds
*/
- (void)setEnabled:(BOOL)isEnabled forSegment:(unsigned)aSegment
+6 -3
View File
@@ -382,9 +382,14 @@ CPCircularSlider = 1;
[self setNeedsDisplay:YES];
}
- (BOOL)isContinuous
{
return (_sendActionOn & CPLeftMouseDraggedMask) !== 0;
}
/*!
@ignore
shoudl we have _continuous?
should we have _continuous?
*/
- (void)setContinuous:(BOOL)flag
{
@@ -425,8 +430,6 @@ var CPSliderMinValueKey = "CPSliderMinValueKey",
{
_altIncrementValue = [aCoder decodeDoubleForKey:CPSliderAltIncrValueKey];
[self setContinuous:YES];
[self _recalculateIsVertical];
[self setNeedsLayout];
+16 -16
View File
@@ -74,7 +74,7 @@
[_rgbLabel setStringValue: "Red, Green, Blue"];
[_rgbLabel setTextColor:[CPColor blackColor]];
_redLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 35, 15, 20)];
_redLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 37, 15, 20)];
[_redLabel setStringValue: "R"];
[_redLabel setTextColor:[CPColor blackColor]];
@@ -86,18 +86,18 @@
[_redSlider setAutoresizingMask: CPViewWidthSizable];
// red value input box
_redValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 30, 45, 29)];
_redValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 30, 45, 28)];
[_redValue setAutoresizingMask: CPViewMinXMargin];
[_redValue setEditable: YES];
[_redValue setBezeled: YES];
[_redValue setDelegate: self];
[_contentView addSubview: _redValue];
_greenLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 58, 15, 20)];
_greenLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 63, 15, 20)];
[_greenLabel setStringValue: "G"];
[_greenLabel setTextColor:[CPColor blackColor]];
_greenSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 58, aFrame.size.width - 70, 20)];
_greenSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 61, aFrame.size.width - 70, 20)];
[_greenSlider setMaxValue: 1.0];
[_greenSlider setMinValue: 0.0];
[_greenSlider setTarget: self];
@@ -105,18 +105,18 @@
[_greenSlider setAutoresizingMask: CPViewWidthSizable];
// green value input box
_greenValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 53, 45, 29)];
_greenValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 56, 45, 28)];
[_greenValue setAutoresizingMask: CPViewMinXMargin];
[_greenValue setEditable: YES];
[_greenValue setBezeled: YES];
[_greenValue setDelegate: self];
[_contentView addSubview: _greenValue];
_blueLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 81, 15, 20)];
_blueLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 90, 15, 20)];
[_blueLabel setStringValue: "B"];
[_blueLabel setTextColor:[CPColor blackColor]];
_blueSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 81, aFrame.size.width - 70, 20)];
_blueSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 87, aFrame.size.width - 70, 20)];
[_blueSlider setMaxValue: 1.0];
[_blueSlider setMinValue: 0.0];
[_blueSlider setTarget: self];
@@ -124,7 +124,7 @@
[_blueSlider setAutoresizingMask: CPViewWidthSizable];
// blue value input box
_blueValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 76, 45, 29)];
_blueValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 82, 45, 28)];
[_blueValue setAutoresizingMask: CPViewMinXMargin];
[_blueValue setEditable: YES];
[_blueValue setBezeled: YES];
@@ -139,7 +139,7 @@
[_hueLabel setStringValue: "H"];
[_hueLabel setTextColor:[CPColor blackColor]];
_hueSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 145, aFrame.size.width - 70, 20)];
_hueSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 143, aFrame.size.width - 70, 20)];
[_hueSlider setMaxValue: 359.0];
[_hueSlider setMinValue: 0.0];
[_hueSlider setTarget: self];
@@ -147,14 +147,14 @@
[_hueSlider setAutoresizingMask: CPViewWidthSizable];
// hue value input box
_hueValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 140, 45, 29)];
_hueValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 138, 45, 28)];
[_hueValue setAutoresizingMask: CPViewMinXMargin];
[_hueValue setEditable: YES];
[_hueValue setBezeled: YES];
[_hueValue setDelegate: self];
[_contentView addSubview: _hueValue];
_saturationLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 168, 15, 20)];
_saturationLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 170, 15, 20)];
[_saturationLabel setStringValue: "S"];
[_saturationLabel setTextColor:[CPColor blackColor]];
@@ -166,18 +166,18 @@
[_saturationSlider setAutoresizingMask: CPViewWidthSizable];
// saturation value input box
_saturationValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 163, 45, 29)];
_saturationValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 164, 45, 28)];
[_saturationValue setAutoresizingMask: CPViewMinXMargin];
[_saturationValue setEditable: YES];
[_saturationValue setBezeled: YES];
[_saturationValue setDelegate: self];
[_contentView addSubview: _saturationValue];
_brightnessLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 191, 15, 20)];
_brightnessLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 196, 15, 20)];
[_brightnessLabel setStringValue: "B"];
[_brightnessLabel setTextColor:[CPColor blackColor]];
_brightnessSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 191, aFrame.size.width - 70, 20)];
_brightnessSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 194, aFrame.size.width - 70, 20)];
[_brightnessSlider setMaxValue: 100.0];
[_brightnessSlider setMinValue: 0.0];
[_brightnessSlider setTarget: self];
@@ -185,7 +185,7 @@
[_brightnessSlider setAutoresizingMask: CPViewWidthSizable];
// brightness value input box
_brightnessValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 186, 45, 29)];
_brightnessValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 190, 45, 28)];
[_brightnessValue setAutoresizingMask: CPViewMinXMargin];
[_brightnessValue setEditable: YES];
[_brightnessValue setBezeled: YES];
@@ -197,7 +197,7 @@
[_hexLabel setTextColor:[CPColor blackColor]];
//hex input box
_hexValue = [[CPTextField alloc] initWithFrame: CGRectMake(32, 225, 80, 29)];
_hexValue = [[CPTextField alloc] initWithFrame: CGRectMake(32, 225, 80, 28)];
[_hexValue setEditable: YES];
[_hexValue setBezeled: YES];
[_hexValue setDelegate: self];
+62 -13
View File
@@ -25,6 +25,7 @@
CPSoundLoadStateEmpty = 0;
CPSoundLoadStateLoading = 1;
CPSoundLoadStateCanBePlayed = 2;
CPSoundLoadStateError = 3;
CPSoundPlayBackStatePlay = 0;
CPSoundPlayBackStateStop = 1;
@@ -44,6 +45,7 @@ CPSoundPlayBackStatePause = 2;
CPString _name @accessors(property=name);
id _delegate @accessors(property=delegate);
BOOL _playRequestBeforeLoad;
HTMLAudioElement _audioTag;
int _loadStatus;
int _playBackStatus;
@@ -60,14 +62,25 @@ CPSoundPlayBackStatePause = 2;
_loops = NO;
_audioTag = document.createElement("audio");
_audioTag.preload = YES;
_playRequestBeforeLoad = NO;
_audioTag.addEventListener("canplay", function()
{
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
[self _soundDidload];
});
}, true);
_audioTag.addEventListener("ended", function()
{
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
[self _soundDidEnd];
});
}, true);
_audioTag.addEventListener("error", function()
{
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
[self _soundError];
}, true);
}
return self;
@@ -77,7 +90,7 @@ CPSoundPlayBackStatePause = 2;
Initialize with the sound contents of the URL represented by aFile.
@param aFile CPString the path of the sound
@param byRef ignored (Cocoa compatibibility)
@param byRef ignored (Cocoa compatibility)
*/
- (id)initWithContentsOfFile:(CPString)aFile byReference:(BOOL)byRef
{
@@ -94,7 +107,7 @@ CPSoundPlayBackStatePause = 2;
Initialize with the sound contents of the file located at aURL.
@param aURL CPURL containing the URL of the sound
@param byRef ignored (Cocoa compatibibility)
@param byRef ignored (Cocoa compatibility)
*/
- (id)initWithContentsOfURL:(CPURL)aURL byReference:(BOOL)byRef
{
@@ -105,7 +118,7 @@ CPSoundPlayBackStatePause = 2;
Initialize with the sound contents of someData.
@param someData CPData containing the sound
@param byRef ignored (Cocoa compatibibility)
@param byRef ignored (Cocoa compatibility)
*/
- (id)initWithData:(CPData)someData
{
@@ -127,6 +140,12 @@ CPSoundPlayBackStatePause = 2;
- (void)_soundDidload
{
_loadStatus = CPSoundLoadStateCanBePlayed;
if (_playRequestBeforeLoad)
{
_playRequestBeforeLoad = NO;
[self play];
}
}
/*! @ignore
@@ -137,31 +156,51 @@ CPSoundPlayBackStatePause = 2;
[self stop];
}
/*! @ignore
*/
- (void)_soundError
{
_loadStatus = CPSoundLoadStateError;
CPLog.error("Cannot load sound. Maybe the format of your sound is not compatible with your browser.");
}
#pragma mark -
#pragma mark Media controls
/*!
Play the sound.
@return YES when the receiver is playing its audio data, NO otherwise.
*/
- (void)play
- (BOOL)play
{
if (_loadStatus === CPSoundLoadStateLoading)
{
_playRequestBeforeLoad = YES;
return YES;
}
if ((_loadStatus !== CPSoundLoadStateCanBePlayed)
|| (_playBackStatus === CPSoundPlayBackStatePlay))
return;
return NO;
_audioTag.play();
_playBackStatus = CPSoundPlayBackStatePlay;
return YES;
}
/*!
Stop the sound.
@return YES when the receiver is playing its audio data, NO otherwise.
*/
- (void)stop
- (BOOL)stop
{
if ((_loadStatus !== CPSoundLoadStateCanBePlayed)
|| (_playBackStatus === CPSoundPlayBackStateStop))
return;
return NO;
_audioTag.pause();
_audioTag.currentTime = 0.0;
@@ -169,32 +208,42 @@ CPSoundPlayBackStatePause = 2;
if (_delegate && [_delegate respondsToSelector:@selector(sound:didFinishPlaying:)])
[_delegate sound:self didFinishPlaying:YES];
return YES;
}
/*!
Pause the sound.
@return YES when the receiver is playing its audio data, NO otherwise.
*/
- (void)pause
- (BOOL)pause
{
if ((_loadStatus !== CPSoundLoadStateCanBePlayed)
|| (_playBackStatus === CPSoundPlayBackStatePause))
return;
return NO;
_audioTag.pause();
_playBackStatus = CPSoundPlayBackStatePause;
return YES;
}
/*!
Resume playback of a paused sound.
@return YES when the receiver is playing its audio data, NO otherwise.
*/
- (void)resume
- (BOOL)resume
{
if ((_loadStatus !== CPSoundLoadStateCanBePlayed)
|| (_playBackStatus !== CPSoundPlayBackStatePause))
return;
return NO;
_audioTag.play();
_playBackStatus = CPSoundPlayBackStatePlay;
return YES;
}
/*!
+416 -39
View File
@@ -20,41 +20,81 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "../Foundation/Foundation.h"
@import "CPButtonBar.j"
@import "CPImage.j"
@import "CPView.j"
#define SPLIT_VIEW_MAYBE_POST_WILL_RESIZE() \
if ((_suppressResizeNotificationsMask & DidPostWillResizeNotification) === 0) \
{ \
[self _postNotificationWillResize]; \
_suppressResizeNotificationsMask |= DidPostWillResizeNotification; \
}
#define SPLIT_VIEW_MAYBE_POST_DID_RESIZE() \
if ((_suppressResizeNotificationsMask & ShouldSuppressResizeNotifications) !== 0) \
_suppressResizeNotificationsMask |= DidSuppressResizeNotification; \
else \
[self _postNotificationDidResize];
#define SPLIT_VIEW_DID_SUPPRESS_RESIZE_NOTIFICATION() \
((_suppressResizeNotificationsMask & DidSuppressResizeNotification) !== 0)
#define SPLIT_VIEW_SUPPRESS_RESIZE_NOTIFICATIONS(shouldSuppress) \
if (shouldSuppress) \
_suppressResizeNotificationsMask |= ShouldSuppressResizeNotifications; \
else \
_suppressResizeNotificationsMask = 0;
CPSplitViewDidResizeSubviewsNotification = @"CPSplitViewDidResizeSubviewsNotification";
CPSplitViewWillResizeSubviewsNotification = @"CPSplitViewWillResizeSubviewsNotification";
var CPSplitViewHorizontalImage = nil,
CPSplitViewVerticalImage = nil;
CPSplitViewVerticalImage = nil,
ShouldSuppressResizeNotifications = 1,
DidPostWillResizeNotification = 1 << 1,
DidSuppressResizeNotification = 1 << 2;
/*!
@ingroup appkit
@class CPSplitView
CPSplitView is a view that allows you to stack several subviews vertically or horizontally. The user is given divider to resize the subviews.
The divider indices are zero-based. So the divider on the top (or left for vertical dividers) will be index 0.
CPSplitView can be supplied a delegate to provide control over the resizing of the splitview and subviews. Those methods are documented in setDelegate:
CPSplitView will add dividers for each subview you add. So just like adding subviews to a CPView you should call addSubview: to add new resizable subviews in your splitview.
*/
@implementation CPSplitView : CPView
{
id _delegate;
BOOL _isVertical;
BOOL _isPaneSplitter;
id _delegate;
BOOL _isVertical;
BOOL _isPaneSplitter;
int _currentDivider;
float _initialOffset;
float _preCollapsePosition;
int _currentDivider;
float _initialOffset;
CPDictionary _preCollapsePositions;
CPString _originComponent;
CPString _sizeComponent;
CPString _originComponent;
CPString _sizeComponent;
CPArray _DOMDividerElements;
CPString _dividerImagePath;
int _drawingDivider;
CPArray _DOMDividerElements;
CPString _dividerImagePath;
int _drawingDivider;
BOOL _needsResizeSubviews;
CPString _autosaveName;
BOOL _shouldAutosave;
BOOL _needsRestoreFromAutosave;
CPArray _buttonBars;
BOOL _needsResizeSubviews;
int _suppressResizeNotificationsMask;
CPArray _buttonBars;
}
+ (CPString)defaultThemeClass
@@ -64,7 +104,7 @@ var CPSplitViewHorizontalImage = nil,
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[10.0, 1.0, [CPColor grayColor]]
return [CPDictionary dictionaryWithObjects:[1.0, 10.0, [CPColor grayColor]]
forKeys:[@"divider-thickness", @"pane-divider-thickness", @"pane-divider-color"]];
}
@@ -85,27 +125,43 @@ var CPSplitViewHorizontalImage = nil,
{
if (self = [super initWithFrame:aFrame])
{
_suppressResizeNotificationsMask = 0;
_preCollapsePositions = [CPMutableDictionary new];
_currentDivider = CPNotFound;
_DOMDividerElements = [];
_buttonBars = [];
_shouldAutosave = YES;
[self _setVertical:YES];
}
return self;
}
/*!
Returns the thickness of the divider.
@return float - the thickness of the divider.
*/
- (float)dividerThickness
{
return [self currentValueForThemeAttribute:[self isPaneSplitter] ? @"pane-divider-thickness" : @"divider-thickness"];
}
/*!
Returns YES if the dividers are vertical, otherwise NO.
@return YES if vertical, otherwise NO.
*/
- (BOOL)isVertical
{
return _isVertical;
}
/*!
Sets if the splitview dividers are vertical.
@param shouldBeVertical - YES if the splitview dividers should be vertical, otherwise NO.
*/
- (void)setVertical:(BOOL)shouldBeVertical
{
if (![self _setVertical:shouldBeVertical])
@@ -147,11 +203,21 @@ var CPSplitViewHorizontalImage = nil,
return changed;
}
/*!
Use to find if the divider is a larger pane splitter.
@return BOOL - YES if the dividers are the larger pane splitters. Otherwise NO.
*/
- (BOOL)isPaneSplitter
{
return _isPaneSplitter;
}
/*!
Used to set if the split view dividers should be the larger pane splitter.
@param shouldBePaneSplitter - YES if the dividers should be the thicker pane splitter, otherwise NO.
*/
- (void)setIsPaneSplitter:(BOOL)shouldBePaneSplitter
{
if (_isPaneSplitter == shouldBePaneSplitter)
@@ -173,11 +239,22 @@ var CPSplitViewHorizontalImage = nil,
_needsResizeSubviews = YES;
}
/*!
Returns YES if the supplied subview is collapsed, otherwise NO.
@param aSubview - the subview you are interested in.
@return BOOL - YES if the subview is collapsed, otherwise NO.
*/
- (BOOL)isSubviewCollapsed:(CPView)subview
{
return [subview frame].size[_sizeComponent] < 1 ? YES : NO;
}
/*!
Returns the CGRect of the divider at a given index.
@param int - The index of a divider.
@return CGRect - The rect of a divider.
*/
- (CGRect)rectOfDividerAtIndex:(int)aDivider
{
var frame = [_subviews[aDivider] frame],
@@ -191,6 +268,12 @@ var CPSplitViewHorizontalImage = nil,
return rect;
}
/*!
Returns the rect of the divider which the user is able to drag to resize.
@param int - The index of the divider.
@return CGRect - The rect the user can drag.
*/
- (CGRect)effectiveRectOfDividerAtIndex:(int)aDivider
{
var realRect = [self rectOfDividerAtIndex:aDivider],
@@ -213,6 +296,35 @@ var CPSplitViewHorizontalImage = nil,
}
}
/*!
@ignore
Because we're use drawRect: to draw the dividers, but use DOM elements instead of CoreGraphics
We must remove those DOM elements (the splitters) when the subview is removed.
*/
- (void)willRemoveSubview:(CPView)aView
{
#if PLATFORM(DOM)
var dividerToRemove = _DOMDividerElements.pop();
// The divider may not exist if we never rendered out the DOM.
if (dividerToRemove)
CPDOMDisplayServerRemoveChild(_DOMElement, dividerToRemove);
#endif
_needsResizeSubviews = YES;
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
- (void)layoutSubviews
{
[self _adjustSubviewsWithCalculatedSize]
}
/*!
Draws the divider at a given rect.
@param aRect - the rect of the divider to draw.
*/
- (void)drawDividerInRect:(CGRect)aRect
{
#if PLATFORM(DOM)
@@ -236,13 +348,13 @@ var CPSplitViewHorizontalImage = nil,
{
if (_isPaneSplitter)
{
_DOMDividerElements[_drawingDivider].style.backgroundColor = [[self currentValueForThemeAttribute:@"pane-divider-color"] cssString];
_DOMDividerElements[_drawingDivider].style.backgroundImage = "";
_DOMDividerElements[_drawingDivider].style.backgroundColor = "";
_DOMDividerElements[_drawingDivider].style.backgroundImage = "url('"+_dividerImagePath+"')";
}
else
{
_DOMDividerElements[_drawingDivider].style.backgroundColor = "";
_DOMDividerElements[_drawingDivider].style.backgroundImage = "url('"+_dividerImagePath+"')";
_DOMDividerElements[_drawingDivider].style.backgroundColor = [[self currentValueForThemeAttribute:@"pane-divider-color"] cssString];
_DOMDividerElements[_drawingDivider].style.backgroundImage = "";
}
}
@@ -336,7 +448,6 @@ var CPSplitViewHorizontalImage = nil,
{
_currentDivider = CPNotFound;
[self _updateResizeCursor:anEvent];
[self _postNotificationDidResize];
}
return;
@@ -360,7 +471,8 @@ var CPSplitViewHorizontalImage = nil,
[_delegate respondsToSelector:@selector(splitView:shouldCollapseSubview:forDoubleClickOnDividerAtIndex:)])
{
var minPosition = [self minPossiblePositionOfDividerAtIndex:i],
maxPosition = [self maxPossiblePositionOfDividerAtIndex:i];
maxPosition = [self maxPossiblePositionOfDividerAtIndex:i],
_preCollapsePosition = [_preCollapsePositions objectForKey:"" + i] || 0;
if ([_delegate splitView:self canCollapseSubview:_subviews[i]] && [_delegate splitView:self shouldCollapseSubview:_subviews[i] forDoubleClickOnDividerAtIndex:i])
{
@@ -450,20 +562,34 @@ var CPSplitViewHorizontalImage = nil,
// If we are currently tracking, keep the resize cursor active even outside of hit areas.
if (_currentDivider === i || (_currentDivider == CPNotFound && [self cursorAtPoint:point hitDividerAtIndex:i]))
{
var frame = [_subviews[i] frame],
size = frame.size[_sizeComponent],
startPosition = frame.origin[_originComponent] + size,
var frameA = [_subviews[i] frame],
sizeA = frameA.size[_sizeComponent],
startPosition = frameA.origin[_originComponent] + sizeA,
frameB = [_subviews[i + 1] frame],
sizeB = frameB.size[_sizeComponent],
canShrink = [self _realPositionForPosition:startPosition - 1 ofDividerAtIndex:i] < startPosition,
canGrow = [self _realPositionForPosition:startPosition + 1 ofDividerAtIndex:i] > startPosition,
cursor = [CPCursor arrowCursor];
if (size === 0)
if (sizeA === 0)
canGrow = YES; // Subview is collapsed.
else if (!canShrink &&
[_delegate respondsToSelector:@selector(splitView:canCollapseSubview:)] &&
[_delegate splitView:self canCollapseSubview:_subviews[i]])
canShrink = YES; // Subview is collapsible.
if (sizeB === 0)
{
// Right/lower subview is collapsed.
canGrow = NO;
// It's safe to assume it can always be uncollapsed.
canShrink = YES;
}
else if (!canGrow &&
[_delegate respondsToSelector:@selector(splitView:canCollapseSubview:)] &&
[_delegate splitView:self canCollapseSubview:_subviews[i + 1]])
canGrow = YES; // Right/lower subview is collapsible.
if (_isVertical && canShrink && canGrow)
cursor = [CPCursor resizeLeftRightCursor];
else if (_isVertical && canShrink)
@@ -485,6 +611,11 @@ var CPSplitViewHorizontalImage = nil,
[[CPCursor arrowCursor] set];
}
/*!
Returns the maximum possible position of a divider at a given index.
@param the index of the divider.
@return float - the max possible position.
*/
- (float)maxPossiblePositionOfDividerAtIndex:(int)dividerIndex
{
var frame = [_subviews[dividerIndex + 1] frame];
@@ -495,6 +626,11 @@ var CPSplitViewHorizontalImage = nil,
return [self frame].size[_sizeComponent] - [self dividerThickness];
}
/*!
Returns the minimum possible position of a divider at a given index.
@param the index of the divider.
@return float - the min possible position.
*/
- (float)minPossiblePositionOfDividerAtIndex:(int)dividerIndex
{
if (dividerIndex > 0)
@@ -511,7 +647,15 @@ var CPSplitViewHorizontalImage = nil,
{
// not sure where this should override other positions?
if ([_delegate respondsToSelector:@selector(splitView:constrainSplitPosition:ofSubviewAt:)])
position = [_delegate splitView:self constrainSplitPosition:position ofSubviewAt:dividerIndex];
{
var proposedPosition = [_delegate splitView:self constrainSplitPosition:position ofSubviewAt:dividerIndex];
// Silently ignore bad positions which could result from odd delegate responses. We don't want these
// bad results to go into the system and cause havoc with frame sizes as the split view tries to resize
// its subviews.
if (_IS_NUMERIC(proposedPosition))
position = proposedPosition;
}
var proposedMax = [self maxPossiblePositionOfDividerAtIndex:dividerIndex],
proposedMin = [self minPossiblePositionOfDividerAtIndex:dividerIndex],
@@ -519,24 +663,45 @@ var CPSplitViewHorizontalImage = nil,
actualMin = proposedMin;
if ([_delegate respondsToSelector:@selector(splitView:constrainMinCoordinate:ofSubviewAt:)])
actualMin = [_delegate splitView:self constrainMinCoordinate:proposedMin ofSubviewAt:dividerIndex];
{
var proposedActualMin = [_delegate splitView:self constrainMinCoordinate:proposedMin ofSubviewAt:dividerIndex];
if (_IS_NUMERIC(proposedActualMin))
actualMin = proposedActualMin;
}
if ([_delegate respondsToSelector:@selector(splitView:constrainMaxCoordinate:ofSubviewAt:)])
actualMax = [_delegate splitView:self constrainMaxCoordinate:proposedMax ofSubviewAt:dividerIndex];
{
var proposedActualMax = [_delegate splitView:self constrainMaxCoordinate:proposedMax ofSubviewAt:dividerIndex];
if (_IS_NUMERIC(proposedActualMax))
actualMax = proposedActualMax;
}
var viewA = _subviews[dividerIndex],
viewB = _subviews[dividerIndex + 1],
realPosition = MAX(MIN(position, actualMax), actualMin);
if (position < proposedMin + (actualMin - proposedMin) / 2)
// Is this position past the halfway point to collapse?
if (position < proposedMin + (actualMin - proposedMin) / 2)
if ([_delegate respondsToSelector:@selector(splitView:canCollapseSubview:)])
if ([_delegate splitView:self canCollapseSubview:viewA])
realPosition = proposedMin;
// We can also collapse to the right.
if (position > proposedMax - (proposedMax - actualMax) / 2)
if ([_delegate respondsToSelector:@selector(splitView:canCollapseSubview:)])
if ([_delegate splitView:self canCollapseSubview:viewB])
realPosition = proposedMax;
return realPosition;
}
/*!
Sets the position of a divider at a given index.
@param position - The float value of the position to place the divider.
@param dividerIndex - The index of the divider to position.
*/
- (void)setPosition:(float)position ofDividerAtIndex:(int)dividerIndex
{
SPLIT_VIEW_SUPPRESS_RESIZE_NOTIFICATIONS(YES);
[self _adjustSubviewsWithCalculatedSize];
var realPosition = [self _realPositionForPosition:position ofDividerAtIndex:dividerIndex];
@@ -544,32 +709,59 @@ var CPSplitViewHorizontalImage = nil,
var viewA = _subviews[dividerIndex],
frameA = [viewA frame],
viewB = _subviews[dividerIndex + 1],
frameB = [viewB frame];
_preCollapsePosition = 0;
frameB = [viewB frame],
_preCollapsePosition = 0;
var preSize = frameA.size[_sizeComponent];
frameA.size[_sizeComponent] = realPosition - frameA.origin[_originComponent];
if (preSize !== 0 && frameA.size[_sizeComponent] === 0)
_preCollapsePosition = preSize;
[_subviews[dividerIndex] setFrame:frameA];
if (preSize !== frameA.size[_sizeComponent])
{
SPLIT_VIEW_MAYBE_POST_WILL_RESIZE();
[_subviews[dividerIndex] setFrame:frameA];
SPLIT_VIEW_MAYBE_POST_DID_RESIZE();
}
preSize = frameB.size[_sizeComponent];
var preOrigin = frameB.origin[_originComponent];
frameB.size[_sizeComponent] = frameB.origin[_originComponent] + frameB.size[_sizeComponent] - realPosition - [self dividerThickness];
if (preSize !== 0 && frameB.size[_sizeComponent] === 0)
_preCollapsePosition = preSize;
_preCollapsePosition = frameB.origin[_originComponent];
frameB.origin[_originComponent] = realPosition + [self dividerThickness];
[_subviews[dividerIndex + 1] setFrame:frameB];
if (preSize !== frameB.size[_sizeComponent] || preOrigin !== frameB.origin[_originComponent])
{
SPLIT_VIEW_MAYBE_POST_WILL_RESIZE();
[_subviews[dividerIndex + 1] setFrame:frameB];
SPLIT_VIEW_MAYBE_POST_DID_RESIZE();
}
if (_preCollapsePosition)
[_preCollapsePositions setObject:_preCollapsePosition forKey:"" + dividerIndex];
[self setNeedsDisplay:YES];
if (SPLIT_VIEW_DID_SUPPRESS_RESIZE_NOTIFICATION())
[self _postNotificationDidResize];
SPLIT_VIEW_SUPPRESS_RESIZE_NOTIFICATIONS(NO);
}
- (void)setFrameSize:(CGSize)aSize
{
[self _adjustSubviewsWithCalculatedSize];
if (_needsRestoreFromAutosave)
_shouldAutosave = NO;
else
[self _adjustSubviewsWithCalculatedSize];
[super setFrameSize:aSize];
if (_needsRestoreFromAutosave)
{
_needsRestoreFromAutosave = NO;
[self _restoreFromAutosave];
_shouldAutosave = YES;
}
[self setNeedsDisplay:YES];
}
@@ -581,6 +773,7 @@ var CPSplitViewHorizontalImage = nil,
return;
}
SPLIT_VIEW_MAYBE_POST_WILL_RESIZE();
[self _postNotificationWillResize];
var index = 0,
@@ -639,11 +832,72 @@ var CPSplitViewHorizontalImage = nil,
bounds.origin[_originComponent] += viewFrame.size[_sizeComponent] + dividerThickness;
[view setFrame:viewFrame];
}
[self _postNotificationDidResize];
SPLIT_VIEW_MAYBE_POST_DID_RESIZE();
}
/*!
Sets the delegate of the receiver.
Possible delegate methods to implement are listed below.
Notifies the delegate when the subviews have resized.
@code
- (void)splitViewDidResizeSubviews:(CPNotification)aNotification;
@endcode
Notifies the delegate when the subviews will be resized.
@code
- (void)splitViewWillResizeSubviews:(CPNotification)aNotification;
@endcode
Lets the delegate specify a different rect for which the user can drag the splitView divider.
@code
- (CGRect)splitView:(CPSplitView)aSplitView effectiveRect:(CGRect)aRect forDrawnRect:(CGRect)aDrawnRect ofDividerAtIndex:(int)aDividerIndex;
@endcode
Lets the delegate specify an additional rect for which the user can drag the splitview divider.
@code
- (CGRect)splitView:(CPSplitView)aSplitView additionalEffectiveRectOfDividerAtIndex:(int)indexOfDivider;
@endcode
Notifies the delegate that the splitview is about to be collapsed. This usually happens when the user
Double clicks on the divider. Return YES if the subview can be collapsed, otherwise NO.
@code
- (BOOL)splitView:(CPSplitView)aSplitView canCollapseSubview:(CPView)aSubview;
@endcode
Notifies the delegate that the subview at indexOfDivider is about to be collapsed. This usually happens when the user
Double clicks on the divider. Return YES if the subview should be collapsed, otherwise NO.
@code
- (BOOL)splitView:(CPSplitView)aSplitView shouldCollapseSubview:(CPView)aSubview forDoubleClickOnDividerAtIndex:(int)indexOfDivider;
@endcode
Allows the delegate to constrain the subview beings resized. This method is called continuously as the user resizes the divider.
For example if the subview needs to have a width which is a multiple of a certain number you could return that multiple with this method.
@code
- (float)splitView:(CPSplitView)aSpiltView constrainSplitPosition:(float)proposedPosition ofSubviewAt:(int)subviewIndex;
@endcode
Allows the delegate to constrain the minimum position of a subview.
@code
- (float)splitView:(CPSplitView)aSplitView constrainMinCoordinate:(float)proposedMin ofSubviewAt:(int)subviewIndex;
@endcode
Allows the delegate to constrain the maximum position of a subview.
@code
- (float)splitView:(CPSplitView)aSplitView constrainMaxCoordinate:(float)proposedMax ofSubviewAt:(int)subviewIndex;
@endcode
Allows the splitview to specify a custom resizing behavior. This is called when the splitview is resized.
The sum of the views and the sum of the dividers should be equal to the size of the splitview.
@code
- (void)splitView:(CPSplitView)aSplitView resizeSubviewsWithOldSize:(CGSize)oldSize;
@endcode
@param delegate - The delegate of the splitview.
*/
- (void)setDelegate:(id)delegate
{
if ([_delegate respondsToSelector:@selector(splitViewDidResizeSubviews:)])
@@ -676,7 +930,11 @@ var CPSplitViewHorizontalImage = nil,
This method will automatically configure the hasResizeControl and resizeControlIsLeftAligned
parameters of the button bar, and will override any currently set values.
@param CPButtonBar - The supplied button bar.
@param unsigned int - The divider index the button bar will be assigned to.
*/
// FIXME Should be renamed to setButtonBar:ofDividerAtIndex:.
- (void)setButtonBar:(CPButtonBar)aButtonBar forDividerAtIndex:(unsigned)dividerIndex
{
if (!aButtonBar)
@@ -713,15 +971,121 @@ var CPSplitViewHorizontalImage = nil,
- (void)_postNotificationDidResize
{
[self _autosave];
[[CPNotificationCenter defaultCenter] postNotificationName:CPSplitViewDidResizeSubviewsNotification object:self];
}
/*!
Set the name under which the split view divider positions is automatically saved to CPUserDefaults.
@param autosaveName the name to save under or nil to not save
*/
- (void)setAutosaveName:(CPString)autosaveName
{
if (_autosaveName == autosaveName)
return;
_autosaveName = autosaveName;
}
/*!
Get the name under which the split view divider position is automatically saved to CPUserDefaults.
@return the name to save under or nil if no auto save is active
*/
- (CPString)autosaveName
{
return _autosaveName;
}
/*!
@ignore
*/
- (void)_autosave
{
if (!_shouldAutosave)
return;
var userDefaults = [CPUserDefaults standardUserDefaults],
autosaveName = [self _framesKeyForAutosaveName:[self autosaveName]],
autosavePrecollapseName = [self _precollapseKeyForAutosaveName:[self autosaveName]],
count = [_subviews count],
positions = [CPMutableArray new],
preCollapseArray = [CPMutableArray new];
for (var i = 0; i < count; i++)
{
var frame = [_subviews[i] frame];
[positions addObject:CPStringFromRect(frame)];
[preCollapseArray addObject:[_preCollapsePositions objectForKey:"" + i]];
}
[userDefaults setObject:positions forKey:autosaveName];
[userDefaults setObject:preCollapseArray forKey:autosavePrecollapseName];
}
/*!
@ignore
*/
- (void)_restoreFromAutosave
{
if (!_autosaveName)
return;
var autosaveName = [self _framesKeyForAutosaveName:[self autosaveName]],
autosavePrecollapseName = [self _precollapseKeyForAutosaveName:[self autosaveName]],
userDefaults = [CPUserDefaults standardUserDefaults],
frames = [userDefaults objectForKey:autosaveName],
preCollapseArray = [userDefaults objectForKey:autosavePrecollapseName];
if (frames)
{
var dividerThickness = [self dividerThickness],
position = 0;
_shouldAutosave = NO;
for (var i = 0, count = [frames count] - 1; i < count; i++)
{
var frame = CPRectFromString(frames[i]);
position += frame.size[_sizeComponent];
[self setPosition:position ofDividerAtIndex:i];
position += dividerThickness;
}
_shouldAutosave = YES;
}
if (preCollapseArray)
{
_preCollapsePositions = [CPMutableDictionary new];
for (var i = 0, count = [preCollapseArray count]; i < count; i++)
[_preCollapsePositions setObject:preCollapseArray[i] forKey:i + ""];
}
}
/*!
@ignore
*/
- (CPString)_framesKeyForAutosaveName:(CPString)theAutosaveName
{
return @"CPSplitView Subview Frames " + theAutosaveName;
}
/*!
@ignore
*/
- (CPString)_precollapseKeyForAutosaveName:(CPString)theAutosaveName
{
return @"CPSplitView Subview Precollapse Positions " + theAutosaveName;
}
@end
var CPSplitViewDelegateKey = "CPSplitViewDelegateKey",
CPSplitViewIsVerticalKey = "CPSplitViewIsVerticalKey",
CPSplitViewIsPaneSplitterKey = "CPSplitViewIsPaneSplitterKey",
CPSplitViewButtonBarsKey = "CPSplitViewButtonBarsKey";
CPSplitViewButtonBarsKey = "CPSplitViewButtonBarsKey",
CPSplitViewAutosaveNameKey = "CPSplitViewAutosaveNameKey";
@implementation CPSplitView (CPCoding)
@@ -735,16 +1099,27 @@ var CPSplitViewDelegateKey = "CPSplitViewDelegateKey",
if (self)
{
_suppressResizeNotificationsMask = 0;
_preCollapsePositions = [CPMutableDictionary new];
_currentDivider = CPNotFound;
_shouldAutosave = YES;
_DOMDividerElements = [];
_buttonBars = [aCoder decodeObjectForKey:CPSplitViewButtonBarsKey] || [];
_delegate = [aCoder decodeObjectForKey:CPSplitViewDelegateKey];
[self setDelegate:[aCoder decodeObjectForKey:CPSplitViewDelegateKey]];
_isPaneSplitter = [aCoder decodeBoolForKey:CPSplitViewIsPaneSplitterKey];
[self _setVertical:[aCoder decodeBoolForKey:CPSplitViewIsVerticalKey]];
[self setAutosaveName:[aCoder decodeObjectForKey:CPSplitViewAutosaveNameKey]];
// We have to wait until we know our frame size before restoring, or the frame resize later will throw
// away the restored size.
if (_autosaveName)
_needsRestoreFromAutosave = YES;
}
return self;
@@ -765,6 +1140,8 @@ var CPSplitViewDelegateKey = "CPSplitViewDelegateKey",
[aCoder encodeBool:_isVertical forKey:CPSplitViewIsVerticalKey];
[aCoder encodeBool:_isPaneSplitter forKey:CPSplitViewIsPaneSplitterKey];
[aCoder encodeObject:_autosaveName forKey:CPSplitViewAutosaveNameKey];
}
@end
+47 -126
View File
@@ -25,11 +25,11 @@
@import <AppKit/CPTextField.j>
var CPStepperButtonsSize = CPSizeMake(19, 13);
/*! CPStepper is an implementation of Cocoa NSStepper.
/*!
CPStepper is an implementation of Cocoa NSStepper.
This control display a two part button that can be used to increase or decrease a value with a given interval.
This control displays a two part button that can be used to increase or decrease a value with a given interval.
*/
@implementation CPStepper: CPControl
{
@@ -38,14 +38,15 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
int _maxValue @accessors(property=maxValue);
int _minValue @accessors(property=minValue);
_CPContinuousButton _buttonDown;
_CPContinuousButton _buttonUp;
CPButton _buttonDown;
CPButton _buttonUp;
}
#pragma mark -
#pragma mark Initialization
/*! Initializes a CPStepper with given values
/*!
Initializes a CPStepper with given values.
@param aValue the initial value of the CPStepper
@param minValue the minimal acceptable value of the stepper
@param maxValue the maximal acceptable value of the stepper
@@ -53,7 +54,7 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
*/
+ (CPStepper)stepperWithInitialValue:(float)aValue minValue:(float)aMinValue maxValue:(float)aMaxValue
{
var stepper = [[CPStepper alloc] initWithFrame:CPRectMake(0, 0, 19, 25)];
var stepper = [[CPStepper alloc] initWithFrame:_CGRectMake(0, 0, 19, 25)];
[stepper setDoubleValue:aValue];
[stepper setMinValue:aMinValue];
[stepper setMaxValue:aMaxValue];
@@ -61,10 +62,12 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
return stepper;
}
/*! Initializes a CPStepper with default values:
/*!
Initializes a CPStepper with default values:
- minValue = 0.0
- maxValue = 59.0
- value = 0.0
@return Initialized CPStepper
*/
+ (CPStepper)stepper
@@ -72,7 +75,8 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
return [CPStepper stepperWithInitialValue:0.0 minValue:0.0 maxValue:59.0];
}
/*! Initializes the CPStepper
/*!
Initializes a CPStepper.
@param aFrame the frame of the control
@return initialized CPStepper
*/
@@ -87,14 +91,14 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
[self setDoubleValue:0.0];
_buttonUp = [[_CPContinuousButton alloc] initWithFrame:CPRectMake(aFrame.size.width - CPStepperButtonsSize.width, 0, CPStepperButtonsSize.width, CPStepperButtonsSize.height)];
_buttonUp = [[CPButton alloc] initWithFrame:_CGRectMakeZero()];
[_buttonUp setContinuous:YES];
[_buttonUp setTarget:self];
[_buttonUp setAction:@selector(_buttonDidClick:)];
[_buttonUp setAutoresizingMask:CPViewNotSizable];
[self addSubview:_buttonUp];
_buttonDown = [[_CPContinuousButton alloc] initWithFrame:CPRectMake(aFrame.size.width - CPStepperButtonsSize.width, CPStepperButtonsSize.height, CPStepperButtonsSize.width, CPStepperButtonsSize.height - 1)];
_buttonDown = [[CPButton alloc] initWithFrame:_CGRectMakeZero()];
[_buttonDown setContinuous:YES];
[_buttonDown setTarget:self];
[_buttonDown setAction:@selector(_buttonDidClick:)];
@@ -110,7 +114,8 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
#pragma mark -
#pragma mark Superclass overrides
/*! set if the CPStepper is enabled or not
/*!
Set if the CPStepper is enabled or not.
@param shouldEnabled BOOL that define if stepper is enabled or not.
*/
- (void)setEnabled:(BOOL)shouldEnabled
@@ -121,19 +126,30 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
[_buttonDown setEnabled:shouldEnabled];
}
/*! set the frame of the CPStepper and check if width is not smaller than theme min-size
@param aFrame the frame
*/
- (void)setFrame:(CGRect)aFrame
{
if (aFrame.size.width >= CGRectGetWidth(aFrame))
[super setFrame:aFrame];
var upSize = [self valueForThemeAttribute:@"up-button-size"],
downSize = [self valueForThemeAttribute:@"down-button-size"],
minSize = _CGSizeMake(upSize.width, upSize.height + downSize.height),
frame = _CGRectMakeCopy(aFrame);
frame.size.width = Math.max(minSize.width, frame.size.width);
frame.size.height = Math.max(minSize.height, frame.size.height);
[super setFrame:frame];
}
/*! @ignore
*/
/*! @ignore */
- (void)layoutSubviews
{
var aFrame = [self frame],
upSize = [self valueForThemeAttribute:@"up-button-size"],
downSize = [self valueForThemeAttribute:@"down-button-size"],
upFrame = _CGRectMake(aFrame.size.width - upSize.width, 0, upSize.width, upSize.height),
downFrame = _CGRectMake(aFrame.size.width - downSize.width, upSize.height, downSize.width, downSize.height);
[_buttonUp setFrame:upFrame];
[_buttonDown setFrame:downFrame];
[_buttonUp setValue:[self valueForThemeAttribute:@"bezel-color-up-button" inState:CPThemeStateBordered] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered];
[_buttonUp setValue:[self valueForThemeAttribute:@"bezel-color-up-button" inState:CPThemeStateBordered | CPThemeStateDisabled] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateDisabled];
[_buttonUp setValue:[self valueForThemeAttribute:@"bezel-color-up-button" inState:CPThemeStateBordered | CPThemeStateHighlighted] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateHighlighted];
@@ -142,7 +158,8 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
[_buttonDown setValue:[self valueForThemeAttribute:@"bezel-color-down-button" inState:CPThemeStateBordered | CPThemeStateHighlighted] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateHighlighted];
}
/*! set if CPStepper should autorepeat
/*!
Set if CPStepper should autorepeat.
@param shouldAutoRepeat if YES, the first mouse down does one increment (decrement) and, after each delay of 0.5 seconds
*/
- (void)setAutorepeat:(BOOL)shouldAutoRepeat
@@ -151,8 +168,9 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
[_buttonDown setContinuous:shouldAutoRepeat];
}
/*! set the current value of the stepper
@param aValue a float contaning the value
/*!
Set the current value of the stepper.
@param aValue a float containing the value
*/
- (void)setDoubleValue:(float)aValue
{
@@ -167,8 +185,7 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
#pragma mark -
#pragma mark Actions
/*! @ignore
*/
/*! @ignore */
- (IBAction)_buttonDidClick:(id)aSender
{
if (![self isEnabled])
@@ -183,7 +200,8 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
[self sendAction:_action to:_target];
}
/*! @perform a programatic click on up button
/*!
Perform a programatic click on up button.
@param aSender sender of the action
*/
- (IBAction)performClickUp:(id)aSender
@@ -191,7 +209,8 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
[_buttonUp performClick:aSender];
}
/*! @perform a programatic click on down button
/*!
Perform a programatic click on down button.
@param aSender sender of the action
*/
- (IBAction)performClickDown:(id)aSender
@@ -210,8 +229,8 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[[CPNull null], [CPNull null]]
forKeys:[@"bezel-color-up-button", @"bezel-color-down-button"]];
return [CPDictionary dictionaryWithObjects:[[CPNull null], [CPNull null], _CGSizeMakeZero(), _CGSizeMakeZero()]
forKeys:[@"bezel-color-up-button", @"bezel-color-down-button", @"up-button-size", @"down-button-size"]];
}
@end
@@ -244,101 +263,3 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
}
@end
/*! This is a subclass of CPButton that allows to send continuous action.
This may should be include in CPButton..
*/
@implementation _CPContinuousButton : CPButton
{
CPTimer _continuousDelayTimer;
CPTimer _continuousTimer;
float _periodicDelay;
float _periodicInterval;
}
- (void)initWithFrame:(CGRect)aFrame
{
if (self = [super initWithFrame:aFrame])
{
_periodicInterval = 0.05;
_periodicDelay = 0.5;
}
return self;
}
- (void)setPeriodicDelay:(float)aDelay interval:(float)anInterval
{
_periodicDelay = aDelay;
_periodicInterval = anInterval;
}
- (void)mouseDown:(CPEvent)anEvent
{
if ([self isContinuous])
{
_continuousDelayTimer = [CPTimer scheduledTimerWithTimeInterval:_periodicDelay callback: function()
{
if (!_continuousTimer)
_continuousTimer = [CPTimer scheduledTimerWithTimeInterval:_periodicInterval target:self selector:@selector(onContinousEvent:) userInfo:anEvent repeats:YES];
}
repeats:NO];
}
[super mouseDown:anEvent];
}
- (void)onContinousEvent:(CPTimer)aTimer
{
if (_target && _action && [_target respondsToSelector:_action])
[_target performSelector:_action withObject:self];
}
- (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp
{
[self invalidateTimers];
[super stopTracking:lastPoint at:aPoint mouseIsUp:mouseIsUp];
}
- (void)invalidateTimers
{
if (_continuousTimer)
{
[_continuousTimer invalidate];
_continuousTimer = nil;
}
if (_continuousDelayTimer)
{
[_continuousDelayTimer invalidate];
_continuousDelayTimer = nil;
}
}
@end
@implementation _CPContinuousButton (CPCodingCompliance)
- (id)initWithCoder:(CPCoder)aCoder
{
if (self = [super initWithCoder:aCoder])
{
_periodicDelay = [aCoder decodeObjectForKey:@"_periodicDelay"];
_periodicInterval = [aCoder decodeObjectForKey:@"_periodicInterval"];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[self invalidateTimers];
[aCoder encodeObject:_periodicDelay forKey:@"_periodicDelay"];
[aCoder encodeObject:_periodicInterval forKey:@"_periodicInterval"];
}
@end
+47 -2
View File
@@ -16,6 +16,14 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
CPTabViewWillSelectTabViewItemSelector = 4,
CPTabViewDidChangeNumberOfTabViewItemsSelector = 8;
/*!
@ingroup appkit
@class CPTabView
A CPTabView object presents a tabbed interface where each page is one a
complete view hiearchy of its own. The user can navigate between various
pages by clicking on the tab headers.
*/
@implementation CPTabView : CPView
{
CPArray _items;
@@ -26,6 +34,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
CPNumber _selectedIndex;
CPTabViewType _type;
CPFont _font;
id _delegate;
unsigned _delegateSelectors;
@@ -74,8 +83,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
}
/*!
Inserts a CPTabViewItem into the tab view
at the specified index.
Inserts a CPTabViewItem into the tab view at the specified index.
@param aTabViewItem the item to insert
@param anIndex the index for the item
*/
@@ -121,6 +129,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
/*!
Returns the index of the specified item
@param aTabViewItem the item to find the index for
@return the index of aTabViewItem or CPNotFound
*/
- (int)indexOfTabViewItem:(CPTabViewItem)aTabViewItem
{
@@ -130,6 +139,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
/*!
Returns the index of the CPTabViewItem with the specified identifier.
@param anIdentifier the identifier of the item
@return the index of the tab view item identified by anIdentifier, or CPNotFound
*/
- (int)indexOfTabViewItemWithIdentifier:(CPString)anIdentifier
{
@@ -142,6 +152,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
/*!
Returns the number of items in the tab view.
@return the number of tab view items in the receiver
*/
- (unsigned)numberOfTabViewItems
{
@@ -150,6 +161,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
/*!
Returns the CPTabViewItem at the specified index.
@return a tab view item, or nil
*/
- (CPTabViewItem)tabViewItemAtIndex:(unsigned)anIndex
{
@@ -158,6 +170,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
/*!
Returns the array of items that backs this tab view.
@return a copy of the array of items in the receiver
*/
- (CPArray)tabViewItems
{
@@ -261,12 +274,36 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
/*!
Returns the current item being displayed.
@return the tab view item currenly being displayed by the receiver
*/
- (CPTabViewItem)selectedTabViewItem
{
return [_items objectAtIndex:_selectedIndex];
}
// Modifying the font
/*!
Returns the font for tab label text.
@return the font for tab label text
*/
- (CPFont)font
{
return _font;
}
/*!
Sets the font for tab label text to font.
@param font the font the receiver should use for tab label text
*/
- (void)setFont:(CPFont)font
{
if ([_font isEqual:font])
return;
_font = font;
[_tabs setFont:_font];
}
//
/*!
Sets the tab view type.
@@ -314,6 +351,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
/*!
Returns the tab view type.
@return the tab view type of the receiver
*/
- (CPTabViewType)tabViewType
{
@@ -322,6 +360,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
/*!
Returns the receiver's delegate.
@return the receiver's delegate
*/
- (id)delegate
{
@@ -415,6 +454,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
var CPTabViewItemsKey = "CPTabViewItemsKey",
CPTabViewSelectedItemKey = "CPTabViewSelectedItemKey",
CPTabViewTypeKey = "CPTabViewTypeKey",
CPTabViewFontKey = "CPTabViewFontKey",
CPTabViewDelegateKey = "CPTabViewDelegateKey";
@implementation CPTabView (CPCoding)
@@ -425,12 +465,16 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
{
[self _init];
_font = [aCoder decodeObjectForKey:CPTabViewFontKey];
[_tabs setFont:_font];
_items = [aCoder decodeObjectForKey:CPTabViewItemsKey];
[self _updateItems];
[self _repositionTabs];
var selected = [aCoder decodeObjectForKey:CPTabViewSelectedItemKey];
if (selected)
[self selectTabViewItem:selected];
@@ -450,6 +494,7 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
[aCoder encodeObject:[self selectedTabViewItem] forKey:CPTabViewSelectedItemKey];
[aCoder encodeInt:_type forKey:CPTabViewTypeKey];
[aCoder encodeObject:_font forKey:CPTabViewFontKey];
[aCoder encodeConditionalObject:_delegate forKey:CPTabViewDelegateKey];
}
+3 -3
View File
@@ -145,8 +145,8 @@ CPPressedTab = 2;
// Assigning an Auxiliary View
/*!
Sets the tab's auxillary view.
@param anAuxillaryView the new auxillary view
Sets the tab's auxiliary view.
@param anAuxiliaryView the new auxiliary view
*/
- (void)setAuxiliaryView:(CPView)anAuxiliaryView
{
@@ -154,7 +154,7 @@ CPPressedTab = 2;
}
/*!
Returns the tab's auxillary view
Returns the tab's auxiliary view
*/
- (CPView)auxiliaryView
{
+157 -42
View File
@@ -37,9 +37,12 @@ CPTableColumnUserResizingMask = 1 << 1;
@class CPTableColumn
A CPTableColumn contains a dataview to display for its column of the CPTableView.
A CPTableColumn determines its own size constrains and resizing behaviour.
A CPTableColumn determines its own size constrains and resizing behavior.
The default dataview is a CPTextField but you can set it to any view you'd like. See -setDataView: for documentaion including theme states.
The default dataview is a CPTextField but you can set it to any view you'd like. See -setDataView: for documentation including theme states.
To customize the text of the column header you can simply call setStringValue: on the headerview of a table column.
For example: [[myTableColumn headerView] setStringValue:"My Title"];
*/
@implementation CPTableColumn : CPObject
{
@@ -62,11 +65,6 @@ CPTableColumnUserResizingMask = 1 << 1;
BOOL _disableResizingPosting @accessors(property=disableResizingPosting);
}
+ (Class)_binderClassForBinding:(CPString)theBinding
{
return [CPBinder class];
}
/*!
@ignore
*/
@@ -134,7 +132,7 @@ CPTableColumnUserResizingMask = 1 << 1;
{
var min = [self minWidth],
max = [self maxWidth],
newWidth = MIN(MAX(width, min), max);
newWidth = ROUND(MIN(MAX(width, min), max));
[self setWidth:newWidth];
@@ -197,7 +195,7 @@ CPTableColumnUserResizingMask = 1 << 1;
}
/*!
Sets the minimum width of the column.
Sets the minimum width of the column.
Default value is 10.
*/
- (void)setMinWidth:(float)aMinWidth
@@ -225,7 +223,7 @@ CPTableColumnUserResizingMask = 1 << 1;
}
/*!
Sets the maximum width of the table column.
Sets the maximum width of the table column.
Default value is: 1000000
*/
- (void)setMaxWidth:(float)aMaxWidth
@@ -254,8 +252,8 @@ CPTableColumnUserResizingMask = 1 << 1;
/*!
<pre>
Set the resizing mask of the column.
By default the column can be resized automatically with the tableview and manaully by the user
Set the resizing mask of the column.
By default the column can be resized automatically with the tableview and manually by the user
Possible masking values are:
CPTableColumnNoResizing
@@ -278,7 +276,7 @@ CPTableColumnUserResizingMask = 1 << 1;
}
/*!
Sizes the column to fix the column header text.
Sizes the column to fix the column header text.
*/
- (void)sizeToFit
{
@@ -296,7 +294,12 @@ CPTableColumnUserResizingMask = 1 << 1;
/*!
Sets the header view for the column.
The headerview handles the display of sort indicators, text, etc
The headerview handles the display of sort indicators, text, etc.
If you do not want a headerview for you table you should call setHeaderView: on your CPTableView instance.
Passing nil here will throw an exception.
In order to customize the text of the column header see - (CPView)headerView;
*/
- (void)setHeaderView:(CPView)aView
{
@@ -312,7 +315,10 @@ CPTableColumnUserResizingMask = 1 << 1;
}
/*!
Returns the headerview for the column
Returns the headerview for the column.
In order to change the text of the headerview for a column you should call setStringValue: on the headerview.
For example: [[myTableColumn headerView] setStringValue:"My Column"];
*/
- (CPView)headerView
{
@@ -320,39 +326,38 @@ CPTableColumnUserResizingMask = 1 << 1;
}
/*!
<pre>
This method sets the "prototype" view which will be used to create all table cells in this column.
It creates a snapshot of aView, using keyed archiving, which is then copied over and over for each
individual cell that is shown. As a result, changes made after calling this method won't be reflected.
When you set a dataview and it is added to the tableview the theme state will be set to CPThemeStateTableDataView
When the dataview becomes selected the theme state will be set to CPThemeStateSelectedDataView.
If the dataview shows up in a group row of the tablview the theme state will be set to CPThemeStateGroupRow.
You should overide setThemeState: and unsetThemeState: to handle these theme state changes in your dataview.
Example:
@code
[tableColumn setDataView:someView]; // snapshot taken
[[tableColumn dataView] setSomething:x]; //won't work
@endcode
This doesn't work because the snapshot is taken before the new property is applied. Instead, do:
@code
[someView setSomething:x];
[tableColumn setDataView:someView];
@endcode
REMEMBER: you should implement CPKeyedArchiving otherwise you might see unexpected results.
@note you should implement CPKeyedArchiving otherwise you might see unexpected results.
This is done by adding the following methods to your class:
@endnote
@code
- (id)initWithCoder(CPCoder)aCoder;
- (void)encodeWithCoder:(CPCoder)aCoder;
@endcode
Example:
Say you have two instance variables in your object that need to be set up each time an object is create.
We will call these instance variables "image" and "text".
Your CPCoding methods will look like the following:
@code
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
@@ -373,7 +378,16 @@ CPTableColumnUserResizingMask = 1 << 1;
[aCoder encodeObject:image forKey:"MyDataViewImage"];
[aCoder encodeObject:text forKey:"MyDataViewText"];
}
</pre>
@endcode
@section Themeing
When you set a dataview and it is added to the tableview the theme state will be set to \c CPThemeStateTableDataView
When the dataview becomes selected the theme state will be set to \c CPThemeStateSelectedDataView.
If the dataview shows up in a group row of the tableview the theme state will be set to \c CPThemeStateGroupRow.
You should overide \c setThemeState: and \c unsetThemeState: to handle these theme state changes in your dataview.
*/
- (void)setDataView:(CPView)aView
{
@@ -414,7 +428,7 @@ CPTableColumnUserResizingMask = 1 << 1;
var x = [self tableView]._cachedDataViews[dataViewUID];
if (x && x.length)
return x.pop();
return x.pop();
// if we haven't cached an archive of the data view, do it now
if (!_dataViewData[dataViewUID])
@@ -460,7 +474,7 @@ CPTableColumnUserResizingMask = 1 << 1;
/*!
Returns YES if the user can edit cells associated with the receiver by double-clicking the
column in the NSTableView, NO otherwise.
column in the CPTableView, NO otherwise.
*/
- (BOOL)isEditable
{
@@ -468,7 +482,7 @@ CPTableColumnUserResizingMask = 1 << 1;
}
/*!
Sets the sort descriptor prototype for the column.
Sets the sort descriptor prototype for the column.
*/
- (void)setSortDescriptorPrototype:(CPSortDescriptor)aSortDescriptor
{
@@ -484,7 +498,7 @@ CPTableColumnUserResizingMask = 1 << 1;
}
/*!
If NO the tablecolumn will no longer be visisble in the tableview
If NO the tablecolumn will no longer be visible in the tableview
If YES the tablecolumn will be visible in the tableview.
*/
- (void)setHidden:(BOOL)shouldBeHidden
@@ -541,16 +555,67 @@ CPTableColumnUserResizingMask = 1 << 1;
@end
@implementation CPTableColumnValueBinder : CPBinder
{
}
- (void)setValueFor:(CPString)aBinding
{
var tableView = [_source tableView],
column = [[tableView tableColumns] indexOfObjectIdenticalTo:_source],
rowIndexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [tableView numberOfRows])],
columnIndexes = [CPIndexSet indexSetWithIndex:column];
[tableView reloadDataForRowIndexes:rowIndexes columnIndexes:columnIndexes];
}
@end
@implementation CPTableColumn (Bindings)
+ (id)_binderClassForBinding:(CPString)aBinding
{
if (aBinding == CPValueBinding)
return [CPTableColumnValueBinder class];
return [super _binderClassForBinding:aBinding];
}
/*!
Binds the receiver to an object.
@param CPString aBinding - The binding you wish to make. Typically CPValueBinding.
@param id anObject - The object to bind the receiver to.
@param CPString aKeyPath - The key path you wish to bind the receiver to.
@param CPDictionary options - A dictionary of options for the binding. This parameter is optional, pass nil if you do not wish to use it.
*/
- (void)bind:(CPString)aBinding toObject:(id)anObject withKeyPath:(CPString)aKeyPath options:(CPDictionary)options
{
[super bind:aBinding toObject:anObject withKeyPath:aKeyPath options:options];
if (![aBinding isEqual:@"someListOfExceptedBindings(notAcceptedBindings)"])
[[self tableView] _establishBindingsIfUnbound:anObject];
{
// Bind the table to the array controller this column is bound to.
// Note that anObject might not be the array controller. E.g. the keypath could be something like
// somePathTo.anArrayController.arrangedObjects.aKey. Cocoa doesn't support this but it is consistent
// and it makes sense.
var acIndex = aKeyPath.lastIndexOf("arrangedObjects."),
arrayController = anObject;
if (acIndex > 1)
{
var firstPart = aKeyPath.substring(0, acIndex - 1);
arrayController = [anObject valueForKeyPath:firstPart];
}
[[self tableView] _establishBindingsIfUnbound:arrayController];
}
}
- (void)prepareDataView:(CPView)aDataView forRow:(unsigned)aRow
/*!
@ignore
*/
- (void)_prepareDataView:(CPView)aDataView forRow:(unsigned)aRow
{
var bindingsDictionary = [CPBinder allBindingsForObject:self],
keys = [bindingsDictionary allKeys];
@@ -596,16 +661,46 @@ CPTableColumnUserResizingMask = 1 << 1;
}
}
/*!
@ignore
*/
- (void)_reverseSetDataView:(CPView)aDataView forRow:(unsigned)aRow
{
var bindingsDictionary = [CPBinder allBindingsForObject:self],
keys = [bindingsDictionary allKeys],
newValue = [aDataView valueForKey:@"objectValue"];
for (var i = 0, count = [keys count]; i < count; i++)
{
var bindingName = keys[i],
bindingPath = [aDataView _replacementKeyPathForBinding:bindingName],
binding = [bindingsDictionary objectForKey:bindingName],
bindingInfo = binding._info,
destination = [bindingInfo objectForKey:CPObservedObjectKey],
keyPath = [bindingInfo objectForKey:CPObservedKeyPathKey],
dotIndex = keyPath.lastIndexOf(".");
if (dotIndex === CPNotFound)
[[destination valueForKeyPath:keyPath] replaceObjectAtIndex:aRow withObject:newValue];
else
{
var firstPart = keyPath.substring(0, dotIndex),
secondPart = keyPath.substring(dotIndex + 1),
firstValue = [destination valueForKeyPath:firstPart];
if ([firstValue isKindOfClass:CPArray])
[[firstValue objectAtIndex:aRow] setValue:newValue forKeyPath:secondPart];
else
[[firstValue valueForKeyPath:secondPart] replaceObjectAtIndex:aRow withObject:newValue];
}
}
}
//- (void)objectValue
//{
// return nil;
//}
- (void)setValue:(CPArray)content
{
[[self tableView] reloadData];
}
@end
var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
@@ -621,6 +716,9 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
@implementation CPTableColumn (CPCoding)
/*!
@ignore
*/
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
@@ -648,13 +746,16 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
return self;
}
/*!
@ignore
*/
- (void)encodeWithCoder:(CPCoder)aCoder
{
[aCoder encodeObject:_identifier forKey:CPTableColumnIdentifierKey];
[aCoder encodeObject:_width forKey:CPTableColumnWidthKey];
[aCoder encodeObject:_minWidth forKey:CPTableColumnMinWidthKey];
[aCoder encodeObject:_maxWidth forKey:CPTableColumnMaxWidthKey];
[aCoder encodeFloat:_width forKey:CPTableColumnWidthKey];
[aCoder encodeFloat:_minWidth forKey:CPTableColumnMinWidthKey];
[aCoder encodeFloat:_maxWidth forKey:CPTableColumnMaxWidthKey];
[aCoder encodeObject:_headerView forKey:CPTableColumnHeaderViewKey];
[aCoder encodeObject:_dataView forKey:CPTableColumnDataViewKey];
@@ -669,31 +770,45 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
@end
@implementation CPTableColumn (NSInCompatibility)
/*!
@ignore
*/
- (void)setHeaderCell:(CPView)aView
{
[CPException raise:CPUnsupportedMethodException
reason:@"setHeaderCell: is not supported. Use -setHeaderView:aView instead."];
}
/*!
@ignore
*/
- (CPView)headerCell
{
[CPException raise:CPUnsupportedMethodException
reason:@"headCell is not supported. Use -headerView instead."];
}
/*!
@ignore
*/
- (void)setDataCell:(CPView)aView
{
[CPException raise:CPUnsupportedMethodException
reason:@"setDataCell: is not supported. Use -setDataView:aView instead."];
}
/*!
@ignore
*/
- (CPView)dataCell
{
[CPException raise:CPUnsupportedMethodException
reason:@"dataCell is not supported. Use -dataView instead."];
}
/*!
@ignore
*/
- (id)dataCellForRow:(int)row
{
[CPException raise:CPUnsupportedMethodException
+10 -11
View File
@@ -212,7 +212,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
- (CGRect)headerRectOfColumn:(int)aColumnIndex
{
var headerRect = [self bounds],
var headerRect = CGRectMakeCopy([self bounds]),
columnRect = [_tableView rectOfColumn:aColumnIndex];
headerRect.origin.x = _CGRectGetMinX(columnRect);
@@ -592,15 +592,15 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
for (var i = 0; i < count; i++)
{
var column = [tableColumns objectAtIndex:i],
headerView = [column headerView];
headerView = [column headerView],
frame = [self headerRectOfColumn:i];
var frame = [self headerRectOfColumn:i];
// Make space for the gridline on the right.
frame.origin.x -= 0.5;
frame.size.width -= 1.0;
frame.size.height -= 0.5;
if (i > 0)
{
frame.origin.x += 0.5;
frame.size.width -= 1;
}
// Note: we're not adding in intercell spacing here. This setting only affects the regular
// table cell data views, not the header. Verified in Cocoa on March 29th, 2011.
[headerView setFrame:frame];
@@ -642,10 +642,9 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
columnMaxX = _CGRectGetMaxX(columnToStroke);
CGContextMoveToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(_CGRectGetMinY(columnToStroke)));
CGContextAddLineToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(_CGRectGetMaxY(columnToStroke)));
CGContextMoveToPoint(context, FLOOR(columnMaxX) - 0.5, ROUND(_CGRectGetMinY(columnToStroke)));
CGContextAddLineToPoint(context, FLOOR(columnMaxX) - 0.5, ROUND(_CGRectGetMaxY(columnToStroke)));
}
CGContextClosePath(context);
CGContextStrokePath(context);
+458 -276
View File
File diff suppressed because it is too large Load Diff
+274 -77
View File
@@ -1,4 +1,3 @@
/*
* CPTextField.j
* AppKit
@@ -21,13 +20,15 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#import "../Foundation/Ref.h"
@import "CPControl.j"
@import "CPStringDrawing.j"
@import "CPCompatibility.j"
@import "_CPImageAndTextView.j"
CPTextFieldSquareBezel = 0; /*! A textfield bezel with a squared corners. */
CPTextFieldSquareBezel = 0; /*! A textfield bezel with squared corners. */
CPTextFieldRoundedBezel = 1; /*! A textfield bezel with rounded corners. */
CPTextFieldDidFocusNotification = @"CPTextFieldDidFocusNotification";
@@ -83,13 +84,11 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
CPColor _textFieldBackgroundColor;
id _placeholderString;
BOOL _currentValueIsPlaceholder;
CPString _placeholderString;
CPString _stringValue;
id _delegate;
CPString _textDidChangeValue;
// NS-style Display Properties
CPTextFieldBezelStyle _bezelStyle;
BOOL _isBordered;
@@ -482,17 +481,17 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
[self setNeedsLayout];
_isEditing = NO;
_stringValue = [self stringValue];
#if PLATFORM(DOM)
var string = [self stringValue],
element = [self _inputElement],
var element = [self _inputElement],
font = [self currentValueForThemeAttribute:@"font"];
// generate the font metric
[font _getMetrics];
element.value = string;
element.value = _stringValue;
element.style.color = [[self currentValueForThemeAttribute:@"text-color"] cssString];
element.style.font = [font cssString];
element.style.zIndex = 1000;
@@ -509,7 +508,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
var contentRect = [self contentRectForBounds:[self bounds]],
verticalAlign = [self currentValueForThemeAttribute:"vertical-alignment"];
switch(verticalAlign)
switch (verticalAlign)
{
case CPTopVerticalTextAlignment:
var topPoint = (_CGRectGetMinY(contentRect) + 1) + "px"; // for the same reason we have a -1 for the left, we also have a + 1 here
@@ -528,10 +527,10 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
break;
}
element.style.top = topPoint;
element.style.top = topPoint;
element.style.left = (_CGRectGetMinX(contentRect) - 1) + "px"; // why -1?
element.style.width = _CGRectGetWidth(contentRect) + "px";
element.style.height = font._lineHeight + "px"; // private ivar for the line height of the DOM text at this particaulr size
element.style.height = font._lineHeight + "px"; // private ivar for the line height of the DOM text at this particular size
_DOMElement.appendChild(element);
@@ -549,8 +548,6 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
CPTextFieldInputOwner = self;
}, 0.0);
element.value = [self stringValue];
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
CPTextFieldInputIsActive = YES;
@@ -573,19 +570,43 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
{
[self unsetThemeState:CPThemeStateEditing];
#if PLATFORM(DOM)
var element = [self _inputElement],
newValue = element.value,
error = @"";
if (newValue !== _stringValue)
{
[self _setStringValue:newValue];
}
// If there is a formatter, always give it a chance to reject the resignation,
// even if the value has not changed.
if ([self _valueIsValid:newValue] === NO)
{
[self setThemeState:CPThemeStateEditing];
element.focus();
return NO;
}
#endif
// Cache the formatted string
_stringValue = [self stringValue];
_willBecomeFirstResponderByClick = NO;
[self _updatePlaceholderState];
[self setNeedsLayout];
#if PLATFORM(DOM)
var element = [self _inputElement];
if ([self stringValue] !== element.value)
[self _setStringValue:element.value];
CPTextFieldInputResigning = YES;
element.blur();
if (CPTextFieldInputIsActive)
element.blur();
if (!CPTextFieldInputDidBlur)
CPTextFieldBlurFunction();
@@ -609,7 +630,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
#endif
//post CPControlTextDidEndEditingNotification
// post CPControlTextDidEndEditingNotification
if (_isEditing)
{
_isEditing = NO;
@@ -624,6 +645,28 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
return YES;
}
- (BOOL)_valueIsValid:(CPString)aValue
{
#if PLATFORM(DOM)
var error = @"";
if ([self _setStringValue:aValue isNewValue:NO errorDescription:AT_REF(error)] === NO)
{
var acceptInvalidValue = NO;
if ([_delegate respondsToSelector:@selector(control:didFailToFormatString:errorDescription:)])
acceptInvalidValue = [_delegate control:self didFailToFormatString:[self _inputElement] errorDescription:error];
if (acceptInvalidValue === NO)
return NO;
}
#endif
return YES;
}
/*!
Text fields require panels to become key window, so this returns \c YES.
*/
@@ -684,10 +727,112 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
- (void)keyUp:(CPEvent)anEvent
{
var oldValue = [self stringValue];
[self _setStringValue:[self _inputElement].value];
#if PLATFORM(DOM)
if (oldValue !== [self stringValue])
var newValue = [self _inputElement].value;
if (newValue !== _stringValue)
{
[self _setStringValue:newValue];
if (!_isEditing)
{
_isEditing = YES;
[self textDidBeginEditing:[CPNotification notificationWithName:CPControlTextDidBeginEditingNotification object:self userInfo:nil]];
}
[self textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:self userInfo:nil]];
}
#endif
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
}
- (void)keyDown:(CPEvent)anEvent
{
// CPTextField uses an HTML input element to take the input so we need to
// propagate the dom event so the element is updated. This has to be done
// before interpretKeyEvents: though so individual commands have a chance
// to override this (escape to clear the text in a search field for example).
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
[self interpretKeyEvents:[anEvent]];
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
}
/*!
Invoke the action specified by aSelector on the current responder.
This is implemented by CPResponder and by default it passes any unrecognized
actions on to the next responder but text fields apparently aren't supposed
to do that according to this documentation by Apple:
http://developer.apple.com/mac/library/documentation/cocoa/reference/NSTextInputClient_Protocol/Reference/Reference.html#//apple_ref/occ/intfm/NSTextInputClient/doCommandBySelector:
*/
- (void)doCommandBySelector:(SEL)aSelector
{
if ([self respondsToSelector:aSelector])
[self performSelector:aSelector];
}
- (void)insertNewline:(id)sender
{
var newValue = [self _inputElement].value;
if (newValue !== _stringValue)
{
[self _setStringValue:newValue];
}
if ([self _valueIsValid:_stringValue])
{
// If _isEditing == YES then the target action can also be called via
// resignFirstResponder, and it is possible that the target action
// itself will change this textfield's responder status, so start by
// setting the _isEditing flag to NO to prevent the target action being
// called twice (once below and once from resignFirstResponder).
if (_isEditing)
{
_isEditing = NO;
[self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:nil]];
}
// If there is no target action, or the sendAction call returns
// success.
if (![self action] || [self sendAction:[self action] to:[self target]])
{
[self selectAll:nil];
}
}
[[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
}
- (void)insertNewlineIgnoringFieldEditor:(id)sender
{
[self _insertCharacterIgnoringFieldEditor:CPNewlineCharacter];
}
- (void)insertTabIgnoringFieldEditor:(id)sender
{
[self _insertCharacterIgnoringFieldEditor:CPTabCharacter];
}
- (void)_insertCharacterIgnoringFieldEditor:(CPString)aCharacter
{
#if PLATFORM(DOM)
var oldValue = _stringValue,
range = [self selectedRange],
element = [self _inputElement];
element.value = [element.value stringByReplacingCharactersInRange:[self selectedRange] withString:aCharacter];
[self _setStringValue:element.value];
// NOTE: _stringValue is now the current input element value
if (oldValue !== _stringValue)
{
if (!_isEditing)
{
@@ -698,33 +843,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
[self textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:self userInfo:nil]];
}
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
}
- (void)keyDown:(CPEvent)anEvent
{
var characters = [anEvent characters];
// Treat \r and \n the same. See issue #710.
if (characters === CPNewlineCharacter || characters === CPCarriageReturnCharacter)
{
// selectText: has a side effect - it can change first responder of the window
// we have to prevent such behaviour inside this method because target should be able to change first responder after receiving action.
[self selectText:nil];
if (_isEditing)
{
_isEditing = NO;
[self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:nil]];
}
[self sendAction:[self action] to:[self target]];
[[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
}
else
[[[self window] platformWindow] _propagateCurrentDOMEvent:YES];
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
#endif
}
- (void)textDidBlur:(CPNotification)note
@@ -745,17 +864,18 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
[[CPNotificationCenter defaultCenter] postNotification:note];
}
- (void)sendAction:(SEL)anAction to:(id)anObject
- (void)textDidChange:(CPNotification)note
{
// Don't reverse set our empty value
if (!_currentValueIsPlaceholder)
[self _reverseSetBinding];
if ([note object] !== self)
return;
[CPApp sendAction:anAction to:anObject from:self];
[self _continuouslyReverseSetBinding];
[super textDidChange:note];
}
/*!
Returns the string the text field.
Returns the string in the text field.
*/
- (id)objectValue
{
@@ -764,24 +884,84 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
/*
@ignore
Sets the internal string value without updating the value in the input element
Sets the internal string value without updating the value in the input element.
This should only be invoked when the underlying text element's value has changed.
*/
- (void)_setStringValue:(id)aValue
- (BOOL)_setStringValue:(CPString)aValue
{
[self willChangeValueForKey:@"objectValue"];
[super setObjectValue:String(aValue)];
[self _updatePlaceholderState];
[self didChangeValueForKey:@"objectValue"];
return [self _setStringValue:aValue isNewValue:YES errorDescription:nil];
}
/*
@ignore
Sets the internal string value without updating the value in the input element.
If there is a formatter and formatting fails, returns NO. Otherwise returns YES.
*/
- (BOOL)_setStringValue:(CPString)aValue isNewValue:(BOOL)isNewValue errorDescription:(CPStringRef)anError
{
_stringValue = aValue;
var objectValue = aValue,
formatter = [self formatter],
result = YES;
if (formatter)
{
var object = nil;
if ([formatter getObjectValue:AT_REF(object) forString:aValue errorDescription:anError])
objectValue = object;
else
{
objectValue = undefined; // Mark the value as invalid
result = NO;
}
isNewValue |= objectValue !== [super objectValue];
}
if (isNewValue)
{
[self willChangeValueForKey:@"objectValue"];
[super setObjectValue:objectValue];
[self _updatePlaceholderState];
[self didChangeValueForKey:@"objectValue"];
}
return result;
}
- (void)setObjectValue:(id)aValue
{
[super setObjectValue:aValue];
var formatter = [self formatter];
if (formatter)
{
// If there is a formatter, make sure the object value can be formatted successfully
var formattedString = [self hasThemeState:CPThemeStateEditing] ? [formatter editingStringForObjectValue:aValue] : [formatter stringForObjectValue:aValue];
if (formattedString === nil)
{
var value = nil;
// Formatting failed, get an "empty" object by formatting an empty string.
// If that fails, the value is undefined.
if ([formatter getObjectValue:AT_REF(value) forString:@"" errorDescription:nil] === NO)
value = undefined;
[super setObjectValue:value];
}
}
_stringValue = [self stringValue];
#if PLATFORM(DOM)
if (CPTextFieldInputOwner === self || [[self window] firstResponder] === self)
[self _inputElement].value = aValue;
[self _inputElement].value = _stringValue;
#endif
[self _updatePlaceholderState];
@@ -789,9 +969,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
- (void)_updatePlaceholderState
{
var string = [self stringValue];
if ((!string || string.length === 0) && ![self hasThemeState:CPThemeStateEditing])
if ((!_stringValue || _stringValue.length === 0) && ![self hasThemeState:CPThemeStateEditing])
[self setThemeState:CPTextFieldStatePlaceholder];
else
[self unsetThemeState:CPTextFieldStatePlaceholder];
@@ -844,7 +1022,6 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
However, since you don't know how tall it needs to be if you change the font, sizeToFit will still be
useful for making the textfield an appropriate height.
*/
- (void)sizeToFit
{
[self setFrameSize:[self _minimumFrameSize]];
@@ -857,7 +1034,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
minSize = [self currentValueForThemeAttribute:@"min-size"],
maxSize = [self currentValueForThemeAttribute:@"max-size"],
lineBreakMode = [self lineBreakMode],
text = ([self stringValue] || @" "),
text = (_stringValue || @" "),
textSize = _CGSizeMakeCopy(frameSize),
font = [self currentValueForThemeAttribute:@"font"];
@@ -928,8 +1105,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
return;
var pasteboard = [CPPasteboard generalPasteboard],
stringValue = [self stringValue],
stringForPasting = [stringValue substringWithRange:selectedRange];
stringForPasting = [_stringValue substringWithRange:selectedRange];
[pasteboard declareTypes:[CPStringPboardType] owner:nil];
[pasteboard setString:stringForPasting forType:CPStringPboardType];
@@ -943,6 +1119,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
[self copy:sender];
[self deleteBackward:sender];
}
else
[CPTimer scheduledTimerWithTimeInterval:0.0 target:self selector:@selector(keyUp:) userInfo:nil repeats:NO];
}
- (void)paste:(id)sender
@@ -957,13 +1135,14 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
[self deleteBackward:sender];
var selectedRange = [self selectedRange],
stringValue = [self stringValue],
pasteString = [pasteboard stringForType:CPStringPboardType],
newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:pasteString];
newValue = [_stringValue stringByReplacingCharactersInRange:selectedRange withString:pasteString];
[self setStringValue:newValue];
[self setSelectedRange:CPMakeRange(selectedRange.location + pasteString.length, 0)];
}
else
[CPTimer scheduledTimerWithTimeInterval:0.0 target:self selector:@selector(keyUp:) userInfo:nil repeats:NO];
}
- (CPRange)selectedRange
@@ -971,6 +1150,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
if ([[self window] firstResponder] !== self)
return CPMakeRange(0, 0);
#if PLATFORM(DOM)
// we wrap this in try catch because firefox will throw an exception in certain instances
try
{
@@ -997,6 +1178,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
// fall through to the return
}
#endif
return CPMakeRange(0, 0);
}
@@ -1005,6 +1188,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
if (![[self window] firstResponder] === self)
return;
#if PLATFORM(DOM)
var inputElement = [self _inputElement];
try
@@ -1033,6 +1218,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
catch (e)
{
}
#endif
}
- (void)selectAll:(id)sender
@@ -1042,9 +1229,15 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
- (void)deleteBackward:(id)sender
{
var selectedRange = [self selectedRange],
stringValue = [self stringValue],
newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:""];
var selectedRange = [self selectedRange];
if (selectedRange.length < 2)
return;
selectedRange.location += 1;
selectedRange.length -= 1;
var newValue = [_stringValue stringByReplacingCharactersInRange:selectedRange withString:""];
[self setStringValue:newValue];
[self setSelectedRange:CPMakeRange(selectedRange.location, 0)];
@@ -1197,7 +1390,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
string = [self placeholderString];
else
{
string = [self stringValue];
string = _stringValue;
if ([self isSecure])
string = secureStringForString(string);
@@ -1337,6 +1530,10 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
newValue = [options objectForKey:CPNotApplicablePlaceholderBindingOption] || @"Not Applicable";
break;
case CPNullMarker:
newValue = [options objectForKey:CPNullPlaceholderBindingOption] || @"";
break;
}
[_source setPlaceholderString:newValue];
+142 -61
View File
@@ -97,61 +97,66 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
{
if (self = [super initWithFrame:frame])
{
_selectedRange = CPMakeRange(0, 0);
_tokenScrollView = [[CPScrollView alloc] initWithFrame:CGRectMakeZero()];
[_tokenScrollView setHasHorizontalScroller:NO];
[_tokenScrollView setHasVerticalScroller:NO];
[_tokenScrollView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
var contentView = [[CPView alloc] initWithFrame:CGRectMakeZero()];
[contentView setAutoresizingMask:CPViewWidthSizable];
[_tokenScrollView setDocumentView:contentView];
[self addSubview:_tokenScrollView];
_tokenIndex = 0;
_cachedCompletions = [];
_completionDelay = [CPTokenField defaultCompletionDelay];
_tokenizingCharacterSet = [[self class] defaultTokenizingCharacterSet];
_autocompleteContainer = [[CPView alloc] initWithFrame:CPRectMake(0.0, 0.0, frame.size.width, 92.0)];
[_autocompleteContainer setBackgroundColor:[_CPMenuWindow backgroundColorForBackgroundStyle:_CPMenuWindowPopUpBackgroundStyle]];
_autocompleteScrollView = [[CPScrollView alloc] initWithFrame:CPRectMake(1.0, 1.0, frame.size.width - 2.0, 90.0)];
[_autocompleteScrollView setAutohidesScrollers:YES];
[_autocompleteScrollView setHasHorizontalScroller:NO];
[_autocompleteContainer addSubview:_autocompleteScrollView];
_autocompleteView = [[CPTableView alloc] initWithFrame:CPRectMakeZero()];
var tableColumn = [[CPTableColumn alloc] initWithIdentifier:CPTokenFieldTableColumnIdentifier];
[tableColumn setResizingMask:CPTableColumnAutoresizingMask];
[_autocompleteView addTableColumn:tableColumn];
[_autocompleteView setDataSource:self];
[_autocompleteView setDelegate:self];
[_autocompleteView setAllowsMultipleSelection:NO];
[_autocompleteView setHeaderView:nil];
[_autocompleteView setCornerView:nil];
[_autocompleteView setRowHeight:30.0];
[_autocompleteView setGridStyleMask:CPTableViewSolidHorizontalGridLineMask];
[_autocompleteView setBackgroundColor:[CPColor clearColor]];
[_autocompleteView setGridColor:[CPColor colorWithRed:242.0 / 255.0 green:243.0 / 255.0 blue:245.0 / 255.0 alpha:1.0]];
[_autocompleteScrollView setDocumentView:_autocompleteView];
[self setBezeled:YES];
[self _init];
[self setObjectValue:[]];
[self setNeedsLayout];
}
return self;
}
- (void)_init
{
_selectedRange = CPMakeRange(0, 0);
var frame = [self frame];
_tokenScrollView = [[CPScrollView alloc] initWithFrame:CGRectMakeZero()];
[_tokenScrollView setHasHorizontalScroller:NO];
[_tokenScrollView setHasVerticalScroller:NO];
[_tokenScrollView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
var contentView = [[CPView alloc] initWithFrame:CGRectMakeZero()];
[contentView setAutoresizingMask:CPViewWidthSizable];
[_tokenScrollView setDocumentView:contentView];
[self addSubview:_tokenScrollView];
_cachedCompletions = [];
_autocompleteContainer = [[CPView alloc] initWithFrame:CPRectMake(0.0, 0.0, frame.size.width, 92.0)];
[_autocompleteContainer setBackgroundColor:[_CPMenuWindow backgroundColorForBackgroundStyle:_CPMenuWindowPopUpBackgroundStyle]];
_autocompleteScrollView = [[CPScrollView alloc] initWithFrame:CPRectMake(1.0, 1.0, frame.size.width - 2.0, 90.0)];
[_autocompleteScrollView setAutohidesScrollers:YES];
[_autocompleteScrollView setHasHorizontalScroller:NO];
[_autocompleteContainer addSubview:_autocompleteScrollView];
_autocompleteView = [[CPTableView alloc] initWithFrame:CPRectMakeZero()];
var tableColumn = [[CPTableColumn alloc] initWithIdentifier:CPTokenFieldTableColumnIdentifier];
[tableColumn setResizingMask:CPTableColumnAutoresizingMask];
[_autocompleteView addTableColumn:tableColumn];
[_autocompleteView setDataSource:self];
[_autocompleteView setDelegate:self];
[_autocompleteView setAllowsMultipleSelection:NO];
[_autocompleteView setHeaderView:nil];
[_autocompleteView setCornerView:nil];
[_autocompleteView setRowHeight:30.0];
[_autocompleteView setGridStyleMask:CPTableViewSolidHorizontalGridLineMask];
[_autocompleteView setBackgroundColor:[CPColor clearColor]];
[_autocompleteView setGridColor:[CPColor colorWithRed:242.0 / 255.0 green:243.0 / 255.0 blue:245.0 / 255.0 alpha:1.0]];
[_autocompleteScrollView setDocumentView:_autocompleteView];
}
// ===============
// = CONVENIENCE =
// ===============
@@ -159,7 +164,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
{
var indexOfSelectedItem = 0;
_cachedCompletions = [self tokenField:self completionsForSubstring:[self _inputElement].value indexOfToken:_tokenIndex indexOfSelectedItem:indexOfSelectedItem];
_cachedCompletions = [self tokenField:self completionsForSubstring:[self _inputElement].value indexOfToken:0 indexOfSelectedItem:indexOfSelectedItem];
[_autocompleteView selectRowIndexes:[CPIndexSet indexSetWithIndex:indexOfSelectedItem] byExtendingSelection:NO];
[_autocompleteView reloadData];
@@ -167,19 +172,20 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
- (void)_autocompleteWithDOMEvent:(JSObject)DOMEvent
{
if (!_cachedCompletions || ![self hasThemeState:CPThemeStateAutoCompleting])
if (![self _inputElement].value && (!_cachedCompletions || ![self hasThemeState:CPThemeStateAutoCompleting]))
return;
[self _hideCompletions];
var token = _cachedCompletions[[_autocompleteView selectedRow]],
var token = _cachedCompletions ? _cachedCompletions[[_autocompleteView selectedRow]] : nil,
shouldRemoveLastObject = token !== @"" && [self _inputElement].value !== @"";
if (!token)
token = [self _inputElement].value;
// Make sure the user typed an actual token to prevent the previous token from being emptied
// If the input area is empty, we want to fallback to the normal behaviour, resigning first responder or select the next or previous key view
// If the input area is empty, we want to fall back to the normal behavior, resigning first
// responder or selecting the next or previous key view.
if (!token || token === @"")
{
if (DOMEvent && DOMEvent.keyCode === CPTabKeyCode)
@@ -194,18 +200,32 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
return;
}
var objectValue = [self objectValue];
// Remove the uncompleted token and add the token string.
// Explicitely remove the last object because the array contains strings and removeObject uses isEqual to compare objects
// Explicitly remove the last object because the array contains strings and removeObject uses isEqual to compare objects
if (shouldRemoveLastObject)
[objectValue removeObjectAtIndex:_selectedRange.location];
[objectValue insertObject:token atIndex:_selectedRange.location];
// Give the delegate a chance to confirm, replace or add to the list of tokens being added.
var delegateApprovedObjects = [self tokenField:self shouldAddObjects:[CPArray arrayWithObject:token] atIndex:_selectedRange.location],
delegateApprovedObjectsCount = [delegateApprovedObjects count];
if (delegateApprovedObjects)
{
for (var i = 0; i < delegateApprovedObjectsCount; i++)
{
[objectValue insertObject:[delegateApprovedObjects objectAtIndex:i] atIndex:_selectedRange.location + i];
}
}
// Put the cursor after the last inserted token.
var location = _selectedRange.location;
[self setObjectValue:objectValue];
_selectedRange = CPMakeRange(location + 1, 0);
if (delegateApprovedObjectsCount)
location += delegateApprovedObjectsCount;
_selectedRange = CPMakeRange(location, 0);
[self _inputElement].value = @"";
[self setNeedsLayout];
@@ -250,8 +270,13 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
var indexOfToken = [[self _tokens] indexOfObject:token],
objectValue = [self objectValue];
// If the token was selected, deselect it for selection preservation.
[self _deselectToken:token];
// If the selection was to the right of the deleted token, move it to the left. If the deleted token was
// selected, deselect it.
if (indexOfToken < _selectedRange.location)
_selectedRange.location--;
else
[self _deselectToken:token];
// Preserve selection.
var selection = CPCopyRange(_selectedRange);
[objectValue removeObjectAtIndex:indexOfToken];
@@ -291,6 +316,14 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
[self _controlTextDidChange];
}
- (void)_updatePlaceholderState
{
if (([[self _tokens] count] === 0) && ![self hasThemeState:CPThemeStateEditing])
[self setThemeState:CPTextFieldStatePlaceholder];
else
[self unsetThemeState:CPTextFieldStatePlaceholder];
}
// =============
// = RESPONDER =
// =============
@@ -455,7 +488,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
- (CPArray)_tokens
{
// We return super here because objectValue uses this method
// If we called self we would loop infinitly
// If we called self we would loop infinitely
return [super objectValue];
}
@@ -575,14 +608,16 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
{
}
// ========
// = VIEW =
// ========
- (void)viewDidMoveToWindow
{
[[[self window] contentView] addSubview:_autocompleteContainer];
#if PLATFORM(DOM)
_autocompleteContainer._DOMElement.style.zIndex = 1000; // Anything else doesn't seem to work
#endif
}
- (void)removeFromSuperview
@@ -633,7 +668,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
CPTokenFieldTextDidChangeValue = [CPTokenFieldInputOwner stringValue];
// Update the selectedIndex if necesary
// Update the selectedIndex if necessary
var index = [[CPTokenFieldInputOwner autocompleteView] selectedRow];
if (aDOMEvent.keyCode === CPUpArrowKeyCode)
@@ -665,7 +700,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
aDOMEvent.stopPropagation();
aDOMEvent.cancelBubble = true;
// Only resign first responder if we weren't autocompleting
// Only resign first responder if we weren't auto-completing
if (![CPTokenFieldInputOwner hasThemeState:CPThemeStateAutoCompleting])
{
if (aDOMEvent && aDOMEvent.keyCode === CPReturnKeyCode)
@@ -1123,13 +1158,13 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
{
if ([[self delegate] respondsToSelector:@selector(tokenField:completionsForSubstring:indexOfToken:indexOfSelectedItem:)])
{
return [[self delegate] tokenField:tokenField completionsForSubstring:substring indexOfToken:_tokenIndex indexOfSelectedItem:selectedIndex];
return [[self delegate] tokenField:tokenField completionsForSubstring:substring indexOfToken:tokenIndex indexOfSelectedItem:selectedIndex];
}
return [];
}
// // Alows the delegate to provide a string to be displayed as a proxy for the given represented object.
// // Allows the delegate to provide a string to be displayed as a proxy for the given represented object.
// // If you return nil or do not implement this method, then representedObject is displayed as the string.
- (CPString)tokenField:(CPTokenField)tokenField displayStringForRepresentedObject:(id)representedObject
{
@@ -1149,7 +1184,19 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
// // return an array of represented objects you want to add.
// // If you want to reject the add, return an empty array.
// // returning nil will cause an error.
// - (NSArray *)tokenField:(NSTokenField *)tokenField shouldAddObjects:(NSArray *)tokens atIndex:(NSUInteger)index;
- (CPArray)tokenField:(CPTokenField)tokenField shouldAddObjects:(CPArray)tokens atIndex:(int)index
{
var delegate = [self delegate];
if ([delegate respondsToSelector:@selector(tokenField:shouldAddObjects:atIndex:)])
{
var approvedObjects = [delegate tokenField:tokenField shouldAddObjects:tokens atIndex:index];
if (approvedObjects !== nil)
return approvedObjects;
}
return tokens;
}
//
// // If you return nil or don't implement these delegate methods, we will assume
// // editing string = display string = represented object
@@ -1292,3 +1339,37 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
}
@end
var CPTokenFieldTokenizingCharacterSetKey = "CPTokenFieldTokenizingCharacterSetKey",
CPTokenFieldCompletionDelayKey = "CPTokenFieldCompletionDelay";
@implementation CPTokenField (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
_tokenizingCharacterSet = [aCoder decodeObjectForKey:CPTokenFieldTokenizingCharacterSetKey] || [[self class] defaultTokenizingCharacterSet];
_completionDelay = [aCoder decodeDoubleForKey:CPTokenFieldCompletionDelayKey] || [[self class] defaultCompletionDelay];
[self _init];
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeInt:_tokenizingCharacterSet forKey:CPTokenFieldTokenizingCharacterSetKey];
[aCoder encodeDouble:_completionDelay forKey:CPTokenFieldCompletionDelayKey];
}
@end
+6 -2
View File
@@ -464,7 +464,7 @@ var CPToolbarIdentifierKey = @"CPToolbarIdentifierKey",
// Because we don't know if a delegate will be set later (it is optional
// as of OS X 10.5), we need to call -_reloadToolbarItems here.
// In order to load any toolbar items that may have been configured in the
// Cib. Unfortunatelly this means that if there is a delegate
// Cib. Unfortunately this means that if there is a delegate
// specified, it will be read later and the resulting call to -setDelegate:
// will cause -_reloadToolbarItems] to run again :-(
// FIXME: Can we make this better?
@@ -849,6 +849,10 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
view = [[_CPToolbarItemView alloc] initWithToolbarItem:item toolbar:self];
_viewsForToolbarItems[[item UID]] = view;
if ([item toolTip] && [view respondsToSelector:@selector(setToolTip:)])
[view setToolTip:[item toolTip]];
[self addSubview:view];
_minWidth += [view minSize].width + TOOLBAR_ITEM_MARGIN;
@@ -1011,7 +1015,7 @@ var TOP_MARGIN = 5.0,
_labelSize = [_labelField frame].size;
_minSize = CGSizeMake(MAX(_labelSize.width, minSize.width), _labelSize.height + minSize.height + LABEL_MARGIN + TOP_MARGIN);
_maxSize = CGSizeMake(MAX(_labelSize.width, minSize.width), 100000000.0);
_maxSize = CGSizeMake(MAX(_labelSize.width, maxSize.width), 100000000.0);
[_toolbar tile];
}
+267
View File
@@ -0,0 +1,267 @@
/*
* CPUserDefaultsController.j
* AppKit
*
* Portions based on NSUserDefaultsController.m (2009-06-04) in Cocotron (http://www.cocotron.org/)
* Copyright (c) 2006-2007 Christopher J. W. Lloyd
*
* Created by Alexander Ljungberg.
* Copyright 2011, WireLoad Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPString.j>
@import <AppKit/CPController.j>
var SharedUserDefaultsController = nil;
@implementation CPUserDefaultsController : CPController
{
CPUserDefaults _defaults @accessors(readonly, property=defaults);
CPDictionary _initialValues @accessors(property=initialValues);
BOOL _appliesImmediately @accessors(property=appliesImmediately);
}
+ (id)sharedUserDefaultsController
{
if (!SharedUserDefaultsController)
SharedUserDefaultsController = [[CPUserDefaultsController alloc] initWithDefaults:nil initialValues:nil];
return SharedUserDefaultsController;
}
- (id)initWithDefaults:(CPUserDefaults)someDefaults initialValues:(CPDictionary)initialValues
{
if (self = [super init])
{
if (!someDefaults)
someDefaults = [CPUserDefaults standardUserDefaults];
_defaults = someDefaults;
_initialValues = [initialValues copy];
_appliesImmediately = YES;
_valueProxy = [[_CPUserDefaultsControllerProxy alloc] initWithController:self];
}
return self;
}
- (id)values
{
return _valueProxy;
}
- (BOOL)hasUnappliedChanges
{
return [_valueProxy hasUnappliedChanges];
}
- (void)save:(id)sender
{
[_valueProxy save];
}
- (void)revert:(id)sender
{
[_valueProxy revert];
}
- (void)revertToInitialValues:(id)sender
{
[_valueProxy revertToInitialValues];
}
@end
var CPUserDefaultsControllerSharedKey = "CPUserDefaultsControllerSharedKey";
@implementation CPUserDefaultsController (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
if ([aCoder decodeBoolForKey:CPUserDefaultsControllerSharedKey])
return [CPUserDefaultsController sharedUserDefaultsController];
self = [super initWithCoder:aCoder];
if (self)
{
[CPException raise:CPUnsupportedMethodException reason:@"decoding of non-shared CPUserDefaultsController not implemented"];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
if (self === SharedUserDefaultsController)
{
[aCoder encodeBool:YES forKey:CPUserDefaultsControllerSharedKey];
return;
}
[CPException raise:CPUnsupportedMethodException reason:@"encoding of non-shared CPUserDefaultsController not implemented"];
}
@end
@implementation _CPUserDefaultsControllerProxy : CPObject
{
CPUserDefaultsController _controller;
// TODO Could be optimised with a JS dict.
CPMutableDictionary _cachedValues;
}
- (id)initWithController:(CPUserDefaultsController)aController
{
if (self = [super init])
{
_controller = aController;
_cachedValues = [CPMutableDictionary dictionary];
[[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(userDefaultsDidChange:) name:CPUserDefaultsDidChangeNotification object:[_controller defaults]];
}
return self;
}
- (void)dealloc
{
// FIXME No dealloc in Cappuccino.
[[CPNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
- (id)valueForKey:(CPString)aKey
{
var value = [_cachedValues objectForKey:aKey];
if (value === nil)
{
value = [[_controller defaults] objectForKey:aKey];
if (value === nil)
value = [[_controller initialValues] objectForKey:aKey];
if (value !== nil)
[_cachedValues setObject:value forKey:aKey];
}
return value;
}
- (void)setValue:(id)aValue forKey:(CPString)aKey
{
[self willChangeValueForKey:aKey];
[_cachedValues setObject:aValue forKey:aKey];
if ([_controller appliesImmediately])
[[_controller defaults] setObject:aValue forKey:aKey];
[self didChangeValueForKey:aKey];
}
- (void)revert
{
var keys = [_cachedValues allKeys],
keysCount = [keys count];
while(keysCount--)
{
var key = keys[keysCount];
[self willChangeValueForKey:key];
[_cachedValues removeObjectForKey:key];
[self didChangeValueForKey:key];
}
}
- (void)save
{
var keys = [_cachedValues allKeys],
keysCount = [keys count];
while(keysCount--)
{
var key = keys[keysCount];
[[_controller defaults] setObject:[_cachedValues objectForKey:key] forKey:key];
}
}
- (void)revertToInitialValues
{
var initial = [_controller initialValues],
keys = [_cachedValues allKeys],
keysCount = [keys count];
while(keysCount--)
{
var key = keys[keysCount];
[self willChangeValueForKey:key];
var initialValue = [initial objectForKey:key];
if (initialValue !== nil)
[_cachedValues setObject:initialValue forKey:key];
else
[_cachedValues removeObjectForKey:key];
[self didChangeValueForKey:key];
}
}
- (void)userDefaultsDidChange:(CPNotification)aNotification
{
var defaults = [_controller defaults],
keys = [_cachedValues allKeys],
keysCount = [keys count];
while(keysCount--)
{
var key = keys[keysCount],
value = [_cachedValues objectForKey:key],
newValue = [defaults objectForKey:key];
if (![value isEqual:newValue])
{
[self willChangeValueForKey:key];
[_cachedValues setObject:newValue forKey:key];
[self didChangeValueForKey:key];
}
}
}
- (BOOL)hasUnappliedChanges
{
var defaults = [_controller defaults],
keys = [_cachedValues allKeys],
keysCount = [keys count];
while(keysCount--)
{
var key = keys[keysCount],
value = [_cachedValues objectForKey:key],
newValue = [defaults objectForKey:key];
if (![value isEqual:newValue])
return YES;
}
return NO;
}
@end
+60 -11
View File
@@ -186,6 +186,9 @@ var CPViewFlags = { },
CPView _previousKeyView;
unsigned _viewClassFlags;
// ToolTips
CPString _toolTip @accessors(property=toolTip);
}
/*
@@ -705,7 +708,7 @@ var CPViewFlags = { },
Sets the frame size of the receiver to the dimensions and origin of the provided rectangle in the coordinate system
of the superview. The method also posts an CPViewFrameDidChangeNotification to the notification
center if the receiver is configured to do so. If the frame is the same as the current frame, the method simply
returns (and no notificaion is posted).
returns (and no notification is posted).
@param aFrame the rectangle specifying the new origin and size of the receiver
*/
- (void)setFrame:(CGRect)aFrame
@@ -1284,6 +1287,14 @@ var CPViewFlags = { },
return view !== nil;
}
/*!
Returns YES if the view is not hidden, has no hidden ancestor and doesn't belong to a hidden window.
*/
- (BOOL)_isVisible
{
return ![self isHiddenOrHasHiddenAncestor] && [[self window] isVisible];
}
/*!
Called when the return value of isHiddenOrHasHiddenAncestor becomes YES,
e.g. when this view becomes hidden due to a setHidden:YES message to
@@ -1735,7 +1746,7 @@ setBoundsOrigin:
@param aLocation the lower-left corner coordinate of \c anImage
@param mouseOffset the distance from the \c -mouseDown: location and the current location
@param anEvent the \c -mouseDown: that triggered the drag
@param aPastebaord the pasteboard that holds the drag data
@param aPasteboard the pasteboard that holds the drag data
@param aSourceObject the drag operation controller
@param slideBack Whether the image should 'slide back' if the drag is rejected
*/
@@ -1750,7 +1761,7 @@ setBoundsOrigin:
@param aLocation the top-left corner coordinate of \c aView
@param mouseOffset the distance from the \c -mouseDown: location and the current location
@param anEvent the \c -mouseDown: that triggered the drag
@param aPastebaord the pasteboard that holds the drag data
@param aPasteboard the pasteboard that holds the drag data
@param aSourceObject the drag operation controller
@param slideBack Whether the view should 'slide back' if the drag is rejected
*/
@@ -2100,7 +2111,7 @@ setBoundsOrigin:
/*!
Scrolls the clip view to a specified point
@param the clip view to scoll
@param the clip view to scroll
@param the point to scroll to
*/
- (void)scrollClipView:(CPClipView)aClipView toPoint:(CGPoint)aPoint
@@ -2121,6 +2132,20 @@ setBoundsOrigin:
@implementation CPView (KeyView)
/*!
Overridden by subclasses to handle a key equivalent.
If the receivers key equivalent is the same as the characters of the key-down event theEvent,
as returned by \ref CPEvent::charactersIgnoringModifiers "[anEvent charactersIgnoringModifiers]",
the receiver should take the appropriate action and return \c YES. Otherwise, it should return
the result of invoking supers implementation. The default implementation of this method simply
passes the message down the view hierarchy (from superviews to subviews)
and returns \c NO if none of the receivers subviews responds \c YES.
@param anEvent An event object that represents the key equivalent pressed
@return \c YES if theEvent is a key equivalent that the receiver handled,
\c NO if it is not a key equivalent that it should handle.
*/
- (BOOL)performKeyEquivalent:(CPEvent)anEvent
{
var count = [_subviews count];
@@ -2167,23 +2192,38 @@ setBoundsOrigin:
- (CPView)previousValidKeyView
{
var result = [self previousKeyView];
var result = [self previousKeyView],
firstResult = result;
while (result && ![result canBecomeKeyView])
{
result = [result previousKeyView];
// Cycled.
if (result === firstResult)
return nil;
}
return result;
}
- (void)_setPreviousKeyView:(CPView)previous
{
_previousKeyView = previous;
if ([previous isEqual:self])
_previousKeyView = nil;
else
_previousKeyView = previous;
}
- (void)setNextKeyView:(CPView)next
{
_nextKeyView = next;
[_nextKeyView _setPreviousKeyView:self];
if ([next isEqual:self])
_nextKeyView = nil;
else
{
_nextKeyView = next;
[_nextKeyView _setPreviousKeyView:self];
}
}
@end
@@ -2498,6 +2538,11 @@ setBoundsOrigin:
return [_themeAttributes[aName] valueForState:_themeState];
}
- (BOOL)hasThemeAttribute:(CPString)aName
{
return (_themeAttributes && _themeAttributes[aName] !== undefined);
}
- (CPView)createEphemeralSubviewNamed:(CPString)aViewName
{
return nil;
@@ -2609,7 +2654,11 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
_registeredDraggedTypes = [CPSet set];
_registeredDraggedTypesArray = [];
_autoresizingMask = [aCoder decodeIntForKey:CPViewAutoresizingMaskKey] || CPViewNotSizable;
// Other views (CPBox) might set an autoresizes mask on their subviews before it is actually decoded.
// We make sure we don't override the value by checking if it was already set.
if (_autoresizingMask === nil)
_autoresizingMask = [aCoder decodeIntForKey:CPViewAutoresizingMaskKey] || CPViewNotSizable;
_autoresizesSubviews = ![aCoder containsValueForKey:CPViewAutoresizesSubviewsKey] || [aCoder decodeBoolForKey:CPViewAutoresizesSubviewsKey];
_hitTests = ![aCoder containsValueForKey:CPViewHitTestsKey] || [aCoder decodeObjectForKey:CPViewHitTestsKey];
@@ -2727,12 +2776,12 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
var nextKeyView = [self nextKeyView];
if (nextKeyView !== nil)
if (nextKeyView !== nil && ![nextKeyView isEqual:self])
[aCoder encodeConditionalObject:nextKeyView forKey:CPViewNextKeyViewKey];
var previousKeyView = [self previousKeyView];
if (previousKeyView !== nil)
if (previousKeyView !== nil && ![previousKeyView isEqual:self])
[aCoder encodeConditionalObject:previousKeyView forKey:CPViewPreviousKeyViewKey];
[aCoder encodeObject:[self themeClass] forKey:CPViewThemeClassKey];
+43 -7
View File
@@ -31,11 +31,41 @@ CPViewAnimationEffectKey = @"CPViewAnimationEffectKey";
CPViewAnimationFadeInEffect = @"CPViewAnimationFadeInEffect";
CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOutEffect";
/*!
@class CPViewAnimation
CPViewAnimation is a subclass of CPAnimation that makes it easy to do
basic animations on views.
*/
@implementation CPViewAnimation : CPAnimation
{
CPArray _viewAnimations;
}
/*!
Designated initializer.
This method takes an array of CPDictionaries. Each dictionary should
contain values for the following keys:
<pre>
CPViewAnimationTargetKey - (Required) The view to animate.
CPViewAnimationStartFrameKey - (Optional) The start frame of the target.
CPViewAnimationEndFrameKey - (Optional) The end frame of the target.
CPViewAnimationEffectKey - (Optional) a fade effect to use for the animation.
</pre>
For example:
<pre>
var animation = [CPDictionary dictionaryWithObjects:[myViewToAnimate, aStartFrame, anEndFrame, CPViewAnimationFadeInEffect]
forKeys:[CPViewAnimationTargetKey, CPViewAnimationStartFrameKey, CPViewAnimationEndFrameKey, CPViewAnimationEffectKey]];
</pre>
If you pass nil instead of an array of dictionaries you should later call setViewAnimations:.
@param viewAnimations - An array of CPDictionaries for each animation.
*/
- (id)initWithViewAnimations:(CPArray)viewAnimations
{
if (self = [super initWithDuration:0.5 animationCurve:CPAnimationLinear])
@@ -81,7 +111,8 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOutEffect";
view = [self _targetView:dictionary],
startFrame = [self _startFrame:dictionary],
endFrame = [self _endFrame:dictionary],
differenceFrame = _CGRectMakeZero();
differenceFrame = _CGRectMakeZero(),
value = [super currentValue];
differenceFrame.origin.x = endFrame.origin.x - startFrame.origin.x;
differenceFrame.origin.y = endFrame.origin.y - startFrame.origin.y;
@@ -89,19 +120,19 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOutEffect";
differenceFrame.size.height = endFrame.size.height - startFrame.size.height;
var intermediateFrame = _CGRectMakeZero();
intermediateFrame.origin.x = startFrame.origin.x + differenceFrame.origin.x * progress;
intermediateFrame.origin.y = startFrame.origin.y + differenceFrame.origin.y * progress;
intermediateFrame.size.width = startFrame.size.width + differenceFrame.size.width * progress;
intermediateFrame.size.height = startFrame.size.height + differenceFrame.size.height * progress;
intermediateFrame.origin.x = startFrame.origin.x + differenceFrame.origin.x * value;
intermediateFrame.origin.y = startFrame.origin.y + differenceFrame.origin.y * value;
intermediateFrame.size.width = startFrame.size.width + differenceFrame.size.width * value;
intermediateFrame.size.height = startFrame.size.height + differenceFrame.size.height * value;
[view setFrame:intermediateFrame];
// Update the view's alpha value
var effect = [self _effect:dictionary];
if (effect === CPViewAnimationFadeInEffect)
[view setAlphaValue:1.0 * progress];
[view setAlphaValue:1.0 * value];
else if (effect === CPViewAnimationFadeOutEffect)
[view setAlphaValue:1.0 + ( 0.0 - 1.0 ) * progress];
[view setAlphaValue:1.0 + ( 0.0 - 1.0 ) * value];
if (progress === 1.0)
[self _targetView:view setHidden:_CGRectIsNull(endFrame) || [view alphaValue] === 0.0];
@@ -181,6 +212,11 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOutEffect";
return _viewAnimations;
}
/*!
Takes an array of CPDictionaries as documented in initWithViewAnimations:.
@param viewAnimations - An array of dictionaries describing the animation.
*/
- (void)setViewAnimations:(CPArray)viewAnimations
{
if (viewAnimations != _viewAnimations)
+59 -31
View File
@@ -29,26 +29,38 @@
var CPViewControllerCachedCibs;
/*! @class CPViewController
The CPViewController class provides the fundamental view-management controller for Cappuccino applications.
The basic view controller class supports the presentation of an associated view in addition to basic support
for managing modal views and, in the future, animations. Subclasses such as CPNavigationController and
CPTabBarController provide additional behavior for managing complex hierarchies of view controllers and views.
/*!
@ingroup appkit
@class CPViewController
You use each instance of CPViewController to manage a single view (and hierarchy). For a simple view controller,
this entails managing the view hierarchy responsible for presenting your application content.
A typical view hierarchy consists of a root viewŃa reference to which is available in the view property of this classŃ
and one or more subviews presenting the actual content. In the case of navigation and tab bar controllers, the view
controller manages not only the high-level view hierarchy (which provides the navigation controls) but also one
or more additional view controllers that handle the presentation of the application content.
The CPViewController class provides the fundamental view-management
controller for Cappuccino applications. The basic view controller class
supports the presentation of an associated view in addition to basic
support for managing modal views and, in the future, animations.
Subclasses such as CPNavigationController and CPTabBarController provide
additional behavior for managing complex hierarchies of view controllers
and views.
Unlike UIViewController in Cocoa Touch, a CPViewController does not represent an entire screen of content. You
will add your root view to an existing view or window's content view. You can manage many view controllers
on screen at once. CPViewController is also the preferred way of working with Cibs.
You use each instance of CPViewController to manage a single view (and
hierarchy). For a simple view controller, this entails managing the view
hierarchy responsible for presenting your application content. A typical
view hierarchy consists of a root view, a reference to which is available
in the view property of this class, and one or more subviews presenting
the actual content. In the case of navigation and tab bar controllers, the
view controller manages not only the high-level view hierarchy (which
provides the navigation controls) but also one or more additional view
controllers that handle the presentation of the application content.
Subclasses can override -loadView to create their custom view hierarchy, or specify a cib name to be loaded automatically.
It has methods that are called when a view appears or disappears.
This class is also a good place for delegate & datasource methods, and other controller stuff.
Unlike UIViewController in Cocoa Touch, a CPViewController does not
represent an entire screen of content. You will add your root view to an
existing view or window's content view. You can manage many view
controllers on screen at once. CPViewController is also the preferred way
of working with Cibs.
Subclasses can override -loadView to create their custom view hierarchy,
or specify a cib name to be loaded automatically. It has methods that are
called when a view appears or disappears. This class is also a good place
for delegate & datasource methods, and other controller stuff.
*/
@implementation CPViewController : CPResponder
{
@@ -88,9 +100,14 @@ var CPViewControllerCachedCibs;
}
/*!
The designated initializer. If you subclass CPViewController, you must call the super implementation of this method, even if you aren't using a Cib.
In the specified Cib, the File's Owner proxy should have its class set to your view controller subclass, with the view outlet connected to the main view.
If you pass in a nil Cib name, then you must either call -setView: before -view is invoked, or override -loadView to set up your views.
The designated initializer. If you subclass CPViewController, you must
call the super implementation of this method, even if you aren't using a
Cib.
In the specified Cib, the File's Owner proxy should have its class set to
your view controller subclass, with the view outlet connected to the main
view. If you pass in a nil Cib name, then you must either call -setView:
before -view is invoked, or override -loadView to set up your views.
@param cibNameOrNil The path to the cib to load for the root view or nil to programmatically create views.
@param cibBundleOrNil The bundle that the cib is located in or nil for the main bundle.
@@ -113,14 +130,18 @@ var CPViewControllerCachedCibs;
}
/*!
Programmatically creates the view that the controller manages.
You should never call this method directly. The view controller calls this method when the view property is requested but is nil.
Programmatically creates the view that the controller manages. You should
never call this method directly. The view controller calls this method
when the view property is requested but is nil.
If you create your views manually, you must override this method and use it to create your view and assign it to the view property.
The default implementation for programmatic views is to create a plain view. You can invoke super to utilize this view.
If you create your views manually, you must override this method and use
it to create your view and assign it to the view property. The default
implementation for programmatic views is to create a plain view. You can
invoke super to utilize this view.
If you use Interface Builder to create your views, you initialize the view using the
initWithCibName:bundle: method then you must not override this method. The consequences risk shattering the space-time continuum.
If you use Interface Builder to create your views, you initialize the view
using the initWithCibName:bundle: method then you must not override this
method. The consequences risk shattering the space-time continuum.
Note: The cib loading system is currently synchronous.
*/
@@ -144,8 +165,10 @@ var CPViewControllerCachedCibs;
/*!
Returns the view that the controller manages.
If this property is nil, the controller sends loadView to itself to create the view that it manages.
Subclasses should override the loadView method to create any custom views. The default value is nil.
If this property is nil, the controller sends loadView to itself to create
the view that it manages. Subclasses should override the loadView method
to create any custom views. The default value is nil.
*/
- (CPView)view
{
@@ -183,8 +206,11 @@ var CPViewControllerCachedCibs;
/*!
This method is called after the view controller has loaded its associated views into memory.
This method is called regardless of whether the views were stored in a nib file or created programmatically in the loadView method.
This method is most commonly used to perform additional initialization steps on views that are loaded from cib files.
This method is called regardless of whether the views were stored in a nib
file or created programmatically in the loadView method. This method is
most commonly used to perform additional initialization steps on views
that are loaded from cib files.
*/
- (void)viewDidLoad
{
@@ -194,7 +220,9 @@ var CPViewControllerCachedCibs;
/*!
Manually sets the view that the controller manages.
Setting to nil will cause -loadView to be called on all subsequent calls of -view.
Setting to nil will cause -loadView to be called on all subsequent calls
of -view.
@param aView The view this controller should represent.
*/
+463 -88
View File
@@ -36,45 +36,94 @@ CPWebViewProgressEstimateChangedNotification = "CPWebViewProgressEstimateChan
CPWebViewProgressStartedNotification = "CPWebViewProgressStartedNotification";
CPWebViewProgressFinishedNotification = "CPWebViewProgressFinishedNotification";
/*!
Automatically choose between AppKit (Cappuccino style) scrollbars and
native scrollbars. In this mode AppKit scrollbars are always used except
when the web view is loaded with a URL which does not appear to pass the
same origin policy.
*/
CPWebViewScrollAuto = 0;
/*!
Always use AppKit scrollbars. If a URL is loaded whcih does not appear to
pass the same origin policy, native scrollbars will be used but a warnning
will be logged.
*/
CPWebViewScrollAppKit = 1;
/*!
Always use native (platform dependent) scrollbars.
*/
CPWebViewScrollNative = 2;
/*!
Never display scrollbars.
*/
CPWebViewScrollNone = 3;
// FIXME: somehow make CPWebView work with CPScrollView instead of native scrollbars (is this even possible?)
/*!
How frequently the size of the document will be checked at page load time
when AppKit scrollbars are used.
*/
CPWebViewAppKitScrollPollInterval = 1.0;
/*!
How many times the size of the size of the document will be checked at
page load time when AppKit scrollbars are used.
AppKit scrollbars must check the size of the document to display the
correct size of scrollbars. To improve performance the checks are only
performed a limited number of times per reload.
*/
CPWebViewAppKitScrollMaxPollCount = 3;
/*!
@ingroup appkit
*/
@class CPWebView
CPWebView allows you to display arbitrary HTML or embed a
webpage inside your application.
It's important to note that the same origin policy applies to this view.
That is, if the web page being displayed is not located in the same origin
(protocol, domain, and port) as the application, you will have limited
control over the view and no access to its contents. Furthermore,
Cappuccino style scrollbars can't be used to scroll it.
*/
@implementation CPWebView : CPView
{
CPScrollView _scrollView;
CPView _frameView;
CPScrollView _scrollView;
CPView _frameView;
IFrame _iframe;
CPString _mainFrameURL;
CPArray _backwardStack;
CPArray _forwardStack;
IFrame _iframe;
CPString _mainFrameURL;
CPArray _backwardStack;
CPArray _forwardStack;
BOOL _ignoreLoadStart;
BOOL _ignoreLoadEnd;
BOOL _ignoreLoadStart;
BOOL _ignoreLoadEnd;
BOOL _isLoading;
id _downloadDelegate;
id _frameLoadDelegate;
id _policyDelegate;
id _resourceLoadDelegate;
id _UIDelegate;
id _downloadDelegate;
id _frameLoadDelegate;
id _policyDelegate;
id _resourceLoadDelegate;
id _UIDelegate;
CPWebScriptObject _wso;
CPWebScriptObject _wso;
CPString _url;
CPString _html;
CPString _url;
CPString _html;
Function _loadCallback;
Function _loadCallback;
int _scrollMode;
CGSize _scrollSize;
int _scrollMode;
int _effectiveScrollMode;
BOOL _contentIsAccessible;
CPTimer _contentSizeCheckTimer;
int _contentSizePollCount;
int _loadHTMLStringTimer;
int _loadHTMLStringTimer;
BOOL _drawsBackground;
}
- (id)initWithFrame:(CPRect)frameRect frameName:(CPString)frameName groupName:(CPString)groupName
@@ -83,17 +132,24 @@ CPWebViewScrollNative = 2;
{
_iframe.name = frameName;
}
return self
return self;
}
- (id)initWithFrame:(CPRect)aFrame
{
if (self = [super initWithFrame:aFrame])
{
_mainFrameURL = nil;
_backwardStack = [];
_forwardStack = [];
_scrollMode = CPWebViewScrollNative;
_mainFrameURL = nil;
_backwardStack = [];
_forwardStack = [];
_scrollMode = CPWebViewScrollAuto;
_contentIsAccessible = YES;
_isLoading = NO;
_drawsBackground = YES;
[self setBackgroundColor:[CPColor whiteColor]];
[self _initDOMWithFrame:aFrame];
}
@@ -113,9 +169,10 @@ CPWebViewScrollNative = 2;
_iframe.style.borderWidth = "0px";
_iframe.frameBorder = "0";
[self setDrawsBackground:YES];
[self _applyBackgroundColor];
_loadCallback = function() {
_loadCallback = function()
{
// HACK: this block handles the case where we don't know about loads initiated by the user clicking a link
if (!_ignoreLoadStart)
{
@@ -127,7 +184,6 @@ CPWebViewScrollNative = 2;
// FIXME: this doesn't actually get the right URL for different domains. Not possible due to browser security restrictions.
_mainFrameURL = _iframe.src;
_mainFrameURL = _iframe.src;
// clear the forward
[_forwardStack removeAllObjects];
@@ -160,21 +216,29 @@ CPWebViewScrollNative = 2;
_frameView._DOMElement.appendChild(_iframe);
[self _setScrollMode:_scrollMode];
[self _updateEffectiveScrollMode];
[self addSubview:_scrollView];
}
- (void)setFrameSize:(CPSize)aSize
{
[super setFrameSize:aSize];
[self _resizeWebFrame];
}
- (void)viewDidUnhide
{
// Sizing cannot properly happen while we're hidden because the iframe is inaccessible.
// So now that it is accessible again, make sure to catch up.
[_frameView setFrameSize:[_scrollView contentSize]];
[self _resizeWebFrame];
[self _scheduleContentSizeCheck];
}
- (void)_attachScrollEventIfNecessary
{
if (_scrollMode !== CPWebViewScrollAppKit)
if (_effectiveScrollMode !== CPWebViewScrollAppKit)
return;
var win = null;
@@ -199,71 +263,130 @@ CPWebViewScrollNative = 2;
- (void)_resizeWebFrame
{
if (_scrollMode === CPWebViewScrollAppKit)
// When a webview is not in the DOM we can't inspect its contents for sizing information.
// If we try, we might end up setting the fallback frame size which will then become
// somewhat sticky.
if (![self _isVisible])
{
if (_scrollSize)
return;
}
if (_effectiveScrollMode === CPWebViewScrollAppKit)
{
var visibleRect = [_frameView visibleRect];
[_frameView setFrameSize:CGSizeMake(CGRectGetMaxX(visibleRect), CGRectGetMaxY(visibleRect))];
// try to get the document size so we can correctly set the frame
var win = null;
try { win = [self DOMWindow]; } catch (e) {}
if (win && win.document && win.document.body)
{
[_frameView setFrameSize:_scrollSize];
var width = win.document.body.scrollWidth,
height = win.document.body.scrollHeight;
_iframe.setAttribute("width", width);
_iframe.setAttribute("height", height);
[_frameView setFrameSize:CGSizeMake(width, height)];
}
else
{
var visibleRect = [_frameView visibleRect];
[_frameView setFrameSize:CGSizeMake(CGRectGetMaxX(visibleRect), CGRectGetMaxY(visibleRect))];
// try to get the document size so we can correctly set the frame
var win = null;
try { win = [self DOMWindow]; } catch (e) {}
if (win && win.document && win.document.body)
{
var width = win.document.body.scrollWidth,
height = win.document.body.scrollHeight;
_iframe.setAttribute("width", width);
_iframe.setAttribute("height", height);
[_frameView setFrameSize:CGSizeMake(width, height)];
}
else
// If we do have access to the content, it might be that the 'body' element simply hasn't loaded yet.
// The size will be updated by the content size timer in this case.
if (!win || !win.document)
{
CPLog.warn("using default size 800*1600");
[_frameView setFrameSize:CGSizeMake(800, 1600)];
}
[_frameView scrollRectToVisible:visibleRect];
}
[_frameView scrollRectToVisible:visibleRect];
}
}
/*!
Sets the scroll mode of the receiver.
Valid values are:
CPWebViewScrollAuto
CPWebViewScrollAppKit
CPWebViewScrollNative
CPWebViewScrollNone
CPWebViewScrollAuto
*/
- (void)setScrollMode:(int)aScrollMode
{
if (_scrollMode == aScrollMode)
return;
[self _setScrollMode:aScrollMode];
_scrollMode = aScrollMode;
[self _updateEffectiveScrollMode];
}
- (void)_setScrollMode:(int)aScrollMode
/*!
Returns the effective scroll mode of the receiver.
Valied values are:
CPWebViewScrollAuto
CPWebViewScrollAppKit
CPWebViewScrollNative
CPWebViewScrollNone
*/
- (int)effectiveScrollMode
{
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
_scrollMode = CPWebViewScrollNative;
else
_scrollMode = aScrollMode;
return _effectiveScrollMode;
}
- (void)_updateEffectiveScrollMode
{
var _newScrollMode = CPWebViewScrollAppKit;
if (_scrollMode == CPWebViewScrollNative
|| (_scrollMode == CPWebViewScrollAuto && !_contentIsAccessible)
|| CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
{
_newScrollMode = CPWebViewScrollNative;
}
else if (_scrollMode == CPWebViewScrollAppKit && !_contentIsAccessible)
{
// Same behaviour as the previous case except that a warning is logged when AppKit
// scrollers can't be used.
CPLog.warn(self + " unable to use CPWebViewScrollAppKit scroll mode due to same origin policy.");
_newScrollMode = CPWebViewScrollNative;
}
if (_newScrollMode !== _effectiveScrollMode)
[self _setEffectiveScrollMode:_newScrollMode];
}
- (void)_setEffectiveScrollMode:(int)aScrollMode
{
_effectiveScrollMode = aScrollMode;
_ignoreLoadStart = YES;
_ignoreLoadEnd = YES;
var parent = _iframe.parentNode;
// FIXME "scrolling" can't be changed without readding the iframe. Unfortunately this causes a reload.
parent.removeChild(_iframe);
if (_scrollMode === CPWebViewScrollAppKit)
if (_effectiveScrollMode === CPWebViewScrollAppKit)
{
[_scrollView setHasHorizontalScroller:YES];
[_scrollView setHasVerticalScroller:YES];
_iframe.setAttribute("scrolling", "no");
}
else if (_effectiveScrollMode === CPWebViewScrollNone)
{
[_scrollView setHasHorizontalScroller:NO];
[_scrollView setHasVerticalScroller:NO];
_iframe.setAttribute("scrolling", "no");
}
else
{
[_scrollView setHasHorizontalScroller:NO];
@@ -275,27 +398,45 @@ CPWebViewScrollNative = 2;
}
parent.appendChild(_iframe);
[self _applyBackgroundColor];
[self _resizeWebFrame];
}
- (void)_maybePollWebFrameSize
{
if (CPWebViewAppKitScrollMaxPollCount == 0 || _contentSizePollCount++ < CPWebViewAppKitScrollMaxPollCount)
[self _resizeWebFrame];
else
[_contentSizeCheckTimer invalidate];
}
/*!
Loads a string of HTML into the receiver.
@param CPString - The string to load.
*/
- (void)loadHTMLString:(CPString)aString
{
[self loadHTMLString:aString baseURL:nil];
}
/*!
Loads a string of HTML into the receiver.
@param CPString - The string to load.
@param CPURL - The base url of the string. (not implemented)
*/
- (void)loadHTMLString:(CPString)aString baseURL:(CPURL)URL
{
// FIXME: do something with baseURL?
[self _setScrollMode:CPWebViewScrollAppKit];
[_frameView setFrameSize:[_scrollView contentSize]];
[self _startedLoading];
_ignoreLoadStart = YES;
_ignoreLoadEnd = NO;
_url = null;
_url = nil;
_html = aString;
[self _load];
@@ -303,15 +444,12 @@ CPWebViewScrollNative = 2;
- (void)_loadMainFrameURL
{
[self _setScrollMode:CPWebViewScrollNative];
[self _startedLoading];
_ignoreLoadStart = YES;
_ignoreLoadEnd = NO;
_url = _mainFrameURL;
_html = null;
_html = nil;
[self _load];
}
@@ -320,13 +458,26 @@ CPWebViewScrollNative = 2;
{
if (_url)
{
// Try to figure out if this URL will pass the same origin policy and hence allow us to potentially
// use appkit scrollbars.
var cpurl = [CPURL URLWithString:_url];
_contentIsAccessible = [cpurl _passesSameOriginPolicy];
[self _updateEffectiveScrollMode];
_ignoreLoadEnd = NO;
_iframe.src = _url;
}
else if (_html)
else if (_html !== nil)
{
// clear the iframe
_iframe.src = "";
_contentIsAccessible = YES;
[self _updateEffectiveScrollMode];
_ignoreLoadEnd = NO;
if (_loadHTMLStringTimer !== nil)
{
window.clearTimeout(_loadHTMLStringTimer);
@@ -338,8 +489,11 @@ CPWebViewScrollNative = 2;
{
var win = [self DOMWindow];
/*
If _html is the empty string, subtitute in an empty HTML structure. Just leaving the contents entirely empty prompts the browser to subtitute in a white page which would interfere with any custom background colours in use by this web view.
*/
if (win)
win.document.write(_html);
win.document.write(_html || "<html><body></body></html>");
window.setTimeout(_loadCallback, 1);
}, 0);
@@ -348,6 +502,8 @@ CPWebViewScrollNative = 2;
- (void)_startedLoading
{
_isLoading = YES;
[[CPNotificationCenter defaultCenter] postNotificationName:CPWebViewProgressStartedNotification object:self];
if ([_frameLoadDelegate respondsToSelector:@selector(webView:didStartProvisionalLoadForFrame:)])
@@ -356,20 +512,69 @@ CPWebViewScrollNative = 2;
- (void)_finishedLoading
{
_isLoading = NO;
[self _resizeWebFrame];
[self _attachScrollEventIfNecessary];
[self _scheduleContentSizeCheck];
[[CPNotificationCenter defaultCenter] postNotificationName:CPWebViewProgressFinishedNotification object:self];
if ([_frameLoadDelegate respondsToSelector:@selector(webView:didFinishLoadForFrame:)])
[_frameLoadDelegate webView:self didFinishLoadForFrame:nil]; // FIXME: give this a frame somehow?
}
- (void)_scheduleContentSizeCheck
{
[_contentSizeCheckTimer invalidate];
if (_effectiveScrollMode == CPWebViewScrollAppKit)
{
/*
FIXME Need better method.
We don't know when the content of the iframe changes size (e.g. a
picture finishes loading, dynamic content is loaded). Often when a
page has initially 'loaded', it does not yet have its final size. In
lieu of any resize events we will simply check back in a few times
some time after loading.
We run these checks only a limited number of times as to not deplete
battery life and slow down the software needlessly. This does mean
there are situations where the content changes size and the AppKit
scrollbars will be out of sync. Users who have dynamic content
in their web view will, for now, have to implement domain specific
fixes.
*/
_contentSizePollCount = 0;
_contentSizeCheckTimer = [CPTimer scheduledTimerWithTimeInterval:CPWebViewAppKitScrollPollInterval target:self selector:@selector(_maybePollWebFrameSize) userInfo:nil repeats:YES];
}
}
/*!
Returns whether the web view is loading. Note: due to browser limitations
this value is not particularly reliable.
*/
- (BOOL)isLoading
{
return _isLoading;
}
/*!
Returns the URL of the main frame.
@return CPString - The URL of the main frame.
*/
- (CPString)mainFrameURL
{
return _mainFrameURL;
}
/*!
Sets the URL of the main frame.
@param CPString - the url to set.
*/
- (void)setMainFrameURL:(CPString)URLString
{
if (_mainFrameURL)
@@ -380,6 +585,11 @@ CPWebViewScrollNative = 2;
[self _loadMainFrameURL];
}
/*!
Tells the webview to navigate to the previous page.
@return BOOL - YES if the receiver was able to go back, otherwise NO.
*/
- (BOOL)goBack
{
if (_backwardStack.length > 0)
@@ -396,6 +606,11 @@ CPWebViewScrollNative = 2;
return NO;
}
/*!
Tells the receiver to go forward in page history.
@return - YES if the receiver was able to go forward, otherwise NO.
*/
- (BOOL)goForward
{
if (_forwardStack.length > 0)
@@ -412,11 +627,23 @@ CPWebViewScrollNative = 2;
return NO;
}
/*!
Checks to see if the webview has a history stack you can navigate back
through.
@return BOOL - YES if the receiver can navigate backward through history, otherwise NO.
*/
- (BOOL)canGoBack
{
return (_backwardStack.length > 0);
}
/*!
Checks to see if the webview has a history stack you can navigate forward
through.
@return BOOL - YES if the receiver can navigate forward through history, otherwise NO.
*/
- (BOOL)canGoForward
{
return (_forwardStack.length > 0);
@@ -428,16 +655,30 @@ CPWebViewScrollNative = 2;
return { back: _backwardStack, forward: _forwardStack };
}
/*!
Closes the webview by unloading the webpage. The webview will no longer
respond to load requests or delegate methods once this is called.
*/
- (void)close
{
_iframe.parentNode.removeChild(_iframe);
}
/*!
Returns the window object of the webview.
@return DOMWindow - The window object.
*/
- (DOMWindow)DOMWindow
{
return (_iframe.contentDocument && _iframe.contentDocument.defaultView) || _iframe.contentWindow;
}
/*!
Returns the root Object of the webview as a CPWebScriptObject.
@return CPWebScriptObject - the Object of the webview.
*/
- (CPWebScriptObject)windowScriptObject
{
var win = [self DOMWindow];
@@ -451,17 +692,37 @@ CPWebViewScrollNative = 2;
return _wso;
}
/*!
Evaluates a javascript string in the webview and returns the result of
that evaluation as a string.
@param script - A string of javascript.
@return CPString - The result of the evaluation.
*/
- (CPString)stringByEvaluatingJavaScriptFromString:(CPString)script
{
var result = [self objectByEvaluatingJavaScriptFromString:script];
return result ? String(result) : nil;
}
/*!
Evaluates a string of javascript in the webview and returns the result.
@param script - A string of javascript.
@return JSObject - A JSObject resulting from the evaluation.
*/
- (JSObject)objectByEvaluatingJavaScriptFromString:(CPString)script
{
return [[self windowScriptObject] evaluateWebScript:script];
}
/*!
Gets the computed style for an element.
@param DOMElement - An Element.
@param pseudoElement - A pseudoElement.
@return DOMCSSStyleDeclaration - The computed style for an element.
*/
- (DOMCSSStyleDeclaration)computedStyleForElement:(DOMElement)element pseudoElement:(CPString)pseudoElement
{
var win = [[self windowScriptObject] window];
@@ -474,47 +735,114 @@ CPWebViewScrollNative = 2;
}
/*!
@return BOOL - YES if the webview draws its own background, otherwise NO.
*/
- (BOOL)drawsBackground
{
return _iframe.style.backgroundColor != "";
return _drawsBackground;
}
- (void)setDrawsBackground:(BOOL)drawsBackround
/*!
Sets whether the webview draws its own background when the displayed contents do not.
If you are trying to create a transparent iframe:
A) call this method with NO
A) call setBackground:[CPColor transparent]
B) ensure the content does not draw a background, e.g. it has <body style="background-color: transparent;">
@param BOOL - YES if the webview should draw its background, otherwise NO.
*/
- (void)setDrawsBackground:(BOOL)drawsBackground
{
_iframe.style.backgroundColor = drawsBackround ? "white" : "";
if (drawsBackground == _drawsBackground)
return;
_drawsBackground = drawsBackground;
[self _applyBackgroundColor];
}
- (void)setBackgroundColor:(CPColor)aColor
{
[super setBackgroundColor:aColor];
[self _applyBackgroundColor];
}
- (void)_applyBackgroundColor
{
if (_iframe)
{
var bgColor = [self backgroundColor] || [CPColor whiteColor];
_iframe.allowtransparency = !_drawsBackground;
_iframe.style.backgroundColor = _drawsBackground ? [bgColor cssString] : "transparent";
}
}
// IBActions
- (IBAction)takeStringURLFrom:(id)sender
/*!
Used with the target/action mechanism to automatically set the webviews
mainFrameURL to the senders stringValue.
@param sender - the sender of the action. Should respond to -stringValue.
*/
- (@action)takeStringURLFrom:(id)sender
{
[self setMainFrameURL:[sender stringValue]];
}
- (IBAction)goBack:(id)sender
/*!
Same as -goBack but takes a sender as a param.
@param sender - the sender of the action.
*/
- (@action)goBack:(id)sender
{
[self goBack];
}
- (IBAction)goForward:(id)sender
/*!
Same as -goForward but takes a sender as a param.
@param sender - the sender of the action.
*/
- (@action)goForward:(id)sender
{
[self goForward];
}
- (IBAction)stopLoading:(id)sender
/*!
Stops loading the webview. (not yet implemented)
@param sender - the sender of the action.
*/
- (@action)stopLoading:(id)sender
{
// FIXME: what to do?
}
- (IBAction)reload:(id)sender
/*!
Reloads the webview.
@param sender - the sender of the action.
*/
- (@action)reload:(id)sender
{
[self _loadMainFrameURL];
// If we're displaying pure HTML, redisplay it.
if(!_url && (_html !== nil))
[self loadHTMLString:_html];
else
[self _loadMainFrameURL];
}
- (IBAction)print:(id)sender
/*!
Tells the webview to print. If the webview is unable to print due to
browser restrictions the user is alerted to print from the file menu.
@param sender - the sender of the receiver.
*/
- (@action)print:(id)sender
{
try
{
@@ -574,12 +902,19 @@ CPWebViewScrollNative = 2;
@end
/*!
@class CPWebScriptObject
A CPWebScriptObject is an Objective-J wrapper around a scripting object.
*/
@implementation CPWebScriptObject : CPObject
{
Window _window;
}
/*!
Initializes the scripting object with the scripting Window object.
*/
- (id)initWithWindow:(Window)aWindow
{
if (self = [super init])
@@ -589,6 +924,12 @@ CPWebViewScrollNative = 2;
return self;
}
/*!
Call a method with arguments on the receiver.
@param methodName - The method that should be called.
@param args - An array of arguments to pass to the method call.
*/
- (id)callWebScriptMethod:(CPString)methodName withArguments:(CPArray)args
{
// Would using "with" be better here?
@@ -602,15 +943,25 @@ CPWebViewScrollNative = 2;
return undefined;
}
/*!
Evaluates a string of javascript and returns the result.
@param script - The script to run.
@return - The result of the evaluation, which may be 'undefined'.
*/
- (id)evaluateWebScript:(CPString)script
{
try {
return _window.eval(script);
} catch (e) {
// FIX ME: if we fail inside here, shouldn't we return an exception?
}
return undefined;
}
/*!
Returns the receivers Window object.
*/
- (Window)window
{
return _window;
@@ -623,6 +974,7 @@ CPWebViewScrollNative = 2;
/*!
Initializes the web view from the data in a coder.
@param aCoder the coder from which to read the data
@return the initialized web view
*/
@@ -636,13 +988,16 @@ CPWebViewScrollNative = 2;
_mainFrameURL = nil;
_backwardStack = [];
_forwardStack = [];
_scrollMode = CPWebViewScrollNative;
_scrollMode = CPWebViewScrollAuto;
#if PLATFORM(DOM)
[self _initDOMWithFrame:[self frame]];
#endif
[self setBackgroundColor:[CPColor whiteColor]];
if (![self backgroundColor])
[self setBackgroundColor:[CPColor whiteColor]];
[self _updateEffectiveScrollMode];
}
return self;
@@ -650,6 +1005,7 @@ CPWebViewScrollNative = 2;
/*!
Writes out the web view's instance information to a coder.
@param aCoder the coder to which to write the data
*/
- (void)encodeWithCoder:(CPCoder)aCoder
@@ -661,3 +1017,22 @@ CPWebViewScrollNative = 2;
}
@end
@implementation CPURL(SOP)
/*!
Private API.
Returns YES if the receiver URL would pass the same origin policy if loaded by the current runtime environment.
Since Cappuccino runs in the browser, it is often restricted from accessing URLs from outside of its own origin (protocol, domain, port). This method tries to determine if the URL represented by the receiver is of the same origin, or if other circumstances will allow the content at the URL to be interacted with.
*/
- (BOOL)_passesSameOriginPolicy
{
var documentURL = [CPURL URLWithString:window.location.href];
if ([documentURL isFileURL] && CPFeatureIsCompatible(CPSOPDisabledFromFileURLs))
return YES;
return ([documentURL scheme] == [self scheme] && [documentURL host] == [self host] && [documentURL port] == [self port]);
}
@end
+217 -31
View File
@@ -193,24 +193,24 @@ var SHADOW_MARGIN_LEFT = 20.0,
_CPWindowShadowColor = nil;
var CPWindowSaveImage = nil,
CPWindowSavingImage = nil;
CPWindowSavingImage = nil,
var CPWindowResizeTime = 0.2;
CPWindowResizeTime = 0.2;
/*
Keys for which action messages will be sent by default when unhandled, e.g. complete:.
*/
var CPWindowActionMessageKeys = [
CPLeftArrowFunctionKey,
CPRightArrowFunctionKey,
CPUpArrowFunctionKey,
CPDownArrowFunctionKey,
CPPageUpFunctionKey,
CPPageDownFunctionKey,
CPHomeFunctionKey,
CPEndFunctionKey,
CPEscapeFunctionKey
];
CPLeftArrowFunctionKey,
CPRightArrowFunctionKey,
CPUpArrowFunctionKey,
CPDownArrowFunctionKey,
CPPageUpFunctionKey,
CPPageDownFunctionKey,
CPHomeFunctionKey,
CPEndFunctionKey,
CPEscapeFunctionKey
];
/*!
@ingroup appkit
@@ -271,6 +271,7 @@ var CPWindowActionMessageKeys = [
BOOL _isAnimating;
BOOL _hasShadow;
BOOL _isMovableByWindowBackground;
BOOL _isMovable;
unsigned _shadowStyle;
BOOL _showsResizeIndicator;
@@ -404,6 +405,7 @@ CPTexturedBackgroundWindowMask
_registeredDraggedTypesArray = [];
_isSheet = NO;
_acceptsMouseMovedEvents = YES;
_isMovable = YES;
// Set up our window number.
_windowNumber = [CPApp._windows count];
@@ -426,6 +428,7 @@ CPTexturedBackgroundWindowMask
// Create a generic content view.
[self setContentView:[[CPView alloc] initWithFrame:CGRectMakeZero()]];
[self setInitialFirstResponder:[self contentView]];
_firstResponder = self;
@@ -466,12 +469,27 @@ CPTexturedBackgroundWindowMask
return _platformWindow;
}
/*!
Sets the platform window of the reciver.
This method will first close the reciever,
change the platform window, then reopen the window (if it was originally open).
*/
- (void)setPlatformWindow:(CPPlatformWindow)aPlatformWindow
{
// FIXME: already visible.
var wasVisible = [self isVisible];
// we have to close it first, otherwise we get a DOM exception.
if (wasVisible)
[self close];
_platformWindow = aPlatformWindow;
[_platformWindow _setTitle:_title window:self];
if (wasVisible)
[self orderFront:self];
}
/*!
@ignore
*/
@@ -539,6 +557,12 @@ CPTexturedBackgroundWindowMask
}
}
/*!
Sets the receiver as a full platform window. If you pass YES the CPWindow instance will fill the entire browser content area,
otherwise the CPWindow will be a window inside of your browser window which the user can drag around, and resize (if you allow).
@param BOOL - YES if the window should fill the browser window, otherwise NO.
*/
- (void)setFullPlatformWindow:(BOOL)shouldBeFullPlatformWindow
{
if (![_platformWindow supportsFullPlatformWindows])
@@ -579,6 +603,9 @@ CPTexturedBackgroundWindowMask
}
}
/*!
@return BOOL - YES if the CPWindow fills the browser window, otherwise NO.
*/
- (BOOL)isFullPlatformWindow
{
return _isFullPlatformWindow;
@@ -594,6 +621,18 @@ CPTexturedBackgroundWindowMask
/*!
Returns the frame rectangle used by a window.
Style masks include:
<pre>
CPBorderlessWindowMask
CPTitledWindowMask
CPClosableWindowMask
CPMiniaturizableWindowMask (NOTE: only available in NativeHost)
CPResizableWindowMask
CPTexturedBackgroundWindowMask
CPBorderlessBridgeWindowMask
CPHUDBackgroundWindowMask
</pre>
@param aContentRect the content rectangle of the window
@param aStyleMask the style mask of the window
@return the matching window's frame rectangle
@@ -635,7 +674,7 @@ CPTexturedBackgroundWindowMask
the resize operation, and redraw itself if necessary.
@param aFrame the new size and location for the window
@param shouldDisplay whether the window should redraw its views
@param shouldAnimate whether the window resize should be animated
@param shouldAnimate whether the window resize should be animated.
*/
- (void)_setClippedFrame:(CGRect)aFrame display:(BOOL)shouldDisplay animate:(BOOL)shouldAnimate
{
@@ -644,6 +683,13 @@ CPTexturedBackgroundWindowMask
[self setFrame:aFrame display:shouldDisplay animate:shouldAnimate];
}
/*!
Sets the frame of the window.
@param aFrame - A CGRect of the new frame for the receiver.
@param shouldDisplay - YES if the window should call setNeedsDisplay otherwise NO.
@param shouldAnimate - YES if the window should animate to it's new size and position, otherwise NO.
*/
- (void)setFrame:(CGRect)aFrame display:(BOOL)shouldDisplay animate:(BOOL)shouldAnimate
{
aFrame = _CGRectMakeCopy(aFrame);
@@ -721,6 +767,11 @@ CPTexturedBackgroundWindowMask
}
}
/*!
Sets the window's frame rect.
@param aFrame - The new CGRect of the window.
@param shouldDisplay - YES if the window should call setNeedsDisplay: otherwise NO.
*/
- (void)setFrame:(CGRect)aFrame display:(BOOL)shouldDisplay
{
[self _setClippedFrame:aFrame display:shouldDisplay animate:NO];
@@ -728,6 +779,7 @@ CPTexturedBackgroundWindowMask
/*!
Sets the window's frame rectangle
@param aFrame - The CGRect of the windows new frame
*/
- (void)setFrame:(CGRect)aFrame
{
@@ -901,6 +953,12 @@ CPTexturedBackgroundWindowMask
var bounds = CGRectMake(0.0, 0.0, CGRectGetWidth(_frame), CGRectGetHeight(_frame));
// During init the initial first responder is set to the contentView
// if it hasn't changed in the mean time we need to update that reference
// to the new contentView
if ([self initialFirstResponder] === _contentView)
[self setInitialFirstResponder:aView];
_contentView = aView;
[_contentView setFrame:[self contentRectForFrameRect:bounds]];
@@ -1111,6 +1169,17 @@ CPTexturedBackgroundWindowMask
[self _updateShadow];
}
/*!
Sets the shadow style of the receiver.
Values are:
<pre>
CPWindowShadowStyleStandard
CPWindowShadowStyleMenu
CPWindowShadowStylePanel
</pre>
@param aStyle - The new shadow style of the receiver.
*/
- (void)setShadowStyle:(unsigned)aStyle
{
_shadowStyle = aStyle;
@@ -1214,17 +1283,17 @@ CPTexturedBackgroundWindowMask
- (BOOL)acceptsFirstResponder
{
return YES;
return NO;
}
- (id)initialFirstResponder
- (CPView)initialFirstResponder
{
return _initialFirstResponder;
}
- (void)setInitialFirstResponder:(id)aResponder
- (void)setInitialFirstResponder:(CPView)aView
{
_initialFirstResponder = aResponder;
_initialFirstResponder = aView;
}
/*!
@@ -1300,6 +1369,7 @@ CPTexturedBackgroundWindowMask
_title = aTitle;
[_windowView setTitle:aTitle];
[_platformWindow _setTitle:_title window:self];
[self _synchronizeMenuBarTitleWithWindowTitle];
}
@@ -1370,6 +1440,23 @@ CPTexturedBackgroundWindowMask
return _isMovableByWindowBackground;
}
/*!
Sets whether the window can be moved.
@param shouldBeMovable \c YES makes the window movable.
*/
- (void)setMovable:(BOOL)shouldBeMovable
{
_isMovable = shouldBeMovable;
}
/*!
Returns \c YES if the window can be moved.
*/
- (void)isMovable
{
return _isMovable;
}
/*!
Sets the window location to be the center of the screen
*/
@@ -1631,7 +1718,7 @@ CPTexturedBackgroundWindowMask
@param aLocation the lower-left corner coordinate of \c anImage
@param mouseOffset the distance from the \c -mouseDown: location and the current location
@param anEvent the \c -mouseDown: that triggered the drag
@param aPastebaord the pasteboard that holds the drag data
@param aPasteboard the pasteboard that holds the drag data
@param aSourceObject the drag operation controller
@param slideBack Whether the image should 'slide back' if the drag is rejected
*/
@@ -1668,7 +1755,7 @@ CPTexturedBackgroundWindowMask
@param aLocation the lower-left corner coordinate of \c aView
@param mouseOffset the distance from the \c -mouseDown: location and the current location
@param anEvent the \c -mouseDown: that triggered the drag
@param aPastebaord the pasteboard that holds the drag data
@param aPasteboard the pasteboard that holds the drag data
@param aSourceObject the drag operation controller
@param slideBack Whether the view should 'slide back' if the drag is rejected
*/
@@ -1819,7 +1906,7 @@ CPTexturedBackgroundWindowMask
}
/*!
Restores a mimized window to it's original size.
Restores a minimized window to it's original size.
*/
- (void)deminiaturize:(id)sender
{
@@ -2332,7 +2419,9 @@ CPTexturedBackgroundWindowMask
// an event going of the responder chain is passed to the input system as a last resort.
// However, the only methods I could get Cocoa to call automatically are
// moveUp: moveDown: moveLeft: moveRight: pageUp: pageDown: and complete:
[self _processKeyboardUIKey:anEvent];
// Unhandled events just travel further up the responder chain _past_ the window.
if (![self _processKeyboardUIKey:anEvent])
[super keyDown:anEvent];
}
/*
@@ -2367,6 +2456,8 @@ CPTexturedBackgroundWindowMask
// The difference is that doCommandBySelector: will also send the action to the window and application delegates.
[[self firstResponder] doCommandBySelector:@selector(complete:)];
}
return NO;
}
- (void)_dirtyKeyViewLoop
@@ -2422,42 +2513,97 @@ CPTexturedBackgroundWindowMask
- (void)selectNextKeyView:(id)sender
{
if (_keyViewLoopIsDirty && [self autorecalculatesKeyViewLoop])
[self recalculateKeyViewLoop];
var nextValidKeyView = nil;
if ([_firstResponder isKindOfClass:[CPView class]])
[self selectKeyViewFollowingView:_firstResponder];
nextValidKeyView = [_firstResponder nextValidKeyView];
if (!nextValidKeyView)
{
var initialFirstResponder = [self initialFirstResponder];
if ([initialFirstResponder acceptsFirstResponder])
nextValidKeyView = initialFirstResponder;
else
nextValidKeyView = [initialFirstResponder nextValidKeyView];
}
[self makeFirstResponder:nextValidKeyView];
}
- (void)selectPreviousKeyView:(id)sender
{
if (_keyViewLoopIsDirty && [self autorecalculatesKeyViewLoop])
[self recalculateKeyViewLoop];
var previousValidKeyView = nil;
if ([_firstResponder isKindOfClass:[CPView class]])
[self selectKeyViewPrecedingView:_firstResponder];
previousValidKeyView = [_firstResponder previousValidKeyView];
if (!previousValidKeyView)
{
var initialFirstResponder = [self initialFirstResponder];
if ([initialFirstResponder acceptsFirstResponder])
previousValidKeyView = initialFirstResponder;
else
previousValidKeyView = [initialFirstResponder previousValidKeyView];
}
[self makeFirstResponder:previousValidKeyView];
}
- (void)selectKeyViewFollowingView:(CPView)aView
{
if (_keyViewLoopIsDirty)
if (_keyViewLoopIsDirty && [self autorecalculatesKeyViewLoop])
[self recalculateKeyViewLoop];
[self makeFirstResponder:[aView nextValidKeyView]];
var nextValidKeyView = [aView nextValidKeyView];
if ([nextValidKeyView isKindOfClass:[CPView class]])
[self makeFirstResponder:nextValidKeyView];
}
- (void)selectKeyViewPrecedingView:(CPView)aView
{
if (_keyViewLoopIsDirty)
if (_keyViewLoopIsDirty && [self autorecalculatesKeyViewLoop])
[self recalculateKeyViewLoop];
[self makeFirstResponder:[aView previousValidKeyView]];
var previousValidKeyView = [aView previousValidKeyView];
if ([previousValidKeyView isKindOfClass:[CPView class]])
[self makeFirstResponder:previousValidKeyView];
}
/*!
Sets the default button for the window.
Note: this method is deprecated use setDefaultButton: instead.
@param aButton - The button that should become default.
*/
- (void)setDefaultButtonCell:(CPButton)aButton
{
[self setDefaultButton:aButton];
}
/*!
Returns the default button of the receiver.
NOTE: This method is deprecated. Use defaultButton instead.
*/
- (CPButton)defaultButtonCell
{
return [self defaultButton];
}
/*!
Sets the default button for the window.
This is equivalent to setting the the key equivalent of the button to "return".
Additionally this will turn your button blue (with the Aristo theme).
@param aButton - The button that should become default.
*/
- (void)setDefaultButton:(CPButton)aButton
{
if (_defaultButton === aButton)
@@ -2472,26 +2618,43 @@ CPTexturedBackgroundWindowMask
[_defaultButton setKeyEquivalent:CPCarriageReturnCharacter];
}
/*!
Returns the default button of the receiver.
*/
- (CPButton)defaultButton
{
return _defaultButton;
}
/*!
Sets the default button key equivalent to "return".
*/
- (void)enableKeyEquivalentForDefaultButton
{
_defaultButtonEnabled = YES;
}
/*!
Sets the default button key equivalent to "return".
NOTE: this method is deprecated. Use enableKeyEquivalentForDefaultButton instead.
*/
- (void)enableKeyEquivalentForDefaultButtonCell
{
[self enableKeyEquivalentForDefaultButton];
}
/*!
Removes the key equivalent for the default button.
*/
- (void)disableKeyEquivalentForDefaultButton
{
_defaultButtonEnabled = NO;
}
/*!
Removes the key equivalent for the default button.
Note: this method is deprecated. Use disableKeyEquivalentForDefaultButton instead.
*/
- (void)disableKeyEquivalentForDefaultButtonCell
{
[self disableKeyEquivalentForDefaultButton];
@@ -2501,9 +2664,11 @@ CPTexturedBackgroundWindowMask
var allViews = function(aWindow)
{
var views = [[aWindow contentView] subviews],
index = 0;
var views = [CPArray arrayWithObject:[aWindow contentView]];
[views addObjectsFromArray:[[aWindow contentView] subviews]];
var index = 0;
for (; index < views.length; ++index)
views = views.concat([views[index] subviews]);
@@ -2603,16 +2768,25 @@ var keyViewComparator = function(lhs, rhs, context)
return _autoresizingMask;
}
/*!
Converts aPoint from the window coordinate system to the global coordinate system.
*/
- (CGPoint)convertBaseToGlobal:(CGPoint)aPoint
{
return [CPPlatform isBrowser] ? [self convertBaseToPlatformWindow:aPoint] : [self convertBaseToScreen:aPoint];
}
/*!
Converts aPoint from the global coordinate system to the window coordinate system.
*/
- (CGPoint)convertGlobalToBase:(CGPoint)aPoint
{
return [CPPlatform isBrowser] ? [self convertPlatformWindowToBase:aPoint] : [self convertScreenToBase:aPoint];
}
/*!
Converts aPoint from the window coordinate system to the coordinate system of the parent platform window.
*/
- (CGPoint)convertBaseToPlatformWindow:(CGPoint)aPoint
{
if ([self _sharesChromeWithPlatformWindow])
@@ -2623,6 +2797,9 @@ var keyViewComparator = function(lhs, rhs, context)
return _CGPointMake(aPoint.x + origin.x, aPoint.y + origin.y);
}
/*!
Converts aPoint from the parent platform window coordinate system to the windows coordinate system.
*/
- (CGPoint)convertPlatformWindowToBase:(CGPoint)aPoint
{
if ([self _sharesChromeWithPlatformWindow])
@@ -2712,12 +2889,19 @@ var keyViewComparator = function(lhs, rhs, context)
@end
@implementation CPWindow (Deprecated)
/*!
Sets the CPWindow to fill the whole browser window.
NOTE: this method has been deprecated in favor of setFullPlatformWindow:
*/
- (void)setFullBridge:(BOOL)shouldBeFullBridge
{
[self setFullPlatformWindow:shouldBeFullBridge];
}
/*!
Returns YES if the window fills the full browser window, otherwise NO.
NOTE: this method has been deprecated in favor of isFullPlatformWindow.
*/
- (BOOL)isFullBridge
{
return [self isFullPlatformWindow];
@@ -2810,8 +2994,10 @@ CPCustomWindowShadowStyle = 3;
@import "_CPWindowView.j"
@import "_CPStandardWindowView.j"
@import "_CPDocModalWindowView.j"
@import "_CPToolTipWindowView.j"
@import "_CPHUDWindowView.j"
@import "_CPBorderlessWindowView.j"
@import "_CPBorderlessBridgeWindowView.j"
@import "_CPAttachedWindowView.j"
@import "CPDragServer.j"
@import "CPView.j"
+300
View File
@@ -0,0 +1,300 @@
/*
* _CPAttachedWindowView.j
* AppKit
*
* Created by Antoine Mercadal
* Copyright 2011 <primalmotion@archipelproject.org>
*
* 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 "_CPWindowView.j"
/*!
@ignore
A custom CPWindowView that manage border and cursor
*/
@implementation _CPAttachedWindowView : _CPWindowView
{
BOOL _mouseDownPressed @accessors(getter=isMouseDownPressed, setter=setMouseDownPressed:);
float _arrowOffsetX @accessors(property=arrowOffsetX);
float _arrowOffsetY @accessors(property=arrowOffsetY);
int _appearance @accessors(property=appearance);
unsigned _preferredEdge @accessors(property=preferredEdge);
CPSize _cursorSize;
}
/*!
Compute the contentView frame from a given window frame
@param aFrameRect the window frame
*/
- (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
{
var contentRect = CGRectMakeCopy(aFrameRect);
// @todo change border art and remove this pixel perfect adaptation
// return CGRectInset(contentRect, 20, 20);
contentRect.origin.x += 18;
contentRect.origin.y += 17;
contentRect.size.width -= 35;
contentRect.size.height -= 37;
return contentRect;
}
/*!
Compute the window frame from a given contentView frame
@param aContentRect the contentView frame
*/
+ (CGRect)frameRectForContentRect:(CGRect)aContentRect
{
var frameRect = CGRectMakeCopy(aContentRect);
// @todo change border art and remove this pixel perfect adaptation
//return CGRectOffset(frameRect, 20, 20);
frameRect.origin.x -= 18;
frameRect.origin.y -= 17;
frameRect.size.width += 35;
frameRect.size.height += 37;
return frameRect;
}
/*!
Initialize the _CPWindowView
*/
- (id)initWithFrame:(CPRect)aFrame styleMask:(unsigned)aStyleMask
{
if (self = [super initWithFrame:aFrame styleMask:aStyleMask])
{
var bundle = [CPBundle bundleForClass:[self class]];
_arrowOffsetX = 0.0;
_arrowOffsetY = 0.0;
// @TODO: make this themable
_useGlowingEffect = YES;
_appearance = CPPopoverAppearanceMinimal;
_cursorSize = CPSizeMake(15, 10);
}
return self;
}
/*!
Hide the cursor
*/
- (void)hideCursor
{
_cursorSize = CPSizeMakeZero();
[self setNeedsDisplay:YES];
}
/*!
Show the cursor
*/
- (void)showCursor
{
_cursorSize = CPSizeMake(15, 10);
[self setNeedsDisplay:YES];
_mouseDownPressed = NO;
}
/*!
Draw the view
*/
- (void)drawRect:(CGRect)aRect
{
[super drawRect:aRect];
var context = [[CPGraphicsContext currentContext] graphicsPort],
radius = 5,
arrowWidth = _cursorSize.width,
arrowHeight = _cursorSize.height,
strokeWidth = 1,
strokeColor,
shadowColor = [[CPColor blackColor] colorWithAlphaComponent:.2],
shadowSize = CGSizeMake(0, 7),
shadowBlur = 15,
gradient;
if (_appearance == CPPopoverAppearanceMinimal)
{
gradient = CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), [(254.0 / 255), (254.0 / 255), (254.0 / 255), 0.93,
(231.0 / 255), (231.0 / 255), (231.0 / 255), 0.93], [0,1], 2);
strokeColor = [CPColor colorWithHexString:@"B8B8B8"];
}
else
{
gradient = CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceRGB(), [(38.0 / 255), (38.0 / 255), (38.0 / 255), 0.93,
(18.0 / 255), (18.0 / 255), (18.0 / 255), 0.93], [0,1], 2);
strokeColor = [CPColor colorWithHexString:@"222222"];
}
// fix rect to take care of stroke and shadow
aRect.origin.x += strokeWidth + shadowBlur;
aRect.origin.y += strokeWidth + (shadowBlur + shadowSize.height / 2);
aRect.size.width -= (strokeWidth * 2) + (shadowBlur * 2);
aRect.size.height -= (strokeWidth * 2) + (shadowBlur * 2 + shadowSize.height);
CGContextSetStrokeColor(context, strokeColor);
CGContextSetLineWidth(context, strokeWidth);
CGContextBeginPath(context);
CGContextSetShadowWithColor(context, shadowSize, shadowBlur, shadowColor);
CGContextDrawLinearGradient(context, gradient, CGPointMake(CPRectGetMidX(aRect), 0.0), CGPointMake(CPRectGetMidX(aRect), aRect.size.height), 0);
var xMin = _CGRectGetMinX(aRect),
xMax = _CGRectGetMaxX(aRect),
yMin = _CGRectGetMinY(aRect),
yMax = _CGRectGetMaxY(aRect);
// draw!
switch (_preferredEdge)
{
case CPMinXEdge:
// origin ne
CGContextMoveToPoint(context, xMin + radius, yMin);
// ne
CGContextAddLineToPoint(context, xMax - radius, yMin);
CGContextAddCurveToPoint(context, xMax - radius, yMin, xMax, yMin, xMax, yMin + radius);
// arrow CPMinXEdge
CGContextAddLineToPoint(context, xMax, (aRect.size.height / 2) + aRect.origin.y + _arrowOffsetY - (arrowHeight - 2));
CGContextAddLineToPoint(context, aRect.size.width + arrowHeight + aRect.origin.x + _arrowOffsetX, (aRect.size.height / 2) + aRect.origin.y + _arrowOffsetY);
CGContextAddLineToPoint(context, aRect.size.width + aRect.origin.x + _arrowOffsetX, (aRect.size.height / 2 + (arrowWidth / 2)) + aRect.origin.y + _arrowOffsetY);
// se
CGContextAddLineToPoint(context, xMax, yMax - radius);
CGContextAddCurveToPoint(context, xMax, yMax - radius, xMax, yMax, xMax - radius, yMax);
// sw
CGContextAddLineToPoint(context, xMin + radius, yMax);
CGContextAddCurveToPoint(context, xMin + radius, yMax, xMin, yMax, xMin, yMax - radius);
// nw
CGContextAddLineToPoint(context, xMin, yMin + radius);
CGContextAddCurveToPoint(context, xMin, yMin + radius, xMin, yMin, xMin + radius, yMin);
break;
case CPMaxXEdge:
// origin ne
CGContextMoveToPoint(context, xMin + radius, yMin);
// ne
CGContextAddLineToPoint(context, xMax - radius, yMin);
CGContextAddCurveToPoint(context, xMax - radius, yMin, xMax, yMin, xMax, yMin + radius);
// se
CGContextAddLineToPoint(context, xMax, yMax - radius);
CGContextAddCurveToPoint(context, xMax, yMax - radius, xMax, yMax, xMax - radius, yMax);
// sw
CGContextAddLineToPoint(context, xMin + radius, yMax);
CGContextAddCurveToPoint(context, xMin + radius, yMax, xMin, yMax, xMin, yMax - radius);
// arrow CPMaxXEdge
CGContextAddLineToPoint(context, xMin, (aRect.size.height / 2 + (arrowWidth / 2) + aRect.origin.y + _arrowOffsetY));
CGContextAddLineToPoint(context, aRect.origin.x - arrowHeight + _arrowOffsetX, (aRect.size.height / 2) + aRect.origin.y + _arrowOffsetY);
CGContextAddLineToPoint(context, aRect.origin.x + _arrowOffsetX, (aRect.size.height / 2 - (arrowWidth / 2) + aRect.origin.y + _arrowOffsetY));
// nw
CGContextAddLineToPoint(context, xMin, yMin + radius);
CGContextAddCurveToPoint(context, xMin, yMin + radius, xMin, yMin, xMin + radius, yMin);
break;
case CPMaxYEdge:
// origin nw
CGContextMoveToPoint(context, xMin, yMin + yMin);
// nw
CGContextAddLineToPoint(context, xMin, yMin + radius);
CGContextAddCurveToPoint(context, xMin, yMin + radius, xMin, yMin, xMin + radius, yMin);
// arrow CPMaxYEdge
CGContextAddLineToPoint(context, (aRect.size.width / 2) + aRect.origin.x + _arrowOffsetX - (arrowWidth / 2), yMin);
CGContextAddLineToPoint(context, (aRect.size.width / 2) + aRect.origin.x + _arrowOffsetX, aRect.origin.y - arrowHeight + _arrowOffsetY);
CGContextAddLineToPoint(context, (aRect.size.width / 2) + (arrowWidth / 2) + aRect.origin.x + _arrowOffsetX, aRect.origin.y + _arrowOffsetY);
// ne
CGContextAddLineToPoint(context, xMax - radius, yMin);
CGContextAddCurveToPoint(context, xMax - radius, yMin, xMax, yMin, xMax, yMin + radius);
// se
CGContextAddLineToPoint(context, xMax, yMax - radius);
CGContextAddCurveToPoint(context, xMax, yMax - radius, xMax, yMax, xMax - radius, yMax);
// sw
CGContextAddLineToPoint(context, xMin + radius, yMax);
CGContextAddCurveToPoint(context, xMin + radius, yMax, xMin, yMax, xMin, yMax - radius);
break;
case CPMinYEdge:
// origin nw
CGContextMoveToPoint(context, xMin, yMin + yMin);
// nw
CGContextAddLineToPoint(context, xMin, yMin + radius);
CGContextAddCurveToPoint(context, xMin, yMin + radius, xMin, yMin, xMin + radius, yMin);
// ne
CGContextAddLineToPoint(context, xMax - radius, yMin);
CGContextAddCurveToPoint(context, xMax - radius, yMin, xMax, yMin, xMax, yMin + radius);
// se
CGContextAddLineToPoint(context, xMax, yMax - radius);
CGContextAddCurveToPoint(context, xMax, yMax - radius, xMax, yMax, xMax - radius, yMax);
// arrow CPMinYEdge
CGContextAddLineToPoint(context, (aRect.size.width / 2) + (arrowWidth / 2) + aRect.origin.x + _arrowOffsetX , yMax);
CGContextAddLineToPoint(context, (aRect.size.width / 2) + aRect.origin.x + _arrowOffsetX, aRect.size.height + aRect.origin.y + arrowHeight + _arrowOffsetY);
CGContextAddLineToPoint(context, (aRect.size.width / 2) - (arrowWidth / 2) + aRect.origin.x + _arrowOffsetX, aRect.size.height + aRect.origin.y + _arrowOffsetY);
// sw
CGContextAddLineToPoint(context, xMin + radius, yMax);
CGContextAddCurveToPoint(context, xMin + radius, yMax, xMin, yMax, xMin, yMax - radius);
break;
default:
// no computed edge means standard rounded rect
CGContextAddPath(context, CGPathWithRoundedRectangleInRect(aRect, radius, radius, YES, YES, YES, YES));
}
CGContextClosePath(context);
//Draw it
CGContextStrokePath(context);
CGContextFillPath(context);
}
- (void)mouseDown:(CPEvent)anEvent
{
_mouseDownPressed = YES;
[super mouseDown:anEvent];
}
- (void)mouseUp:(CPEvent)anEvent
{
_mouseDownPressed = NO;
[super mouseUp:anEvent];
}
@end
@@ -46,31 +46,31 @@ var _CPToolbarViewBackgroundColor = nil;
- (void)tile
{
[super tile];
var theWindow = [self window],
bounds = [self bounds];
[[theWindow contentView] setFrame:CGRectMake(0.0, [self toolbarMaxY], CGRectGetWidth(bounds), CGRectGetHeight(bounds) - [self toolbarMaxY])];
if (![[theWindow toolbar] isVisible])
{
[_toolbarBackgroundView removeFromSuperview];
_toolbarBackgroundView = nil;
return;
}
if (!_toolbarBackgroundView)
{
_toolbarBackgroundView = [[CPView alloc] initWithFrame:CGRectMakeZero()];
[_toolbarBackgroundView setBackgroundColor:[[self class] toolbarBackgroundColor]];
[_toolbarBackgroundView setAutoresizingMask:CPViewWidthSizable];
[self addSubview:_toolbarBackgroundView positioned:CPWindowBelow relativeTo:nil];
}
var frame = CGRectMakeZero(),
toolbarOffset = [self toolbarOffset];
+7 -7
View File
@@ -13,25 +13,25 @@ var _CPStandardWindowViewBodyBackgroundColor = nil;
{
if (!_CPStandardWindowViewBodyBackgroundColor)
_CPStandardWindowViewBodyBackgroundColor = [CPColor colorWithWhite:0.96 alpha:0.9];
return _CPStandardWindowViewBodyBackgroundColor;
return _CPStandardWindowViewBodyBackgroundColor;
}
- (id)initWithFrame:(CPRect)aFrame styleMask:(unsigned)aStyleMask
{
self = [super initWithFrame:aFrame styleMask:aStyleMask];
if (self)
{
var theClass = [self class],
bounds = [self bounds];
_bodyView = [[CPView alloc] initWithFrame:_CGRectMake(0.0, 0.0, _CGRectGetWidth(bounds), _CGRectGetHeight(bounds))];
[_bodyView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
[_bodyView setBackgroundColor:[theClass bodyBackgroundColor]];
[_bodyView setHitTests:NO];
[self addSubview:_bodyView];
var bundle = [CPBundle bundleForClass:[CPWindow class]];
@@ -41,7 +41,7 @@ var _CPStandardWindowViewBodyBackgroundColor = nil;
[self addSubview:_shadowView];
}
return self;
return self;
}
- (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
+2 -2
View File
@@ -106,7 +106,7 @@ var _CPStandardWindowViewBodyBackgroundColor = nil,
_CPStandardWindowViewMinimizeButtonImage = nil,
_CPStandardWindowViewMinimizeButtonHighlightedImage = nil;
var STANDARD_GRADIENT_HEIGHT = 41.0;
var STANDARD_GRADIENT_HEIGHT = 41.0,
STANDARD_TITLEBAR_HEIGHT = 25.0;
@implementation _CPStandardWindowView : _CPWindowView
@@ -342,7 +342,7 @@ var STANDARD_GRADIENT_HEIGHT = 41.0;
if (_minimizeButton)
leftOffset += 19.0;
[_titleField setFrame:CGRectMake(leftOffset, 5.0, width - leftOffset*2.0, CGRectGetHeight([_titleField frame]))];
[_titleField setFrame:CGRectMake(leftOffset, 5.0, width - leftOffset * 2.0, CGRectGetHeight([_titleField frame]))];
[[theWindow contentView] setFrameOrigin:CGPointMake(0.0, CGRectGetMaxY([_dividerView frame]))];
}
+114
View File
@@ -0,0 +1,114 @@
/*
* _CPToolTipWindowView.j
* AppKit
*
* Created by Antoine Mercadal
* Copyright 2011 <primalmotion@archipelproject.org>
*
* 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 "_CPWindowView.j"
@implementation _CPToolTipWindowView : _CPWindowView
{
BOOL _mouseDownPressed @accessors(getter=isMouseDownPressed, setter=setMouseDownPressed:);
unsigned _gravity @accessors(property=gravity);
CPColor _backgroundColor;
CPColor _strokeColor;
}
#pragma mark -
#pragma mark Class methods
/*! compute the contentView frame from a given window frame
@param aFrameRect the window frame
*/
+ (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
{
var contentRect = CGRectMakeCopy(aFrameRect);
contentRect.origin.x += 3;
contentRect.origin.y += 3;
contentRect.size.width -= 6;
contentRect.size.height -= 6;
return contentRect;
}
/*! compute the window frame from a given contentView frame
@param aContentRect the contentView frame
*/
+ (CGRect)frameRectForContentRect:(CGRect)aContentRect
{
var aFrameRect = CGRectMakeCopy(aContentRect);
aFrameRect.origin.x -= 3;
aFrameRect.origin.y -= 3;
aFrameRect.size.width += 6;
aFrameRect.size.height += 6;
return aFrameRect;
}
#pragma mark -
#pragma mark Initialization
- (id)initWithFrame:(CPRect)aFrame styleMask:(unsigned)aStyleMask
{
if (self = [super initWithFrame:aFrame styleMask:aStyleMask])
{
_strokeColor = [CPColor colorWithHexString:@"E3E3E3"];
_backgroundColor = [CPColor colorWithHexString:@"FFFFCA"];
}
return self;
}
#pragma mark -
#pragma mark drawing
- (void)drawRect:(CGRect)aRect
{
[super drawRect:aRect];
var context = [[CPGraphicsContext currentContext] graphicsPort],
radius = 2,
strokeWidth = 1;
CGContextSetStrokeColor(context, _strokeColor);
CGContextSetFillColor(context, _backgroundColor);
CGContextSetLineWidth(context, strokeWidth);
CGContextBeginPath(context);
aRect.origin.x += strokeWidth;
aRect.origin.y += strokeWidth;
aRect.size.width -= strokeWidth * 2;
aRect.size.height -= strokeWidth * 2;
CGContextAddPath(context, CGPathWithRoundedRectangleInRect(aRect, radius, radius, YES, YES, YES, YES));
CGContextClosePath(context);
//Draw it
CGContextStrokePath(context);
CGContextFillPath(context);
}
@end
+5 -2
View File
@@ -111,7 +111,7 @@ var _CPWindowViewResizeIndicatorImage = nil;
return [self trackResizeWithEvent:anEvent];
}
if ([theWindow isMovableByWindowBackground])
if ([theWindow isMovable] && [theWindow isMovableByWindowBackground])
[self trackMoveWithEvent:anEvent];
else
@@ -161,7 +161,7 @@ var _CPWindowViewResizeIndicatorImage = nil;
var minPointY = 0;
if([CPMenu menuBarVisible])
if ([CPMenu menuBarVisible])
minPointY = [[CPApp mainMenu] menuBarHeight];
var restrictedPoint = CGPointMake(0, 0);
@@ -174,6 +174,9 @@ var _CPWindowViewResizeIndicatorImage = nil;
- (void)trackMoveWithEvent:(CPEvent)anEvent
{
if (![[self window] isMovable])
return;
var type = [anEvent type];
if (type === CPLeftMouseUp)
+16 -9
View File
@@ -32,10 +32,15 @@
@ingroup appkit
@class CPWindowController
An instance of a CPWindowController manages a CPWindow. It has methods
that get called when the window is loading, and after the window has loaded. In the
Model-View-Controller method of program design, the CPWindowController would be
considered the 'Controller' and the CPWindow the 'Model.'
An instance of a CPWindowController manages a CPWindow. Windows are typically loaded via a cib,
but they can also manage windows created in code. A CPWindowController can manage a window by
itself or work with AppKits's document-based architecture.
In a Document based app, a CPWindowController instance is created and managed by a CPDocument subclass.
If the CPWindowController is managing a CPWindow created in a cib the \c owner of the CPWindow is this controller.
@note When creating the window programatically (instead of a cib) you should override the \c loadWindow method.\c loadWindow is called the first time the window object is needed. @endnote
*/
@implementation CPWindowController : CPResponder
{
@@ -62,7 +67,7 @@
/*!
Initializes the controller with a window.
@param aWindow the window to control
@return the initialzed window controller
@return the initialized window controller
*/
- (id)initWithWindow:(CPWindow)aWindow
{
@@ -82,7 +87,7 @@
}
/*!
Initializes the controller with a Capppuccino Interface Builder name.
Initializes the controller with a Cappuccino Interface Builder name.
@param aWindowCibName the cib name of the window to control
@return the initialized window controller
*/
@@ -124,7 +129,8 @@
}
/*!
Loads the window
Loads the window. This method should never be called directly. Instead call \c window which will in turn call windowWillLoad and windowDidLoad.
This method should be overwritten if you are creating the view programatically.
*/
- (void)loadWindow
{
@@ -158,7 +164,8 @@
}
/*!
Returns the window this object controls.
Returns the CPWindow the reciever controls.
This will cause \c loadWindow to be called if no window object exists yet.
*/
- (CPWindow)window
{
@@ -377,7 +384,7 @@
}
/*!
Returns the document in the controlled window.
Returns the CPDocument in the controlled window.
*/
- (CPDocument)document
{
+5 -5
View File
@@ -34,11 +34,11 @@
@import "_CPCibWindowTemplate.j"
CPCibOwner = @"CPCibOwner",
CPCibTopLevelObjects = @"CPCibTopLevelObjects",
CPCibReplacementClasses = @"CPCibReplacementClasses",
CPCibOwner = @"CPCibOwner";
CPCibTopLevelObjects = @"CPCibTopLevelObjects";
CPCibReplacementClasses = @"CPCibReplacementClasses";
CPCibExternalObjects = @"CPCibExternalObjects";
var CPCibObjectDataKey = @"CPCibObjectDataKey";
/*!
@@ -87,7 +87,7 @@ var CPCibObjectDataKey = @"CPCibObjectDataKey";
{
if (![aName hasSuffix:@".cib"])
aName = [aName stringByAppendingString:@".cib"];
// If aBundle is nil, use mainBundle, but ONLY for searching for the nib, not for resources later.
self = [self initWithContentsOfURL:[aBundle || [CPBundle mainBundle] pathForResource:aName]];
+2 -2
View File
@@ -64,14 +64,14 @@ var _CPCibConnectorSourceKey = @"_CPCibConnectorSourceKey",
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
if (self)
{
_source = [aCoder decodeObjectForKey:_CPCibConnectorSourceKey];
_destination = [aCoder decodeObjectForKey:_CPCibConnectorDestinationKey];
_label = [aCoder decodeObjectForKey:_CPCibConnectorLabelKey];
}
return self;
}
-4
View File
@@ -47,12 +47,8 @@
// If the destination doesn't respond to this selector, warn but don't die.
if (_destination && ![_destination respondsToSelector:selector])
{
CPLog.warn(@"Could not connect the action " + selector + @" to target of class " + [_destination className]);
return;
}
// Not being able to set the action is a fatal error.
if ([_source respondsToSelector:@selector(setAction:)])
objj_msgSend(_source, @selector(setAction:), selector);
+1 -1
View File
@@ -76,7 +76,7 @@ var CPCibOwner = @"CPCibOwner";
// Path is based solely on anOwner:
var bundle = anOwner ? [CPBundle bundleForClass:[anOwner class]] : [CPBundle mainBundle],
path = [bundle pathForResource:aName];
return [self loadCibFile:path externalNameTable:[CPDictionary dictionaryWithObject:anOwner forKey:CPCibOwner] loadDelegate:aDelegate];
}
+7
View File
@@ -83,7 +83,14 @@ var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey",
if ([aCoder respondsToSelector:@selector(bundle)] &&
(![aCoder respondsToSelector:@selector(awakenCustomResources)] || [aCoder awakenCustomResources]))
if (_className === @"CPImage")
{
if (_resourceName == "CPAddTemplate")
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPButtonBar class]] pathForResource:@"plus_button.png"] size:CGSizeMake(11, 12)];
else if (_resourceName == "CPRemoveTemplate")
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPButtonBar class]] pathForResource:@"minus_button.png"] size:CGSizeMake(11, 4)];
return [[CPImage alloc] initWithContentsOfFile:[[aCoder bundle] pathForResource:_resourceName] size:_properties.valueForKey(@"size")];
}
return self;
}
+3 -3
View File
@@ -12,15 +12,15 @@
- (id)initForReadingWithData:(CPData)data bundle:(CPBundle)aBundle awakenCustomResources:(BOOL)shouldAwakenCustomResources
{
self = [super initForReadingWithData:data];
if (self)
{
_bundle = aBundle;
_awakenCustomResources = shouldAwakenCustomResources;
[self setDelegate:self];
}
return self;
}
+24 -24
View File
@@ -5,19 +5,19 @@
@import "CPWindow.j"
var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinSizeKey",
_CPCibWindowTemplateMaxSizeKey = @"_CPCibWindowTemplateMaxSizeKey",
_CPCibWindowTemplateViewClassKey = @"_CPCibWindowTemplateViewClassKey",
_CPCibWindowTemplateWindowClassKey = @"_CPCibWindowTemplateWindowClassKey",
_CPCibWindowTemplateWindowRectKey = @"_CPCibWindowTemplateWindowRectKey",
_CPCibWindowTemplateWindowStyleMaskKey = @"_CPCibWindowTempatStyleMaskKey",
_CPCibWindowTemplateWindowTitleKey = @"_CPCibWindowTemplateWindowTitleKey",
_CPCibWindowTemplateWindowViewKey = @"_CPCibWindowTemplateWindowViewKey",
var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinSizeKey",
_CPCibWindowTemplateMaxSizeKey = @"_CPCibWindowTemplateMaxSizeKey",
_CPCibWindowTemplateWindowAutorecalculatesKeyViewLoop = @"_CPCibWindowTemplateWindowAutorecalculatesKeyViewLoop";
_CPCibWindowTemplateWindowIsFullPlatformWindowKey = @"_CPCibWindowTemplateWindowIsFullPlatformWindowKey";
_CPCibWindowTemplateViewClassKey = @"_CPCibWindowTemplateViewClassKey",
_CPCibWindowTemplateWindowClassKey = @"_CPCibWindowTemplateWindowClassKey",
_CPCibWindowTemplateWindowRectKey = @"_CPCibWindowTemplateWindowRectKey",
_CPCibWindowTemplateWindowStyleMaskKey = @"_CPCibWindowTempatStyleMaskKey",
_CPCibWindowTemplateWindowTitleKey = @"_CPCibWindowTemplateWindowTitleKey",
_CPCibWindowTemplateWindowViewKey = @"_CPCibWindowTemplateWindowViewKey",
_CPCibWindowTemplateWindowAutorecalculatesKeyViewLoop = @"_CPCibWindowTemplateWindowAutorecalculatesKeyViewLoop",
_CPCibWindowTemplateWindowIsFullPlatformWindowKey = @"_CPCibWindowTemplateWindowIsFullPlatformWindowKey";
@implementation _CPCibWindowTemplate : CPObject
{
@@ -60,27 +60,27 @@ var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinS
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
if (self)
{
if ([aCoder containsValueForKey:_CPCibWindowTemplateMinSizeKey])
_minSize = [aCoder decodeSizeForKey:_CPCibWindowTemplateMinSizeKey];
if ([aCoder containsValueForKey:_CPCibWindowTemplateMaxSizeKey])
_maxSize = [aCoder decodeSizeForKey:_CPCibWindowTemplateMaxSizeKey];
_viewClass = [aCoder decodeObjectForKey:_CPCibWindowTemplateViewClassKey];
_windowClass = [aCoder decodeObjectForKey:_CPCibWindowTemplateWindowClassKey];
_windowRect = [aCoder decodeRectForKey:_CPCibWindowTemplateWindowRectKey];
_windowStyleMask = [aCoder decodeIntForKey:_CPCibWindowTemplateWindowStyleMaskKey];
_windowTitle = [aCoder decodeObjectForKey:_CPCibWindowTemplateWindowTitleKey];
_windowView = [aCoder decodeObjectForKey:_CPCibWindowTemplateWindowViewKey];
_windowAutorecalculatesKeyViewLoop = !![aCoder decodeObjectForKey:_CPCibWindowTemplateWindowAutorecalculatesKeyViewLoop];
_windowIsFullPlatformWindow = !![aCoder decodeObjectForKey:_CPCibWindowTemplateWindowIsFullPlatformWindowKey];
}
return self;
}
@@ -90,13 +90,13 @@ var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinS
[aCoder encodeSize:_minSize forKey:_CPCibWindowTemplateMinSizeKey];
if (_maxSize)
[aCoder encodeSize:_maxSize forKey:_CPCibWindowTemplateMaxSizeKey];
[aCoder encodeObject:_viewClass forKey:_CPCibWindowTemplateViewClassKey];
[aCoder encodeObject:_windowClass forKey:_CPCibWindowTemplateWindowClassKey];
[aCoder encodeRect:_windowRect forKey:_CPCibWindowTemplateWindowRectKey];
[aCoder encodeInt:_windowStyleMask forKey:_CPCibWindowTemplateWindowStyleMaskKey];
[aCoder encodeObject:_windowTitle forKey:_CPCibWindowTemplateWindowTitleKey];
[aCoder encodeObject:_windowView forKey:_CPCibWindowTemplateWindowViewKey];
@@ -126,13 +126,13 @@ var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinS
- (id)_cibInstantiate
{
var windowClass = CPClassFromString([self windowClass]);
/* if (!windowClass)
[NSException raise:NSInvalidArgumentException format:@"Unable to locate NSWindow class %@, using NSWindow",_windowClass];
class=[NSWindow class];*/
var theWindow = [[windowClass alloc] initWithContentRect:_windowRect styleMask:_windowStyleMask];
if (_minSize)
[theWindow setMinSize:_minSize];
if (_maxSize)
@@ -147,7 +147,7 @@ var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinS
[theWindow setContentView:_windowView];
[_windowView setAutoresizesSubviews:YES];
if ([_viewClass isKindOfClass:[CPToolbar class]])
{
[theWindow setToolbar:_viewClass];
+6 -6
View File
@@ -46,10 +46,10 @@
- (id)init
{
self = [super init];
if (self)
_isRemovedOnCompletion = YES;
return self;
}
@@ -130,12 +130,12 @@
@end
/*
*/
@implementation CAPropertyAnimation : CAAnimation
{
CPString _keyPath;
BOOL _isCumulative;
BOOL _isAdditive;
}
@@ -143,9 +143,9 @@
+ (id)animationWithKeyPath:(CPString)aKeyPath
{
var animation = [self animation];
[animation setKeyPath:aKeyPath];
return animation;
}
+5 -5
View File
@@ -37,9 +37,9 @@ if (CPFeatureIsCompatible(CPHTMLCanvasFeature))
CABackingStoreCreate = function()
{
var DOMElement = document.createElement("canvas");
DOMElement.style.position = "absolute";
// FIXME: Consolidate drawImage to support this.
return { context:DOMElement.getContext("2d"), buffer:DOMElement, _image:DOMElement };
}
@@ -47,7 +47,7 @@ CABackingStoreCreate = function()
CABackingStoreSetSize = function(aBackingStore, aSize)
{
var buffer = aBackingStore.buffer;
buffer.width = aSize.width;
buffer.height = aSize.height;
buffer.style.width = PIXEL(aSize.width);
@@ -60,9 +60,9 @@ else
CABackingStoreCreate = function()
{
var context = CGBitmapGraphicsContextCreate();
context.buffer = "";
return { context:context };
}
+4 -4
View File
@@ -33,12 +33,12 @@
{
if (_flashMovie == aFlashMovie)
return;
_flashMovie = aFlashMovie;
_DOMElement.innerHTML = "<object width = \"100%\" height = \"100%\"><param name = \"movie\" value = \"" +
aFlashMovie._fileName +
"\"></param><param name = \"wmode\" value = \"transparent\"></param><embed src = \"" +
aFlashMovie._fileName +
"\"></param><param name = \"wmode\" value = \"transparent\"></param><embed src = \"" +
aFlashMovie._fileName + "\" type = \"application/x-shockwave-flash\" wmode = \"transparent\" width = \"100%\" height = \"100%\"></embed></object>";
}
+156 -151
View File
@@ -64,54 +64,54 @@ var CALayerRegisteredRunLoopUpdates = nil;
@implementation CALayer : CPObject
{
// Modifying the Layer Geometry
CGRect _frame;
CGRect _bounds;
CGPoint _position;
unsigned _zPosition;
CGPoint _anchorPoint;
CGAffineTransform _affineTransform;
CGAffineTransform _sublayerTransform;
CGAffineTransform _sublayerTransformForSublayers;
CGRect _backingStoreFrame;
CGRect _standardBackingStoreFrame;
BOOL _hasSublayerTransform;
BOOL _hasCustomBackingStoreFrame;
// Style Attributes
float _opacity;
BOOL _isHidden;
CPColor _backgroundColor;
// Managing Layer Hierarchy
CALayer _superlayer;
CPMutableArray _sublayers;
// Updating Layer Display
unsigned _runLoopUpdateMask;
BOOL _needsDisplayOnBoundsChange;
// Modifying the Delegate
id _delegate;
BOOL _delegateRespondsToDisplayLayerSelector;
BOOL _delegateRespondsToDrawLayerInContextSelector;
// DOM Implementation
DOMElement _DOMElement;
DOMElement _DOMContentsElement;
id _contents;
CGContext _context;
CPView _owningView;
CGAffineTransform _transformToLayer;
CGAffineTransform _transformFromLayer;
}
@@ -130,14 +130,14 @@ var CALayerRegisteredRunLoopUpdates = nil;
- (id)init
{
self = [super init];
if (self)
{
_frame = CGRectMakeZero();
_backingStoreFrame = CGRectMakeZero();
_standardBackingStoreFrame = CGRectMakeZero();
_bounds = CGRectMakeZero();
_position = CGPointMakeZero();
_zPosition = 0.0;
@@ -147,15 +147,15 @@ var CALayerRegisteredRunLoopUpdates = nil;
_transformToLayer = CGAffineTransformMakeIdentity(); // FIXME? does it matter?
_transformFromLayer = CGAffineTransformMakeIdentity();
_opacity = 1.0;
_isHidden = NO;
_masksToBounds = NO;
_sublayers = [];
_DOMElement = document.createElement("div");
_DOMElement.style.overflow = "visible";
_DOMElement.style.position = "absolute";
_DOMElement.style.visibility = "visible";
@@ -165,7 +165,7 @@ var CALayerRegisteredRunLoopUpdates = nil;
_DOMElement.style.width = "0px";
_DOMElement.style.height = "0px";
}
return self;
}
@@ -182,20 +182,20 @@ var CALayerRegisteredRunLoopUpdates = nil;
var oldOrigin = _bounds.origin;
_bounds = _CGRectMakeCopy(aBounds);
if (_hasSublayerTransform)
_CALayerUpdateSublayerTransformForSublayers(self);
// _hasSublayerTransform == true will handle this for us.
/*else if (!CGPointEqualToPoint(_bounds.origin, oldOrigin))
{
var index = _sublayers.length;
// FIXME: This should climb the layer tree down.
while (index--)
_CALayerRecalculateGeometry(_sublayers[index], CALayerGeometryPositionMask);
}*/
_CALayerRecalculateGeometry(self, CALayerGeometryBoundsMask);
}
@@ -215,9 +215,9 @@ var CALayerRegisteredRunLoopUpdates = nil;
{
if (CGPointEqualToPoint(_position, aPosition))
return;
_position = _CGPointMakeCopy(aPosition);
_CALayerRecalculateGeometry(self, CALayerGeometryPositionMask);
}
@@ -237,9 +237,9 @@ var CALayerRegisteredRunLoopUpdates = nil;
{
if (_zPosition == aZPosition)
return;
_zPosition = aZPosition;
[self registerRunLoopUpdateWithMask:CALayerZPositionUpdateMask];
}
@@ -252,18 +252,18 @@ var CALayerRegisteredRunLoopUpdates = nil;
anAnchorPoint = _CGPointMakeCopy(anAnchorPoint);
anAnchorPoint.x = MIN(1.0, MAX(0.0, anAnchorPoint.x));
anAnchorPoint.y = MIN(1.0, MAX(0.0, anAnchorPoint.y));
if (CGPointEqualToPoint(_anchorPoint, anAnchorPoint))
return;
_anchorPoint = anAnchorPoint;
if (_hasSublayerTransform)
_CALayerUpdateSublayerTransformForSublayers(self);
if (_owningView)
_position = CGPointMake(_CGRectGetWidth(_bounds) * _anchorPoint.x, _CGRectGetHeight(_bounds) * _anchorPoint.y);
_CALayerRecalculateGeometry(self, CALayerGeometryAnchorPointMask);
}
@@ -283,9 +283,9 @@ var CALayerRegisteredRunLoopUpdates = nil;
{
if (CGAffineTransformEqualToTransform(_affineTransform, anAffineTransform))
return;
_affineTransform = _CGAffineTransformMakeCopy(anAffineTransform);
_CALayerRecalculateGeometry(self, CALayerGeometryAffineTransformMask);
}
@@ -307,16 +307,16 @@ var CALayerRegisteredRunLoopUpdates = nil;
return;
var hadSublayerTransform = _hasSublayerTransform;
_sublayerTransform = _CGAffineTransformMakeCopy(anAffineTransform);
_hasSublayerTransform = !_CGAffineTransformIsIdentity(_sublayerTransform);
if (_hasSublayerTransform)
{
_CALayerUpdateSublayerTransformForSublayers(self);
var index = _sublayers.length;
// FIXME: This should climb the layer tree down.
while (index--)
_CALayerRecalculateGeometry(_sublayers[index], CALayerGeometryParentSublayerTransformMask);
@@ -353,23 +353,23 @@ var CALayerRegisteredRunLoopUpdates = nil;
/*!
Returns the layer's frame.
The frame defines the bounding box of the layer: the smallest
possible rectangle that could fit this layer after transform
The frame defines the bounding box of the layer: the smallest
possible rectangle that could fit this layer after transform
properties are applied in superlayer coordinates.
*/
- (CGRect)frame
{
if (!_frame)
_frame = [self convertRect:_bounds toLayer:_superlayer];
return _frame;
}
/*!
The Backing Store Frame specifies the frame of the actual backing
store used to contain this layer. Naturally, by default it is the
same as the frame, however, users can specify their own custom
Backing Store Frame in order to speed up certain operations, such as
store used to contain this layer. Naturally, by default it is the
same as the frame, however, users can specify their own custom
Backing Store Frame in order to speed up certain operations, such as
live transformation.
@return the backing store frame
*/
@@ -385,7 +385,7 @@ var CALayerRegisteredRunLoopUpdates = nil;
- (void)setBackingStoreFrame:(CGRect)aFrame
{
_hasCustomBackingStoreFrame = (aFrame != nil);
if (aFrame == nil)
aFrame = CGRectMakeCopy(_standardBackingStoreFrame);
else
@@ -393,23 +393,23 @@ var CALayerRegisteredRunLoopUpdates = nil;
if (_superlayer)
{
aFrame = [_superlayer convertRect:aFrame toLayer:nil];
var bounds = [_superlayer bounds],
frame = [_superlayer convertRect:bounds toLayer:nil];
aFrame.origin.x -= _CGRectGetMinX(frame);
aFrame.origin.y -= _CGRectGetMinY(frame);
}
else
aFrame = CGRectMakeCopy(aFrame);
}
if (!CGPointEqualToPoint(_backingStoreFrame.origin, aFrame.origin))
[self registerRunLoopUpdateWithMask:CALayerFrameOriginUpdateMask];
if (!CGSizeEqualToSize(_backingStoreFrame.size, aFrame.size))
[self registerRunLoopUpdateWithMask:CALayerFrameSizeUpdateMask];
_backingStoreFrame = aFrame;
}
@@ -431,9 +431,9 @@ var CALayerRegisteredRunLoopUpdates = nil;
{
if (_contents == contents)
return;
_contents = contents;
[self composite];
}
@@ -445,27 +445,32 @@ var CALayerRegisteredRunLoopUpdates = nil;
{
if (USE_BUFFER && !_contents || !_context)
return;
CGContextClearRect(_context, _CGRectMake(0.0, 0.0, _CGRectGetWidth(_backingStoreFrame), _CGRectGetHeight(_backingStoreFrame)));
// Recomposite
var transform = _transformFromLayer;
var transform;
if (_superlayer)
{
var superlayerTransform = _CALayerGetTransform(_superlayer, nil),
superlayerOrigin = CGPointApplyAffineTransform(_superlayer._bounds.origin, superlayerTransform);
transform = CGAffineTransformConcat(transform, superlayerTransform);
transform = CGAffineTransformConcat(_transformFromLayer, superlayerTransform);
transform.tx -= superlayerOrigin.x;
transform.ty -= superlayerOrigin.y;
}
else
// Copy so we don't affect the original.
transform = CGAffineTransformCreateCopy(_transformFromLayer);
transform.tx -= _CGRectGetMinX(_backingStoreFrame);
transform.ty -= _CGRectGetMinY(_backingStoreFrame);
CGContextSaveGState(_context);
CGContextConcatCTM(_context, transform);//_transformFromView);
if (USE_BUFFER)
{
@@ -485,18 +490,18 @@ var CALayerRegisteredRunLoopUpdates = nil;
if (!_context)
{
_context = CGBitmapGraphicsContextCreate();
_DOMContentsElement = _context.DOMElement;
_DOMContentsElement.style.zIndex = -100;
_DOMContentsElement.style.overflow = "hidden";
_DOMContentsElement.style.position = "absolute";
_DOMContentsElement.style.visibility = "visible";
_DOMContentsElement.width = ROUND(_CGRectGetWidth(_backingStoreFrame));
_DOMContentsElement.height = ROUND(_CGRectGetHeight(_backingStoreFrame));
_DOMContentsElement.style.top = "0px";
_DOMContentsElement.style.left = "0px";
_DOMContentsElement.style.width = ROUND(_CGRectGetWidth(_backingStoreFrame)) + "px";
@@ -504,23 +509,23 @@ var CALayerRegisteredRunLoopUpdates = nil;
_DOMElement.appendChild(_DOMContentsElement);
}
if (USE_BUFFER)
{
if (_delegateRespondsToDisplayLayerSelector)
return [_delegate displayInLayer:self];
if (_CGRectGetWidth(_backingStoreFrame) == 0.0 || _CGRectGetHeight(_backingStoreFrame) == 0.0)
return;
if (!_contents)
_contents = CABackingStoreCreate();
CABackingStoreSetSize(_contents, _bounds.size);
[self drawInContext:CABackingStoreGetContext(_contents)];
}
[self composite];
}
@@ -535,7 +540,7 @@ var CALayerRegisteredRunLoopUpdates = nil;
CGContextSetFillColor(aContext, _backgroundColor);
CGContextFillRect(aContext, _bounds);
}
if (_delegateRespondsToDrawLayerInContextSelector)
[_delegate drawLayer:self inContext:aContext];
}
@@ -559,9 +564,9 @@ var CALayerRegisteredRunLoopUpdates = nil;
{
if (_opacity == anOpacity)
return;
_opacity = anOpacity;
_DOMElement.style.opacity = anOpacity;
_DOMElement.style.filter = "alpha(opacity=" + anOpacity * 100 + ")";
}
@@ -600,7 +605,7 @@ var CALayerRegisteredRunLoopUpdates = nil;
{
if (_masksToBounds == masksToBounds)
return;
_masksToBounds = masksToBounds;
_DOMElement.style.overflow = _masksToBounds ? "hidden" : "visible";
}
@@ -612,7 +617,7 @@ var CALayerRegisteredRunLoopUpdates = nil;
- (void)setBackgroundColor:(CPColor)aColor
{
_backgroundColor = aColor;
[self setNeedsDisplay];
}
@@ -665,10 +670,10 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
{
if (_owningView)
[_owningView setLayer:nil];
if (!_superlayer)
return;
_superlayer._DOMElement.removeChild(_DOMElement);
[_superlayer._sublayers removeObject:self];
@@ -684,24 +689,24 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
{
if (!aLayer)
return;
var superlayer = [aLayer superlayer];
if (superlayer == self)
{
var index = [_sublayers indexOfObjectIdenticalTo:aLayer];
if (index == anIndex)
return;
[_sublayers removeObjectAtIndex:index];
if (index < anIndex)
--anIndex;
}
else if (superlayer != nil)
[aLayer removeFromSuperlayer];
ADJUST_CONTENTS_ZINDEX(aLayer);
[_sublayers insertObject:aLayer atIndex:anIndex];
@@ -710,9 +715,9 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
_DOMElement.appendChild(DOM(aLayer));
else
_DOMElement.insertBefore(DOM(aLayer), _sublayers[anIndex + 1]._DOMElement);
aLayer._superlayer = self;
if (self != superlayer)
_CALayerRecalculateGeometry(aLayer, 0xFFFFFFF);
}
@@ -726,7 +731,7 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
- (void)insertSublayer:(CALayer)aLayer below:(CALayer)aSublayer
{
var index = aSublayer ? [_sublayers indexOfObjectIdenticalTo:aSublayer] : 0;
[self insertSublayer:aLayer atIndex:index == CPNotFound ? _sublayers.length : index];
}
@@ -754,16 +759,16 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
{
if (aSublayer == aLayer)
return;
// FIXME: EXCEPTION
if (aSublayer._superlayer != self)
{
alert("EXCEPTION");
return;
}
ADJUST_CONTENTS_ZINDEX(aLayer);
[_sublayers replaceObjectAtIndex:[_sublayers indexOfObjectIdenticalTo:aSublayer] withObject:aLayer];
_DOMElement.replaceChild(DOM(aSublayer), DOM(aLayer));
}
@@ -782,16 +787,16 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
if (mask & CALayerDOMUpdateMask)
_CALayerUpdateDOM(layer, mask);
if (mask & CALayerDisplayUpdateMask)
[layer display];
else if (mask & CALayerFrameSizeUpdateMask || mask & CALayerCompositeUpdateMask)
[layer composite];
layer._runLoopUpdateMask = 0;
}
window.loop= false;
window.loop = false;
CALayerRegisteredRunLoopUpdates = nil;
}
@@ -803,11 +808,11 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
if (CALayerRegisteredRunLoopUpdates == nil)
{
CALayerRegisteredRunLoopUpdates = {};
[[CPRunLoop currentRunLoop] performSelector:@selector(runLoopUpdateLayers)
target:CALayer argument:nil order:0 modes:[CPDefaultRunLoopMode]];
}
_runLoopUpdateMask |= anUpdateMask;
CALayerRegisteredRunLoopUpdates[[self UID]] = self;
}
@@ -846,7 +851,7 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
}
/*!
Marks the specified rectange as needing to be redrawn.
Marks the specified rectangle as needing to be redrawn.
@param aRect the area that needs to be redrawn.
*/
- (void)setNeedsDisplayInRect:(CGRect)aRect
@@ -890,8 +895,8 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
}
/*!
Converts the rectangle from the receier's coordinate system to the specified layer's coordinate system.
@param aRect the rectange to convert
Converts the rectangle from the receiver's coordinate system to the specified layer's coordinate system.
@param aRect the rectangle to convert
@param aLayer the layer coordinate system to convert to
@return the converted rectangle
*/
@@ -919,21 +924,21 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
{
if (_isHidden)
return nil;
var point = CGPointApplyAffineTransform(aPoint, _transformToLayer);
//alert(point.x + " " + point.y);
if (!_CGRectContainsPoint(_bounds, point))
return nil;
var layer = nil,
index = _sublayers.length;
// FIXME: this should take into account zPosition.
while (index--)
if (layer = [_sublayers[index] hitTest:point])
return layer;
return self;
}
@@ -946,12 +951,12 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
{
if (_delegate == aDelegate)
return;
_delegate = aDelegate;
_delegateRespondsToDisplayLayerSelector = [_delegate respondsToSelector:@selector(displayLayer:)];
_delegateRespondsToDrawLayerInContextSelector = [_delegate respondsToSelector:@selector(drawLayer:inContext:)];
if (_delegateRespondsToDisplayLayerSelector || _delegateRespondsToDrawLayerInContextSelector)
[self setNeedsDisplay];
}
@@ -968,15 +973,15 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
- (void)_setOwningView:(CPView)anOwningView
{
_owningView = anOwningView;
if (_owningView)
{
_owningView = anOwningView;
_bounds.size = CGSizeMakeCopy([_owningView bounds].size);
_position = CGPointMake(_CGRectGetWidth(_bounds) * _anchorPoint.x, _CGRectGetHeight(_bounds) * _anchorPoint.y);
}
_CALayerRecalculateGeometry(self, CALayerGeometryPositionMask | CALayerGeometryBoundsMask);
}
@@ -985,7 +990,7 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
{
_bounds.size = CGSizeMakeCopy([_owningView bounds].size);
_position = CGPointMake(_CGRectGetWidth(_bounds) * _anchorPoint.x, _CGRectGetHeight(_bounds) * _anchorPoint.y);
_CALayerRecalculateGeometry(self, CALayerGeometryPositionMask | CALayerGeometryBoundsMask);
}
@@ -993,20 +998,20 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
- (void)_update
{
window.loop = true;
var mask = _runLoopUpdateMask;
if (mask & CALayerDOMUpdateMask)
_CALayerUpdateDOM(self, mask);
if (mask & CALayerDisplayUpdateMask)
[self display];
else if (mask & CALayerFrameSizeUpdateMask || mask & CALayerCompositeUpdateMask)
[self composite];
_runLoopUpdateMask = 0;
window.loop = false;
}
@@ -1018,7 +1023,7 @@ function _CALayerUpdateSublayerTransformForSublayers(aLayer)
anchorPoint = aLayer._anchorPoint,
translateX = _CGRectGetWidth(bounds) * anchorPoint.x,
translateY = _CGRectGetHeight(bounds) * anchorPoint.y;
aLayer._sublayerTransformForSublayers = CGAffineTransformConcat(
CGAffineTransformMakeTranslation(-translateX, -translateY),
CGAffineTransformConcat(aLayer._sublayerTransform,
@@ -1028,27 +1033,27 @@ function _CALayerUpdateSublayerTransformForSublayers(aLayer)
function _CALayerUpdateDOM(aLayer, aMask)
{
var DOMElementStyle = aLayer._DOMElement.style;
if (aMask & CALayerZPositionUpdateMask)
DOMElementStyle.zIndex = aLayer._zPosition;
var frame = aLayer._backingStoreFrame;
if (aMask & CALayerFrameOriginUpdateMask)
{
DOMElementStyle.top = ROUND(_CGRectGetMinY(frame)) + "px";
DOMElementStyle.left = ROUND(_CGRectGetMinX(frame)) + "px";
}
if (aMask & CALayerFrameSizeUpdateMask)
{
var width = MAX(0.0, ROUND(_CGRectGetWidth(frame))),
height = MAX(0.0, ROUND(_CGRectGetHeight(frame))),
DOMContentsElement = aLayer._DOMContentsElement;
DOMElementStyle.width = width + "px";
DOMElementStyle.height = height + "px";
if (DOMContentsElement)
{
DOMContentsElement.width = width;
@@ -1070,7 +1075,7 @@ function _CALayerRecalculateGeometry(aLayer, aGeometryChange)
affineTransform = aLayer._affineTransform,
backingStoreFrameSize = _CGSizeMakeCopy(aLayer._backingStoreFrame),
hasCustomBackingStoreFrame = aLayer._hasCustomBackingStoreFrame;
// Go to anchor, transform, go back to bounds.
aLayer._transformFromLayer = CGAffineTransformConcat(
CGAffineTransformMakeTranslation(-width * anchorPoint.x - _CGRectGetMinX(aLayer._bounds), -height * anchorPoint.y - _CGRectGetMinY(aLayer._bounds)),
@@ -1082,68 +1087,68 @@ function _CALayerRecalculateGeometry(aLayer, aGeometryChange)
// aLayer._transformFromLayer = CGAffineTransformConcat(aLayer._transformFromLayer, superlayer._sublayerTransformForSublayers);
_CGAffineTransformConcatTo(aLayer._transformFromLayer, superlayer._sublayerTransformForSublayers, aLayer._transformFromLayer);
}
aLayer._transformToLayer = CGAffineTransformInvert(aLayer._transformFromLayer);
//aLayer._transformFromLayer.tx = ROUND(aLayer._transformFromLayer.tx);
//aLayer._transformFromLayer.ty = ROUND(aLayer._transformFromLayer.ty);
aLayer._frame = nil;
aLayer._standardBackingStoreFrame = [aLayer convertRect:bounds toLayer:nil];
if (superlayer)
{
var bounds = [superlayer bounds],
frame = [superlayer convertRect:bounds toLayer:nil];
aLayer._standardBackingStoreFrame.origin.x -= _CGRectGetMinX(frame);
aLayer._standardBackingStoreFrame.origin.y -= _CGRectGetMinY(frame);
}
// We used to use CGRectIntegral here, but what we actually want, is the largest integral
// rect that would ever contain this box, since for any width/height, there are 2 (4)
// rect that would ever contain this box, since for any width/height, there are 2 (4)
// possible integral rects for it depending on it's position. It's OK that this is sometimes
// bigger than the "optimal" bounding integral rect since that doesn't change drawing.
var origin = aLayer._standardBackingStoreFrame.origin,
size = aLayer._standardBackingStoreFrame.size;
origin.x = FLOOR(origin.x);
origin.y = FLOOR(origin.y);
size.width = CEIL(size.width) + 1.0;
size.height = CEIL(size.height) + 1.0;
// FIXME: This avoids the central issue that a position change is sometimes a display and sometimes
// a div move, and sometimes both.
// Only use this frame if we don't currently have a custom backing store frame.
if (!hasCustomBackingStoreFrame)
{
var backingStoreFrame = CGRectMakeCopy(aLayer._standardBackingStoreFrame);
// These values get rounded in the DOM, so don't both updating them if they're
// These values get rounded in the DOM, so don't both updating them if they're
// not going to be different after rounding.
if (ROUND(_CGRectGetMinX(backingStoreFrame)) != ROUND(_CGRectGetMinX(aLayer._backingStoreFrame)) ||
ROUND(_CGRectGetMinY(backingStoreFrame)) != ROUND(_CGRectGetMinY(aLayer._backingStoreFrame)))
[aLayer registerRunLoopUpdateWithMask:CALayerFrameOriginUpdateMask];
// Any change in size due to a geometry change is purely due to rounding error.
if ((_CGRectGetWidth(backingStoreFrame) != ROUND(_CGRectGetWidth(aLayer._backingStoreFrame)) ||
_CGRectGetHeight(backingStoreFrame) != ROUND(_CGRectGetHeight(aLayer._backingStoreFrame))))
[aLayer registerRunLoopUpdateWithMask:CALayerFrameSizeUpdateMask];
aLayer._backingStoreFrame = backingStoreFrame;
}
if (aGeometryChange & CALayerGeometryBoundsMask && aLayer._needsDisplayOnBoundsChange)
[aLayer setNeedsDisplay];
// We need to recomposite if we have a custom backing store frame, OR
// We need to recompose if we have a custom backing store frame, OR
// If the change is not solely composed of position and anchor points changes.
// Anchor point and position changes simply move the object, requiring
// Anchor point and position changes simply move the object, requiring
// no re-rendering.
else if (hasCustomBackingStoreFrame || (aGeometryChange & ~(CALayerGeometryPositionMask | CALayerGeometryAnchorPointMask)))
[aLayer setNeedsComposite];
var sublayers = aLayer._sublayers,
index = 0,
count = sublayers.length;
@@ -1155,45 +1160,45 @@ function _CALayerRecalculateGeometry(aLayer, aGeometryChange)
function _CALayerGetTransform(fromLayer, toLayer)
{
var transform = CGAffineTransformMakeIdentity();
if (fromLayer)
{
var layer = fromLayer;
// If we have a fromLayer, "climb up" the layer tree until
// If we have a fromLayer, "climb up" the layer tree until
// we hit the root node or we hit the toLayer.
while (layer && layer != toLayer)
{
var transformFromLayer = layer._transformFromLayer;
//transform = CGAffineTransformConcat(transform, layer._transformFromLayer);
_CGAffineTransformConcatTo(transform, transformFromLayer, transform);
layer = layer._superlayer;
}
// If we hit toLayer, then we're done.
if (layer == toLayer)
return transform;
}
var layers = [],
layer = toLayer;
while (layer)
{
layers.push(layer);
layer = layer._superlayer;
}
var index = layers.length;
while (index--)
{
var transformToLayer = layers[index]._transformToLayer;
_CGAffineTransformConcatTo(transform, transformToLayer, transform);
}
return transform;
}
+4 -4
View File
@@ -45,13 +45,13 @@ var CAMediaNamedTimingFunctions = nil;
if (!CAMediaNamedTimingFunctions)
{
CAMediaNamedTimingFunctions = [CPDictionary dictionary];
[CAMediaNamedTimingFunctions setObject:[CAMediaTimingFunction functionWithControlPoints:0.0 :0.0 :1.0 :1.0] forKey:kCAMediaTimingFunctionLinear];
[CAMediaNamedTimingFunctions setObject:[CAMediaTimingFunction functionWithControlPoints:0.42 :0.0 :1.0 :1.0] forKey:kCAMediaTimingFunctionEaseIn];
[CAMediaNamedTimingFunctions setObject:[CAMediaTimingFunction functionWithControlPoints:0.0 :0.0 :0.58 :1.0] forKey:kCAMediaTimingFunctionEaseOut];
[CAMediaNamedTimingFunctions setObject:[CAMediaTimingFunction functionWithControlPoints:0.42 :0.0 :0.58 :1.0] forKey:kCAMediaTimingFunctionEaseInEaseOut];
}
return [CAMediaNamedTimingFunctions objectForKey:aName];
}
@@ -63,7 +63,7 @@ var CAMediaNamedTimingFunctions = nil;
- (id)initWithControlPoints:(float)c1x :(float)c1y :(float)c2x :(float)c2y
{
self = [super init];
if (self)
{
_c1x = c1x;
@@ -71,7 +71,7 @@ var CAMediaNamedTimingFunctions = nil;
_c2x = c2x;
_c2y = c2y;
}
return self;
}
+2 -2
View File
@@ -65,7 +65,7 @@ function CGAffineTransformMakeRotation(anAngle)
{
var sin = SIN(anAngle),
cos = COS(anAngle);
return _CGAffineTransformMake(cos, sin, -sin, cos, 0.0, 0.0);
}
@@ -133,7 +133,7 @@ function CGRectApplyAffineTransform(aRect, anAffineTransform)
maxX = MAX(topLeft.x, topRight.x, bottomLeft.x, bottomRight.x),
minY = MIN(topLeft.y, topRight.y, bottomLeft.y, bottomRight.y),
maxY = MAX(topLeft.y, topRight.y, bottomLeft.y, bottomRight.y);
return _CGRectMake(minX, minY, (maxX - minX), (maxY - minY));
}
+17 -13
View File
@@ -47,7 +47,7 @@ function CGColorGetConstantColor(aColorName)
}
/*!
This function is for source compatability.
This function is for source compatibility.
*/
function CGColorRetain(aColor)
{
@@ -55,7 +55,7 @@ function CGColorRetain(aColor)
}
/*!
This function is for source compatability.
This function is for source compatibility.
*/
function CGColorRelease()
{
@@ -108,7 +108,7 @@ function CGColorCreateCopy(aColor)
*/
function CGColorCreateGenericGray(gray, alpha)
{
return CGColorCreate(0, [gray, alpha]);
return CGColorCreate(CGColorSpaceCreateDeviceRGB(), [gray, gray, gray, alpha]);
}
/*!
@@ -122,7 +122,7 @@ function CGColorCreateGenericGray(gray, alpha)
*/
function CGColorCreateGenericRGB(red, green, blue, alpha)
{
return CGColorCreate(0, [red, green, blue, alpha]);
return CGColorCreate(CGColorSpaceCreateDeviceRGB(), [red, green, blue, alpha]);
}
/*!
@@ -137,7 +137,8 @@ function CGColorCreateGenericRGB(red, green, blue, alpha)
*/
function CGColorCreateGenericCMYK(cyan, magenta, yellow, black, alpha)
{
return CGColorCreate(0, [cyan, magenta, yellow, black, alpha]);
return CGColorCreate(CGColorSpaceCreateDeviceCMYK(),
[cyan, magenta, yellow, black, alpha]);
}
/*!
@@ -149,19 +150,22 @@ function CGColorCreateGenericCMYK(cyan, magenta, yellow, black, alpha)
*/
function CGColorCreateCopyWithAlpha(aColor, anAlpha)
{
var components = aColor.components;
if (!aColor)
return aColor; // Avoid error null pointer in next line
if (!aColor || anAlpha == components[components.length - 1])
var components = aColor.components.slice();
if (anAlpha == components[components.length - 1])
return aColor;
// set new alpha value now so that a potentially a new cache entry is made and
// not that an existing cache entry is mutated.
components[components.length - 1] = anAlpha;
if (aColor.pattern)
var copy = CGColorCreateWithPattern(aColor.colorspace, aColor.pattern, components);
return CGColorCreateWithPattern(aColor.colorspace, aColor.pattern, components);
else
var copy = CGColorCreate(aColor.colorspace, components);
copy.components[components.length - 1] = anAlpha;
return copy;
return CGColorCreate(aColor.colorspace, components);
}
/*!

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