Compare commits

..
1204 Commits
Author SHA1 Message Date
release 929cd78bae Changed version number to 1.0.0.003 2011-06-24 03:05:51 -05:00
hmalphettes f5961b9e06 remove the web-fragment.xml. it is not used and could be harmful. 2011-06-15 14:42:01 +08:00
Pascal Belloncle 7fb17e9f41 added Gemfile 2011-06-14 14:55:18 -03:00
hmalphettes dd70bdc698 use '/' for development. use the BundleShape to be able to be published by the latest version of tycho eventually 2011-06-13 17:14:35 +08:00
release 59d619d190 Changed version number to 1.0.0.003-SNAPSHOT 2011-06-13 03:31:35 -05:00
release dd160d6bed Changed version number to 1.0.0.002 2011-06-13 03:31:30 -05:00
hmalphettes ae5a2c4164 CARBON-183 and remove harful servlet-3.0 web-fragment.xml. Remove the dependency on buildr4osgi 2011-06-13 16:15:15 +08:00
hmalphettes a939bed8e0 CORE-153 pad the buildnumber 2011-06-13 15:51:15 +08:00
release c686a4384b Changed version number to 1.0.0.2-SNAPSHOT 2011-06-11 13:19:43 -05:00
release 6bb2dd2a16 Changed version number to 1.0.0.1 2011-06-11 13:19:38 -05:00
Pascal Belloncle 2ec574173a correct path for patch in archive 2011-06-10 17:17:00 -07:00
Pascal Belloncle 743feb5360 stupid copy paste typo 2011-06-10 16:52:14 -07:00
Pascal Belloncle bc4dc041e5 Merge branch 'master' of github.com:intalio/cappuccino 2011-06-10 16:37:40 -07:00
Pascal Belloncle 8c8d1ae3d3 osgi build 2011-06-10 16:37:30 -07:00
Aparajita Fishman a9781016be Look for frameworks in the app/Frameworks directory before the install directory. Document framework search path and CPAuxiliaryThemes support in the man page. 2011-06-04 22:53:31 -07:00
Aparajita Fishman 4be0bb3a30 Load userland NS classes from the main bundle as well as frameworks, and temporarily change the class of NSSwapper classes to the target class when calling KVC methods. 2011-06-04 18:03:53 -07:00
Aparajita Fishman a74267e937 Merge remote branch 'refs/remotes/280north/master' 2011-06-04 16:20:50 -07:00
Alexander LjungbergandAparajita Fishman 6dea853ef3 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-04 16:19:59 -07:00
Aparajita Fishman 94df530580 Another overhaul of nib2cib.
- Added support for userland NS classes.
- Added support for auxiliary themes.
- NSView should be writing _themeClass, otherwise custom themed classes do not get the correct _themeClass when unarchived.
- Added support for stored options, this is critical. For example, if you are using custom frameworks, you have to ensure they are loaded during automatic nib2cib'ing that occurs when building an app or using xcodecapp. Stored options makes this easy to do.
- Finally did the right thing and made nib2cib into an Objective-J class.
2011-06-04 16:07:00 -07:00
Aparajita Fishman d038c50531 Added ability to specify bundle, which makes this usable with non-main bundle images. 2011-06-04 12:01:19 -07:00
Aparajita Fishman 83546d58db Tweak language of error message to be clearer, currently it sounds like it was searching in the cib file for the class, not the other way around. 2011-06-04 10:59:49 -07:00
Aparajita Fishman 8de587d4fc Only log the connection info if _source and _destination are defined. Runtime attribute connections do not have both. Correctly show boolean value types as BOOL, not CPNumber. 2011-06-04 10:58:38 -07:00
Aparajita Fishman bd9a6ea150 A few more fixes to support multiple themes. 2011-06-04 10:46:29 -07:00
Aparajita Fishman fe69142567 Merge remote branch 'refs/remotes/aparajita/runtime-attributes'
Conflicts:
	Tools/nib2cib/NSNibConnector.j
2011-06-04 10:39:50 -07:00
Tom Robinson fa0a4d3b56 Fix tests for CI. 2011-06-03 21:15:25 -07:00
Aparajita Fishman 5f85f7bef1 Removed unused variable, fixed typo 2011-06-03 18:08:33 -07: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 397e314cc9 Use Menlo if Consolas is not available 2011-06-01 18:19:49 -07:00
Aparajita Fishman c87d96676c Merge remote branch 'refs/remotes/280north/master' 2011-06-01 12:21:27 -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
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 13d4e36d39 Lost this change in the merge 2011-05-30 23:39:44 -07:00
Aparajita Fishman a5c06c8f27 Merge remote branch 'refs/remotes/280north/master'
Conflicts:
	AppKit/CPTableView.j
2011-05-30 23:37:16 -07:00
Aparajita Fishman 76bdbb660e clickedRow should be -1 initially, remove leftover setTheme. 2011-05-30 23:31:28 -07:00
Aparajita Fishman a7929e6c1e Enable escape as key equivalent. 2011-05-30 23:18:43 -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 b3cbc7e362 Test app and unit test to validate pinned ranges in beginsWith/endsWith predicate comparison. 2011-05-26 14:29:51 -07:00
Aparajita Fishman d6b3efaae8 Pin ranges to valid values. 2011-05-26 13:00:46 -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 33345f65ce 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:15 -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 3fe5ec5d6d Fixed set of keys that can be considered a key equivalent, removed redundant call to performKeyEquivalent, test app 2011-05-22 18:05:08 -07:00
Aparajita Fishman 142b982577 Documentation tweaks 2011-05-22 17:19:06 -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
Aparajita Fishman 147c65b962 On WebKit (at least on Mac), right Command key code is 93, not 91. This was not being interpreted correctly. 2011-05-22 17:06:25 -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
Aparajita Fishman 89dbccd74e Use CPLog instead of console.log 2011-05-20 08:01:22 -07:00
Aparajita Fishman a4647f2b82 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:17 -07:00
Aparajita Fishman 94336ebcbb Merge remote branch 'refs/remotes/280north/master'
Conflicts:
	Tools/Documentation/preprocess/003.make_headers.rb
2011-05-19 23:19:08 -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 5dfa43ce5f Oops, accessor methods weren't being synthesized, removed some cruft 2011-05-19 17:10:26 -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 ff7774976e 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:46:41 -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 a435e54a67 Stupid Uber Glory bundle duplicated the file a few times when stripping whitespace. 2011-05-18 17:32:59 -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 852597f11d 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:15 -07:00
Aparajita Fishman 896f91215e Whitespace cleanup 2011-05-18 16:54:21 -07:00
Aparajita Fishman 806fea9222 Whitespace cleanup 2011-05-18 16:53:51 -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 972bb4100f 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:29:54 -07: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
Aparajita Fishman 6a6b83635f 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:49:52 -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
Aparajita Fishman d8f202fc1f Missed a text substitution, darkened up the method header a bit 2011-05-17 21:11:31 -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
Aparajita Fishman 2322743252 Documentation tweak 2011-05-17 10:51:09 -07:00
Aparajita Fishman 8b3f9c5557 Merge remote branch 'refs/remotes/280north/master'
Conflicts:
	Tools/Documentation/doxygen.css
	Tools/Documentation/processor_setup.sh
2011-05-17 10:48:22 -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
Aparajita Fishman b573daf59b NSColorWell was not setting its enabled state 2011-05-16 11:12:48 -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
Aparajita Fishman 4f8fa778d5 Style cleanup 2011-05-14 14:03:51 -04: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 30d5a7f7a2 Tweak the class list page 2011-05-12 23:15:13 -04:00
Aparajita Fishman 02f61fa413 Lightened up box around method prototype 2011-05-12 16:56:28 -04:00
Aparajita Fishman b01a4436b6 Lightened up box around method prototype 2011-05-12 16:55:32 -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 9ad8f75a08 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:40:19 -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
Aparajita Fishman 2bf9afa97a Whitespace cleanup 2011-05-11 23:58:20 -04:00
Aparajita Fishman 9e892d4eea Added CPMenu -removeAll method, removed unused internal _itemIsHighlighted method, test app 2011-05-11 23:56:01 -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
Aparajita Fishman d2407d1c2a Don't generate XML for docs, updated ThemeDescriptor capp template 2011-05-11 12:18:21 -04:00
Aparajita Fishman 17dc96ad2f Merge remote branch 'refs/remotes/280north/master' 2011-05-11 08:13:33 -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
Aparajita Fishman b3a427ba18 Correct performKeyEquivalent documentation 2011-05-10 19:17:32 -04:00
Aparajita Fishman 4cdefcc2c7 Merge remote branch 'refs/remotes/280north/master' 2011-05-10 11:12:05 -04:00
Alexander Ljungberg 5a2e5a7de3 Fixed CPColor isEqual: for pattern images. 2011-05-09 21:38:32 -04:00
Aparajita Fishman b7c0dcf050 Added textFrame method to locate the text within the view 2011-05-09 21:14:02 -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 fe9573e5b8 Merge branch 'refs/heads/object-union-operators' 2011-05-09 17:12:54 -04:00
Aparajita Fishman 9fcf0258e0 Fix the content inset on CPTextField so there are 2 pixels below and 3 pixels above a text selection. 2011-05-09 17:12:27 -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
Aparajita Fishman e22faa0d79 Added distinctUnionOfObjects and unionOfObjects object operators. 2011-05-09 15:31:12 -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
Aparajita Fishman 175b204bb6 Improvements to the ThemeDescriptor capp template:
- New/improved jake tasks: debug, release, all, clean, clobber, test, test-release, help.
- help task shows comprehensive, formatted documentation for the available tasks.
- BlendKit is automatically symlinked into the Frameworks directory if necessary as part of the build process, so that the showcase will always work.
- User can easily change the build directory by changing one line.
- Fixed incorrect placeholders in main.j.
2011-05-07 13:10:33 -04:00
Aparajita Fishman b126b2946d Revert "Using objects to encapsulate a bit more"
This reverts commit f0a2a91837.
5c10615c9f fixes the root cause,
thus obviating the reverted commit.
2011-05-06 18:04:36 -04:00
Aparajita Fishman fec200c835 Merge remote branch 'refs/remotes/280north/master' 2011-05-06 17:56:00 -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
Aparajita Fishman ea0a47a845 _CPThemeAttribute -setValue should not blow away existing values. 2011-05-06 08:51:17 -04:00
Aparajita Fishman 835d89774a Merge remote branch 'refs/remotes/origin/nib2cib-fix-load-theme' 2011-05-05 15:00:01 -04:00
Aparajita Fishman f0a2a91837 Using objects to encapsulate a bit more 2011-05-05 14:40:19 -04:00
Aparajita Fishman 8614bab724 Merge branch 'master' of git://github.com/280north/cappuccino 2011-05-05 08:07:16 -04:00
Aparajita Fishman 9c181cc9c9 Allow class to be used with +themeForView, fix to image load notification 2011-05-05 08:06:31 -04: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
Aparajita Fishman a0a7b126ab When multiple _CPImageAndTextViews to share a common image, update them all when the image loads. 2011-05-04 10:59:23 -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 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
Aparajita Fishman 78ddc2db70 Automated support for multiple themes and simple theme inheritance 2011-04-29 16:45:00 -04: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
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 e80cbc89b2 Added debug logging, some more samples in AppController 2011-03-28 19:24:13 -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
Aparajita Fishman c0f5ed1f87 Fixed the copyright 2011-03-28 07:50:15 -04:00
Klaas Pieter Annema 42c60913c6 add firstObject method to CPArray 2011-03-28 13:14:25 +02:00
Aparajita Fishman 51a8975f0a Implement support for user defined runtime attributes in nib2cib 2011-03-27 22:14:43 -04: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
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
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
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
Francisco Ryan Tolmasky I 9796f5d5d7 Fix CPPopUpButton menu support.
- Added enumerateObjectsUsingBlock: to CPArray
- Fixed a remaining case of [] being used instead of objectAtIndex: in CPMutableArray.
- Added KVO support for menu items array in menus.
- Changed CPPopUpButton to use KVO to sync up with menu instead of notifications.
- Removed extra menu encoding in CPPopUpButton.
- Removed extra mainMenu object from CPApplication.
- Use setters in CPResponder instead of direct ivar access in initWithCoder:.

Closes #298.
Closes $1059.

Reviewed by me.
2011-01-17 01:31:15 -08: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
Randall Luecke 8720a952b0 Fix for scrollview flashing while uniformly resizing columns. Closes #1075 2011-01-16 00:23:14 -05:00
Randall Luecke bf4724d401 Fix for textfield jumping when textfield wasn't the right size or the vertical alignment was something other than center. 2011-01-15 23:15:55 -05:00
Randall Luecke c73e2e1a91 Fix for nib2cib'd textfields jumping when editing 2011-01-15 21:45:37 -05:00
Randall Luecke 630cd121a6 Typo in docs 2011-01-15 20:40:24 -05:00
Randall Luecke 5d88ffbe66 Merge branch 'decimal' of https://github.com/stevegeek/cappuccino into stevegeek-decimal 2011-01-15 20:32:24 -05:00
Randall Luecke bd5aa1c959 Merge branch 'CPPredicate' of https://github.com/cacaodev/cappuccino into cacaodev-CPPredicate 2011-01-15 18:50:12 -05:00
Stephen Ierodiaconou c65bfd22a2 Use native javascript array for mantissa for big performance increase 2011-01-16 01:47:14 +02:00
Randall Luecke e656e0561b removeTableColumn: on the outlineview shouldn't allow removal of outlineTableColumn per cocoa. 2011-01-15 18:31:41 -05:00
Randall Luecke ddbba22533 Only set the outlineview column if it's the first column added. 2011-01-15 18:10:28 -05:00
Randall Luecke 91b5596034 Merge branch 'cacaodev-CPOutlineView' 2011-01-15 17:59:13 -05:00
Stephen Ierodiaconou e0185a0eff Documentation for CPDecimalNumber 2011-01-15 21:58:47 +02:00
Stephen Ierodiaconou 2fe8845842 CPDecimalString returns NaN for a NaN and Fix Compare of NaNs and Cocoa compatable handling of overflow/underflows when no exception 2011-01-15 19:29:55 +02:00
Stephen Ierodiaconou c02128a1fd Instantiate default number handler lazily and fix CPDecimalNumberHandler initialisers and CPDecimalNumberHandler docs 2011-01-15 18:50:47 +02:00
Stephen Ierodiaconou 27ad98e160 Initialiser fixes and docs
Fix tests for new initialisers
2011-01-15 16:40:11 +02:00
Stephen Ierodiaconou fc746db70f Cocoa compatible constructors for CPDecimals 2011-01-15 16:12:06 +02:00
Stephen Ierodiaconou 6a6256bdb4 CPCoding support for CPDecimalNumber and test 2011-01-15 14:15:31 +02:00
Stephen Ierodiaconou 5a0cfc1595 Make default number hanler file global only and Improvements and optimisations for CPDecimalNumber 2011-01-15 11:49:20 +02:00
Stephen Ierodiaconou 32107ab650 Improvements to CPDecimalNumberHandler including docs and archiving/unarchiving and associated test. 2011-01-15 09:38:31 +02:00
Stephen Ierodiaconou 494f615aaa Merge branch 'master' into imports
Conflicts:
	Foundation/CPScanner.j
2011-01-15 09:11:46 +02:00
Francisco Ryan Tolmasky I 5c2ebd546c Don't include a delegate class entry in Info.plist for nib application templates.
Reviewed by me.
2011-01-14 15:42:23 -08:00
cacaodev 72b8ed2faf CPOutlineView: If nil, set outlineTableColumn when the first column is added.
nib2cib: handle indentationPerLevel when the key is not in the xib.
CPoutlineViewCibTest
2011-01-15 00:39:38 +01:00
Alexander Ljungberg 6b8c85df7c Additional testing for outline view archiving. 2011-01-14 19:59:25 -03:00
Alexander Ljungberg cce4e3ded8 Fixed: manual CPBrowser test's click handler threw an exception. 2011-01-14 14:46:37 -03:00
Alexander Ljungberg 0240c648aa Encode delegate when archiving CPBrowser. 2011-01-14 14:36:57 -03:00
Alexander Ljungberg 6019ff9107 Fixed: archiving 'undefined' would cause an exception. 2011-01-14 14:25:11 -03:00
Alexander Ljungberg c4ee83e4c1 Basic CPBrowser CPCoding support. 2011-01-14 13:34:18 -03:00
Alexander Ljungberg 61b0cbb1af Test CPBrowser data loading. 2011-01-14 12:42:38 -03:00
Alexander Ljungberg af30e96b7b Cleanup. 2011-01-14 12:16:51 -03:00
Alexander Ljungberg b7bdec189a Fixed: when an outline view node was expanded, selections below it would not stick to their items if the newly expanded node also had previously expanded children. 2011-01-14 12:10:52 -03:00
Alexander Ljungberg 2a27a87ae6 Fixed: CPOutlineView could not be archived with CPCoding. Closes #1093.
This fixes the exception "[_CPOutlineViewTableViewDataSource encodeWithCoder:] unrecognized selector sent to instance".
2011-01-13 22:18:05 -03:00
Alexander Ljungberg 31ac84f683 Fix non ASCII codes in documentation. 2011-01-13 20:59:28 -03:00
Alexander Ljungberg c41defe864 Merge branch 'master' of github.com:280north/cappuccino 2011-01-13 20:56:58 -03:00
Alexander Ljungberg 6bc109f7fc Optimised: outline view expandItem:expandChildren:YES sent repeated selection change notifications. 2011-01-13 20:51:43 -03:00
Alexander Ljungberg 2d603df83c Fixed: outline view's collapseItem sent up selection notifications in triplicate, each of them at the wrong time. 2011-01-13 20:03:06 -03:00
Alexander Ljungberg dcf440396d Fixed: the outline view was temporarily inconsistent to outside observers while expanding a node.
In particular, a selection did change notification was sent before the rows the selection referred to had had a chance to be loaded.
2011-01-13 18:57:36 -03:00
Randall Luecke 1dc10440b7 Documentaion of CPObjectController. 2011-01-13 00:57:07 -05:00
Randall Luecke 0ef2557ec3 Documentation of CPArrayController. 2011-01-13 00:30:50 -05:00
Randall Luecke 05e69c85c7 More documentation of the tableview, outlineview, and table columns. Wrapped formatted documenation in <pre> tags and added sample code for using custom dataviews 2011-01-12 23:40:28 -05:00
cacaodev 9c6476615d Allow parsing of functions with multiple arguments like multiply:by:(5,2) or FUNCTION('method:arg:', arg1, arg2)
Added a missing CPDate.j import in CPExpression_function that was causing an 'unknown variable CPDate' error in deploy builds.
Added documentation for +expressionForSubquery:...
Added licence headers with credits.
2011-01-12 18:43:09 +01:00
Randall Luecke b393d0597f If selectedRow no longer exists when numberOfRows change reset it to CPNotFound. Closes #1089. 2011-01-12 11:49:36 -05:00
Francisco Ryan Tolmasky I f69e2e8d8f Merge branch 'master' of github.com:280north/cappuccino 2011-01-12 08:41:26 -08:00
Francisco Ryan Tolmasky I 5fd470acea Fix for adding a js object to a CPArray and associated tests.
Reviewed by me.
2011-01-12 08:41:02 -08:00
Alexander Ljungberg 28e660c295 Merge branch 'master' of github.com:280north/cappuccino 2011-01-12 11:02:33 -03:00
Alexander Ljungberg 9a76b4451f Cleanup. 2011-01-12 10:54:47 -03:00
Alexander Ljungberg b50f955cfd Standardise source file header. 2011-01-12 10:52:35 -03:00
Francisco Ryan Tolmasky I 0aa2e2b298 0.9.0 RC 1.
Reviewed by me.
2011-01-11 16:12:30 -08:00
Francisco Ryan Tolmasky I 1f5ad49591 CPMutableArray fixes and tests.
Reviewed by me.
2011-01-11 15:27:35 -08:00
Francisco Ryan Tolmasky I 3e45c7895c More tests and bug fixes for CPArray family.
Reviewed by me.
2011-01-11 12:08:00 -08:00
Francisco Ryan Tolmasky I 29301f440e Fixed a few bugs in CPArray and added many new tests for CPArray.
Reviewed by me.
2011-01-11 10:12:26 -08:00
Francisco Ryan Tolmasky I 2f86c0d9d2 Slight initWithArray:shouldCopyItems: fix.
Reviewed by me.
2011-01-10 09:21:46 -08:00
Klaas Pieter Annema e7dbd5a5cc add test for CPButton setObjectValue: behavior 2011-01-10 09:32:18 +01:00
Francisco Ryan Tolmasky I 62c00bb7f5 Fix for press removing all files.
Reviewed by me.
2011-01-10 00:19:34 -08:00
Aparajita Fishman 12f0d2a867 Fixes to content-inset bugs introduced by b80c48886a 2011-01-09 19:04:12 -05:00
Francisco Ryan Tolmasky I 5af66b60e1 Better -copy implementations for KVC arrays and sets.
Reviewed by me.
2011-01-09 03:46:29 -08:00
Francisco Ryan Tolmasky I 028a4fe5b2 Merge branch 'CPKeyValueCodingArray-copy' of https://github.com/cacaodev/cappuccino into cacaodev-CPKeyValueCodingArray-copy 2011-01-09 03:29:51 -08:00
Francisco Ryan Tolmasky I fa6e711c2f Merge branch 'master' of github.com:280north/cappuccino 2011-01-09 03:27:46 -08:00
Francisco Ryan Tolmasky I c620c7bf39 Fix for %% being broken in sprintf (minor bugfix for press message showing undefined, larger press bugs remain).
Reviewed by me.
2011-01-09 03:25:59 -08:00
Derek Hammer f3066594fe Tests for Pull Request 1085 2011-01-08 22:12:20 -06:00
Francisco Ryan Tolmasky I 4db1e28677 Merge branch 'trunk' of https://github.com/meelash/cappuccino into meelash-trunk 2011-01-08 15:27:34 -08:00
meelash d6cbc52790 Fix for issue #302 CPTabViewItem _tabView is not set. Closes #302 2011-01-08 15:15:13 -05:00
Alexander Ljungberg 0943065498 Merge branch 'master' of github.com:280north/cappuccino into eventualbuddha-CPTokenField-sendAction-fix
Conflicts:
	AppKit/CPTokenField.j
2011-01-07 18:53:44 -03:00
Alexander Ljungberg 42cc3f309f Manual test for token field action sending. 2011-01-07 18:52:18 -03:00
Alexander Ljungberg 6d7dc24775 Merge branch 'CPTokenField-sendAction-fix' of https://github.com/eventualbuddha/cappuccino into eventualbuddha-CPTokenField-sendAction-fix 2011-01-07 18:14:17 -03:00
Klaas Pieter Annema 8faa17ad33 reset allow mixed state when bound 2011-01-07 15:20:12 +01:00
Klaas Pieter Annema 3d5232b308 give objects a chance to change their binder class
- make every object calling getBinding:forObject: aware of this change
- implement _CPCheckBoxValueBinder to handle binding to the value of a checkbox Closes: #1083
- re-implement CPTextField's behavior for controller markers using the new binder class
- disabled some tests that are not compliant with Cocoa
2011-01-07 14:14:19 +01:00
Klaas Pieter Annema c2bab5b369 fix [CPButton setObjectValue:CPOnState] 2011-01-07 14:14:19 +01:00
Klaas Pieter Annema eee1dcef13 restore the original placeholder when unbinding 2011-01-07 14:14:19 +01:00
Randall Luecke 8254543da7 Fix for scrollColumnToVisisble also scrolling in the Y direction. Also fixed headerview not being scrolled. Closes #1081 2011-01-06 15:22:18 -06:00
Randall Luecke 2028efabc3 Fix for scrollRowToVisible changing the X value instead of just the Y. Closes #1082 2011-01-06 15:08:35 -06:00
Randall Luecke 011c033478 Merge branch 'master' of git://github.com/280north/cappuccino 2011-01-06 14:51:16 -06:00
Randall Luecke 477e9f85be Fix for variable row heights when initial setup of the tableview had zero rows 2011-01-06 14:50:40 -06:00
Ilya Kulakov 0d5ae63013 The isSubsetOfSet looking for objects inside itself instead of provided set 2011-01-07 02:03:11 +06:00
Francisco Ryan Tolmasky I aa60a7b975 Use stubbed out Array methods instead of relying on them existing on the object.
Reviewed by me.
2011-01-06 10:28:24 -08:00
Francisco Ryan Tolmasky I c071569f3c Fix for @import loop when pressing.
Reviewed by me.
2011-01-05 18:24:42 -08:00
Alexander Ljungberg 1d717ffe99 Merge branch 'flllow-outlineview-selection' 2011-01-05 21:30:34 -03:00
Alexander Ljungberg c53fff058b Preserve selection when expanding items in an outline view. 2011-01-05 21:25:57 -03:00
Alexander Ljungberg c836bd48e0 Preserve selection when collapsing items in an outline view.
This fixes the error where if a row was selected below a certain item and that item was collapsed, the row selection would remain fixed in place even while the item it was highlighting moved upwards.
2011-01-05 21:09:19 -03:00
Alexander Ljungberg ec675a5662 Deselect outline view items when their ancestor is collapsed. 2011-01-05 20:41:26 -03:00
Alexander Ljungberg 02e72493ef Unit test outline view data loading and item collapse. 2011-01-05 20:40:30 -03:00
Alexander Ljungberg dd2ad410b8 Cleanup. 2011-01-05 17:45:51 -03:00
cacaodev 92fb183c22 CPKeyValueCodingArray/Set -copy. Fetch all objects through accessors, that's what cocoa does. 2011-01-05 19:21:13 +01:00
Klaas Pieter Annema 46eca09d69 determine sorted column in setSortDescriptors:
Closes #1079
2011-01-05 12:48:19 +01:00
Klaas Pieter Annema f7bc2b6d06 add a description to CPSortDescriptor 2011-01-05 12:47:36 +01:00
Klaas Pieter Annema c87cb4bacd properly fix CPThemeStateNormal behavior
- revert the previous fix
- explicitly check for CPThemeStateNormal in hasThemeState:
- update the test case
2011-01-05 12:30:14 +01:00
Klaas Pieter Annema b6ea6530b7 hasThemeState: always returned no for normal state 2011-01-05 10:44:50 +01:00
Randall Luecke af4e69afc9 Fix for variable row heights with no rows on startup 2011-01-05 01:46:12 -06:00
Randall Luecke a292936d55 Extra bracket. 2011-01-04 23:01:44 -06:00
Randall Luecke a000687a42 Fix for CPArray and _CPJavaScriptArray -copy 2011-01-04 22:59:33 -06:00
Alexander Ljungberg 03aaa89a61 Merge branch 'master' of github.com:280north/cappuccino 2011-01-04 17:02:11 -03:00
Alexander Ljungberg be71d957e1 Fixed: indexOfObject:inSortedRange: searched 1 index too far when a range was applied. 2011-01-04 17:00:48 -03:00
Francisco Ryan Tolmasky I 651970899d Merge branch 'primalmotion-fix-cptabview' 2011-01-04 11:26:01 -08:00
Antoine Mercadal ae67b00c4d remove the change in tabViewItemAtIndex: 2011-01-04 20:06:53 +01:00
Alexander Ljungberg 51848b6cce Merge branch 'master' of github.com:280north/cappuccino 2011-01-04 16:06:25 -03:00
Alexander Ljungberg 8e0b3a5df3 Test indexOfObject:inSortedRange: with out of range insertion point. 2011-01-04 15:38:54 -03:00
Randall Luecke 692c43a3cc Snap columns when we size the last column to fit. 2011-01-04 12:36:57 -06:00
Antoine Mercadal 29430df66d fix small bugs in CPTabView 2011-01-04 19:36:05 +01:00
Alexander Ljungberg 9954a75cdd Fixed array test arrayByReversingArray. More indexOfObject:inSortedRange:... tests. 2011-01-04 15:30:02 -03:00
Alexander Ljungberg 6ee7964fa6 Cleanup. 2011-01-04 13:42:00 -03:00
Ilya KulakovandAlexander Ljungberg db6608571a Refs #1071. indexOfObject:inSortedRange:options:usingComparator is incorrectly implemented.
Add more tests to cover more features of the indexOfObject:inSortedRange:options:usingComparator method
2011-01-04 13:37:06 -03:00
Randall Luecke 76d5051833 Remove unused variable 2011-01-03 20:25:56 -06:00
cacaodevandRandall Luecke 9cdcbb1988 OutlineView should decode a new instance of tableview delegate 2011-01-03 20:24:01 -06:00
Randall Luecke 33882942e4 Documentation of the outlineview and some API fixes. 2011-01-03 20:17:12 -06:00
Randall Luecke 6c2c690504 Remove log 2011-01-03 16:23:43 -06:00
Randall Luecke c78f232e4a Fix for ouline column disclosure button staying in place while resizing 2011-01-03 16:22:28 -06:00
Randall Luecke 5f39046a52 Document setBorderType: for CPScrollView 2011-01-03 15:53:00 -06:00
Randall Luecke fff2be49fc Fix for outline column dragging leaving disclosure indicator in place. 2011-01-03 15:36:19 -06:00
Alexander Ljungberg 95a2b46ae1 Merge branch 'master' of github.com:280north/cappuccino 2011-01-03 16:37:47 -03:00
Alexander Ljungberg 754324d253 Table view documentation fix. 2011-01-03 16:36:26 -03:00
Francisco Ryan Tolmasky I b350b89376 Added some more KVO tests.
Reviewed by me.
2011-01-02 13:16:43 -08:00
Alexander Ljungberg 4445f752f3 Avoid usage of [event keyCode].
Key codes have platform and browser specific behaviours.
2011-01-02 13:15:38 -03:00
Alexander Ljungberg 9e92947b2c Cleanup, fix accidental global in the average operator. 2011-01-02 11:42:40 -03:00
Alexander Ljungberg 92d44b12bd Fixed: a recent change disabled first and last column resizing modes. 2010-12-31 20:56:24 -03:00
Alexander Ljungberg 36c673c660 Whitespace cleanup. 2010-12-31 15:25:39 -03:00
Alexander Ljungberg db509cb72f Merge branch 'master' of github.com:280north/cappuccino 2010-12-31 15:24:09 -03:00
Alexander Ljungberg c0af2af7e7 Merge branch 'master' of https://github.com/Kentzo/cappuccino into Kentzo-master 2010-12-31 15:12:35 -03:00
Alexander Ljungberg 35b2b5263c Test table view inline cell editing in general, and the next fix in particular. 2010-12-31 14:59:24 -03:00
Alexander Ljungberg fa3df44535 Fixed: the text field selectText: message worked significantly differently in unit tests than in the browser.
The message normally makes the text field the first responder, but this did not happen outside of the DOM platform.

Also documented the first responder side effect.
2010-12-31 14:49:03 -03:00
Alexander Ljungberg 08dd7d6951 ASCII fix, cleanup. 2010-12-31 14:18:56 -03:00
Alexander Ljungberg d7316918a3 Refactor test data source in table view test. 2010-12-31 12:56:56 -03:00
Ilya Kulakov 044fc3af69 Refs issue #1607. Make CPTableView the first responder after user is done editing dataview. 2010-12-31 12:07:42 +06:00
Francisco Ryan Tolmasky I d1eb20e7b3 Merge branch 'master' of https://github.com/snaury/cappuccino into snaury-master 2010-12-30 21:49:50 -08:00
Alexander Ljungberg c27edb2475 Various documentation fixes. 2010-12-30 00:06:06 -03:00
Alexander Ljungberg 58d4030133 Brief documentation about using bindings to provide data for a table view. 2010-12-29 23:40:30 -03:00
Alexander Ljungberg e8b1063647 Whitespace cleanup. 2010-12-29 23:17:18 -03:00
Alexander Ljungberg 3caa703ced Bring back testing of HUD style CPAlerts.
This part of the test was temporarily disabled recently due to changes which broke HUD style CPAlerts.
2010-12-29 23:15:22 -03:00
Alexander Ljungberg f7e016a98c Merge branch 'cpalert-fixes' of https://github.com/primalmotion/cappuccino into primalmotion-cpalert-fixes 2010-12-29 23:11:10 -03:00
Randall Luecke 156e9b8e54 Merge branch 'master' of git://github.com/280north/cappuccino 2010-12-29 19:45:36 -06:00
Randall Luecke 7aa00a961a Attached sheets should have a shadow. 2010-12-29 19:45:09 -06:00
Alexey Borzenkov 4678efff72 Fix #1063 [CPDate description] returns incorrect timezone + tests 2010-12-28 23:42:06 +03:00
Klaas Pieter Annema f3b4e7f752 fixes for inline table editing
- make sure the data view is reset to it's no editable state when a textfield is dismissed without editing
- remove a comment (selectText: works now)
2010-12-27 19:48:21 +01:00
Francisco Ryan Tolmasky I e39fa44cdb Fix for typo in new KVC code.
Reviewed by me.
2010-12-27 10:40:27 -08:00
Francisco Ryan Tolmasky I 3fb4d1e4c1 Merge branch 'master' of github.com:280north/cappuccino 2010-12-27 10:38:41 -08:00
Francisco Ryan Tolmasky I 06b8636817 Removed remaining references to isKeyObserved.
Reviewed by me.
2010-12-27 10:38:10 -08:00
Randall Luecke 4b653ee367 in sizeLastColumnToFit make sure we respect min/max widths 2010-12-27 12:05:38 -06:00
Klaas Pieter Annema d2cdd46466 fix a typo in CPTableView 2010-12-27 13:52:50 +01:00
David K. HessandFrancisco Ryan Tolmasky I 2d46fb885d Fix for -nextValidKeyView infinitely looping when no next valid key view.
Closes #1049.

Reviewed by me.
2010-12-27 03:17:52 -08:00
Francisco Ryan Tolmasky I b3e0c4a5d5 Added a FIXME.
Reviewed by me.
2010-12-27 03:05:20 -08:00
Francisco Ryan Tolmasky I ab6609282d Some reorganization.
Reviewed by me.
2010-12-27 03:02:00 -08:00
Francisco Ryan Tolmasky I 6ff21692f1 Fix for incorrectly installing KVO if all the mutation methods aren't implemented.
Reviewed by me.
2010-12-27 02:18:52 -08:00
Randall Luecke f64cc4c655 Bounds errors on rectOfColumn 2010-12-27 01:25:32 -06:00
Randall Luecke e31af96ef9 Made the selection behavior more correct 2010-12-27 00:59:46 -06:00
Randall Luecke a431b34c43 Merge branch 'master' of git://github.com/280north/cappuccino 2010-12-26 17:40:15 -06:00
Randall Luecke 562bb8a878 setIntercellSpacing doesn't update dateviews. Closes #827 2010-12-26 17:39:10 -06:00
Francisco Ryan Tolmasky I 719dbf02d4 Merge branch 'master' of github.com:280north/cappuccino 2010-12-26 15:38:01 -08:00
Francisco Ryan Tolmasky I e2327fcf94 Fix for remaining delegate reference instead of _delegate in CPTabView.
Closes #1061.

Reviewed by me.
2010-12-26 15:36:06 -08:00
Randall Luecke 5a0c8f4a8b Legacy tableviews cibs dont decode properly. Closes #850 2010-12-26 17:31:54 -06:00
Francisco Ryan Tolmasky I 031a380c25 Merge branch 'master' of github.com:280north/cappuccino 2010-12-26 15:27:10 -08:00
Francisco Ryan Tolmasky I 23c4e584d4 Automatically re-validate toolbar items in multi-document windows, and restore removeObjectsInArray: to CPMutableSet.
Reviewed by me.
2010-12-26 15:26:04 -08:00
Randall Luecke 452febd73e Test for uniform column resizing 2010-12-26 17:17:27 -06:00
Randall Luecke 645741aa23 Merge branch 'master' of git://github.com/280north/cappuccino 2010-12-26 16:14:34 -06:00
Randall Luecke 97b141b653 Fixes for uniform column resizing 2010-12-26 13:44:31 -06:00
Francisco Ryan Tolmasky I 67ac778d4c Sight improvement to applyChange: in KVO.
Reviewed by me.
2010-12-26 00:31:14 -08:00
Stephen Ierodiaconou 76b5682234 Missing imports in CPSet+KVO 2010-12-26 10:29:46 +02:00
Francisco Ryan Tolmasky I e45ed19dc7 Fix remaining failing tests and add indexOfObject:inSortedRange:options:usingComparator:, and removed non-standard methods:
- indexOfObject:sortedBySelector:
- indexOfObject:sortedByFunction:
- indexOfObject:sortedByDescriptors:
- indexOfObject:sortedByFunction:context:

Reviewed by me.
2010-12-25 21:10:32 -08:00
Francisco Ryan Tolmasky I f79c2346a5 More test fixes.
Reviewed by me.
2010-12-25 17:05:31 -08:00
Francisco Ryan Tolmasky I e964c60830 Fix a few failing tests, and a bad import.
Reviewed by me.
2010-12-25 16:58:09 -08:00
Francisco Ryan Tolmasky I f8ffb4abbd Small fix and whitespace fix.
Reviewed by me.
2010-12-25 16:38:56 -08:00
Francisco Ryan Tolmasky I 37931f08b5 First pass at CPArray class cluster.
Reviewed by me.
2010-12-25 16:07:30 -08: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
Francisco Ryan Tolmasky I 9b75e37e1f A number of set and array fixes and added tests for unordered accessor pattern in key value coding.
Reviewed by me.
2010-12-25 02:18:02 -08:00
Francisco Ryan Tolmasky I 232f1d008d Added better implementation of valueForKey for indexed accessor pattern and tests for it.
Reviewed by me.
2010-12-25 01:47:18 -08:00
Francisco Ryan Tolmasky I 3947bd65f2 Reimplementation of CPSet as a class-cluster, and better set support for valueForKey:
1. CPSet and CPMutableSet are now abstract super classes that create appropriate concrete subclasses behind the scenes.
2. CPSet subclassers need only implement -count, -member:, and -objectEnumerator.
3. CPMutableSet subclassers need only implement -count, -member:, -objectEnumerator:, -addObject:, and removeObject:.
4. Added more CPSet tests.
5. Added _CPKeyValueCodingSet which subclasses CPSet for set returns in valueForKey:.

Reviewed by me.
2010-12-25 01:01:19 -08:00
Francisco Ryan Tolmasky I 1d39299a7d Fix for missing imports and incorrect variable.
Reviewed by me.
2010-12-24 23:36:53 -08:00
Francisco Ryan Tolmasky I da1389b0b4 Forgot one last typo.
Reviewed by me.
2010-12-24 16:46:17 -08:00
Francisco Ryan Tolmasky I 818c7dac3d Fix for set accessor methods.
Reveiwed by me.
2010-12-24 16:29:40 -08:00
Francisco Ryan Tolmasky I 15b05304cc Cleanup setValue:forKey:.
Reviewed by me.
2010-12-24 13:20:13 -08:00
Francisco Ryan Tolmasky I e33c7f6be4 Initial support for valueForKey: supporting sets and arrays.
Reviewed by me.
2010-12-24 12:42:28 -08:00
Francisco Ryan Tolmasky I d23bf7b927 Some KVC cleanup:
1. Added class_getInstanceVariable to runtime.
2. Changed KVC to rely on class-defined variables vs prototypal ones.
3. Modified KVO code to use public APIs.

Reviewed by me.
2010-12-23 23:46:23 -08:00
Klaas Pieter Annema de1ebe6319 add test case for previous fix 2010-12-22 10:49:02 +01:00
cncolder 3e9e0802f6 Show null placeholder when the value is CPNull. 2010-12-22 15:15:05 +08:00
Randall Luecke b8f9263d18 Fixed some 3am typos in the documentation 2010-12-21 16:55:00 -05:00
Randall Luecke 946cd381a0 Compelete documentation of the tableview and tablecolumns (which the exception of bindins) 2010-12-21 02:29:14 -05:00
Francisco Ryan Tolmasky I 0a49d09878 Merge branch 'new-aristo-theme' of https://github.com/primalmotion/cappuccino into primalmotion-new-aristo-theme 2010-12-20 14:07:12 -08:00
Antoine Mercadal f936277a4d make CPTokenField's token pixel perfect 2010-12-20 21:34:25 +01:00
Antoine Mercadal ac16c5663b fix the frame size of the pulldown button 2010-12-20 21:25:40 +01:00
Francisco Ryan Tolmasky I 83058b01d3 Remove AppKit imports from Foundation.
Bugs filed to deal with associated technologies: #1051 and #1052

Reviewed by me.
2010-12-20 11:14:55 -08:00
Francisco Ryan Tolmasky I 3c8619db5d Merge branch 'fixes' of https://github.com/stevegeek/cappuccino into stevegeek-fixes
Conflicts:
	Foundation/CPValueTransformer.j
2010-12-20 11:13:54 -08:00
Randall Luecke 14226ef69c Merge branch 'master' of git://github.com/280north/cappuccino 2010-12-19 20:19:02 -05:00
Randall Luecke 910691ad4b Capp Lint of tableview 2010-12-19 20:18:36 -05:00
Alexander Ljungberg 115d29b6f8 Fixed: if data source was nil, the table view needlessly warned about no content binding in numberOfRowsInTableView.
A table with a nil data source and no content binding is simply an empty table, or more likely, a table not fully configured yet.
2010-12-19 22:54:29 +01:00
Francisco Ryan Tolmasky I 05ef7c83a8 Merge branch 'CPTokenField-missing-import' of https://github.com/eventualbuddha/cappuccino into eventualbuddha-CPTokenField-missing-import 2010-12-19 12:43:43 -08:00
Francisco Ryan Tolmasky I 2311fb9a6d Merge branch 'master' of github.com:280north/cappuccino 2010-12-19 12:37:46 -08:00
Francisco Ryan Tolmasky I c1b8ec8da1 Some minor style changes and perf improvements.
Reviewed by me.
2010-12-19 12:34:57 -08:00
Randall Luecke a1efd1d024 Merge branch 'master' of git://github.com/280north/cappuccino 2010-12-19 15:33:26 -05:00
Randall Luecke 088b6eac35 Last row of the tableview didn't draw 2010-12-19 15:32:52 -05:00
Francisco Ryan Tolmasky I ea1068c465 Merge branch 'nib2cib-binding-transformer' of https://github.com/cncolder/cappuccino into cncolder-nib2cib-binding-transformer 2010-12-19 12:21:03 -08:00
Brian Donovan 978545af94 Import required CPTableView. 2010-12-19 11:46:13 -08:00
Randall Luecke 86c10e687b Row offset regression fix, removed console.log 2010-12-19 02:06:25 -05:00
Randall Luecke 24ab9f9fdf Merge branch 'master' of git://github.com/280north/cappuccino 2010-12-18 22:32:24 -05:00
Randall Luecke 5d69bbc4ca Fixed several bugs and regressions in the tableview. 2010-12-18 22:31:49 -05:00
Johannes FahrenkrugandFrancisco Ryan Tolmasky I 3c3b7ff61c Addition of applications tests and CPCollectionView selection fix.
Reviewed by me.
2010-12-18 10:34:32 -08:00
cncolder 5a6e266c8d nib2cib binding with buildin transformers support. 2010-12-18 15:02:25 +08:00
Brian Donovan 6f724e34f5 Fix apostrophe typo. 2010-12-17 17:14:58 -08:00
Antoine Mercadal 7cec421419 revert test 2010-12-17 12:55:49 +01:00
Antoine Mercadal 967f541659 change inset for CPTokenField 2010-12-17 12:52:23 +01:00
Antoine Mercadal 6e78d903e0 make only border translucent in disabled state 2010-12-17 12:52:22 +01:00
Antoine Mercadal 03a243fd20 Make CPPopUpButton art pixel perfect 2010-12-17 12:52:22 +01:00
Antoine Mercadal 0b8d3744bb update MainMenu bar art 2010-12-17 12:52:22 +01:00
Antoine Mercadal a0bb3b31a3 adding the art for disabled CPTextField 2010-12-17 12:52:22 +01:00
Antoine Mercadal 1f79402a0a use alpha-ized art.. 2010-12-17 12:52:22 +01:00
Antoine Mercadal f7db4058a8 fix another inset issue 2010-12-17 12:52:22 +01:00
Antoine Mercadal 4d9854695a fix a offset in inset 2010-12-17 12:52:22 +01:00
Antoine Mercadal e90133ebd0 uses the new CPPPopUpButton Aristo art 2010-12-17 12:52:22 +01:00
Antoine Mercadal d4818b5a71 uses the new CPTextField Aristo art 2010-12-17 12:52:21 +01:00
Ross Boucher 68a15c5c7c Be more lenient in documents about strings versus URLs.
Fix a typo in CPTextField.
2010-12-16 17:22:32 -08:00
Francisco Ryan Tolmasky I 42db55fabd Apply Chrome Frame fix across the board.
Reviewed by me.
2010-12-16 14:49:15 -08:00
Francisco Ryan Tolmasky I e6c1dfc51e Merge branch 'google-chrome-frame-support' of https://github.com/eventualbuddha/cappuccino into eventualbuddha-google-chrome-frame-support 2010-12-16 14:24:26 -08:00
Stephen Ierodiaconou 4f3146dc7b Remove unnecessary defines of MIN/MAX/ABS 2010-12-16 20:20:58 +02:00
Francisco Ryan Tolmasky I 4372edb7c4 Fix for remaining reference to objj_standardize_path.
Closes #1040.

Reviewed by me.
2010-12-16 09:51:44 -08:00
Stephen Ierodiaconou d105388d82 Move CPOrderedX to CPObjRuntime only instead of duplicated in CPSortDescriptor 2010-12-16 19:16:38 +02:00
Stephen Ierodiaconou fd812f25a5 Imports additions
Import fixes and clean up

Missing import

Missing imports

Missing import

Remove uncessary comments
2010-12-16 19:16:33 +02:00
Stephen Ierodiaconou 9f5904eaf2 Alphabetical order 2010-12-16 17:34:02 +02:00
Stephen Ierodiaconou d246b19750 Some linting and deprecation error and ivar '_' addition 2010-12-16 17:18:11 +02:00
cncolder 128a3ac4d9 Commit ab083a3b change CPTabView variable names to underscore style. This patch fix nib2cib NSTabView. 2010-12-16 14:19:46 +08:00
Ross Boucher abd908949a Merge branch 'master' of github.com:280north/cappuccino 2010-12-15 15:53:23 -08:00
Ross Boucher ab083a3baf Clean up several flaws in CPTabView:
- should not force empty space above and below, but only where the tabs are
- box should fill frame when no tabs are present
- ivars should be prefixed with underscore
- not sure about the current background color code, may revisit
2010-12-15 15:48:42 -08:00
Alexander Ljungberg 45ee3aa0a3 Merge branch 'master' of github.com:280north/cappuccino 2010-12-15 23:32:16 +01:00
Alexander Ljungberg d587016cc3 Fixed: CPSegmentedControl did not take divider width into account when auto sizing. This resolves the incorrect tab sizes in CPTabView.
If a segmented control was initialised with a zero width and then expanded with setSegmentCount, it would not allocate space for any needed dividers. The more tabs were added the more the segmented control would be undersized. The fix is to automatically adjust the width when dividers are added or removed.
2010-12-15 23:26:31 +01:00
Alexander Ljungberg 8edee4e755 Fix accidental globals, cleanup. 2010-12-15 16:02:50 +01:00
Klaas Pieter Annema 8aeaa6681a implement menuForEvent in CPTableView 2010-12-15 15:30:10 +01:00
Klaas Pieter Annema 8a0a68248c don't check valid row range in dragging code 2010-12-15 15:30:10 +01:00
Alexander Ljungberg 251ba407be Implement CPURL isEqualToURL:. 2010-12-15 11:08:28 +01: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
Alexander Ljungberg bd28d688aa Merge branch 'CPScrollView-home-end-fix' of https://github.com/eventualbuddha/cappuccino into eventualbuddha-CPScrollView-home-end-fix 2010-12-15 01:06:32 +01:00
Alexander Ljungberg 6ab679a725 Optimise _processKeyboardUIKey by only declaring the keys of interest once. 2010-12-15 01:06:02 +01:00
Brian Donovan 6b7d636b0d Follow tolmasky's suggestions.
- Fixes a bug in moveByOffset where we called CGPointMake with a CGPoint.
- Remove _moveToPoint: and just inline it where it was used.
2010-12-14 16:00:20 -08:00
Alexander Ljungberg f72749fbd6 Allow home and end function keys as unqualified key equivalents. Manual test for home and end function keys. 2010-12-15 00:26:42 +01:00
Alexander Ljungberg 9a032a57d0 Merge branch 'CPScrollView-home-end-fix' of https://github.com/eventualbuddha/cappuccino into eventualbuddha-CPScrollView-home-end-fix 2010-12-15 00:12:30 +01:00
Alexander Ljungberg 244ff0d846 Finished unit test based on Cocoa example With And Without Bindings 02. 2010-12-14 23:57:51 +01:00
Alexander Ljungberg c65726fb12 Fixed: CPURL isEqual threw an exception if the argument was not a CPURL. 2010-12-14 23:49:24 +01:00
Alexander Ljungberg 8ef7f07195 Fixed: CPArrayController's addObject and CPArray's insertObject:inArraySortedByDescriptors:.
CPArray insertObject:inArraySortedByDescriptors: now quickly inserts objects at the end of the array if no sort descriptors are specified.

CPArrayController initialises its sort descriptors to an empty array.

Fixed: array controller's addObject added objects to the arranged objects array in a different order than in the content array if no sort descriptor was set.
2010-12-14 23:33:14 +01:00
Alexander Ljungberg 2af2fc31a1 Fixed: archived table views could end up with a nil sort descriptor instead of an empty array. 2010-12-14 21:36:04 +01:00
Brian Donovan 9bf0edb5df Implement CPScrollView scrollToBeginningOfDocument: and scrollToEndOfDocument:.
Also ensures that the home/end DOM keys were properly mapped to their Cocoa equivalents, so that home/end will trigger scrollToBeginningOfDocument:/scrollToEndOfDocument:.
2010-12-14 12:12:25 -08:00
Alexander Ljungberg 53f4baa9ac Fixed: CPArrayController add: and insert: would fail if automaticallyPreparesContent was NO.
This was caused by an unimplemented method in the original adapted from Cocotron CPObjectController.
2010-12-14 20:44:22 +01:00
Alexander Ljungberg 63cc9c4b36 Fixed: nib2cib did not properly transfer the 'isEditable' property for object and array controllers. 2010-12-14 20:28:57 +01:00
Alexander Ljungberg 8b60ef1156 Added nib2cib support for several array controller properties.
The properties in question are declaredKeys, automaticallyPreparesContent and objectClass, from the base object controller class.
2010-12-14 20:28:40 +01:00
Brian Donovan 751a80afb7 Google Chrome Frame doesn't work with duplicate X-UA-Compatible header.
There should only be one X-UA-Compatible header and it should have the chrome=1 part at the end, per http://www.chromium.org/developers/how-tos/chrome-frame-getting-started.

"You may recognize the X-UA-Compatible flag as the same mechanism introduced with IE 8 for controlling the rendering engine that IE uses for a particular page. In cases where GCF is not installed, the values can be combined to control IE's rendering behavior:"

    <meta http-equiv="X-UA-Compatible" content="IE=8,chrome=1">
2010-12-14 10:37:15 -08:00
Alexander Ljungberg f2b2852b76 Allow array controllers as table sources in cibs.
When an array controller is loaded from a cib, the data source may be connected before the bindings are. Hence, we can't check for required data source methods at the time because we do not know if we are using bindings yet. The new behaviour is to only warn when the methods are actually required, which matches Cocoa.
2010-12-14 17:35:34 +01:00
Alexander Ljungberg f36d8224a6 Unit test based on Cocoa example With And Without Bindings 01.
This test exercises loading of an array controller with bindings to a table and a content array, plus various editing actions.
2010-12-14 15:05:30 +01:00
Alexander Ljungberg c5c2a80af9 More unit tests on 01_WithoutBindings. 2010-12-14 13:40:44 +01:00
Alexander Ljungberg b9dfd2a795 Merge branch 'master' of github.com:280north/cappuccino 2010-12-14 12:36:53 +01:00
Alexander Ljungberg b381fe6c27 Cleanup. 2010-12-14 12:36:37 +01:00
Klaas Pieter Annema 003dcface0 make selectedTag accessor public again
This reverts commit cfee75b6e9.
2010-12-13 22:16:06 +01:00
Alexander Ljungberg 0e05f1a8b7 Merge branch 'master' of github.com:280north/cappuccino 2010-12-13 13:39:41 +01:00
Klaas Pieter Annema 5a340804fe remove failing reverse set selected tag test 2010-12-13 10:55:10 +01:00
Klaas Pieter Annema 65f6c35c88 add manual test for CPPopUpButton 2010-12-13 10:44:25 +01:00
Klaas Pieter Annema cfee75b6e9 rename CPPopUpButton selectedTag to _selectedTag 2010-12-13 10:38:23 +01:00
Klaas Pieter Annema 0463af26b3 Merge branch 'CPPopUpButton-selectedTag-binding' of https://github.com/eventualbuddha/cappuccino into eventualbuddha-CPPopUpButton-selectedTag-binding 2010-12-13 10:11:46 +01:00
Francisco Ryan Tolmasky I ced3c2d778 Missing @end in NSMutableDictionary.
Reviewed by me.
2010-12-11 21:51:27 -08:00
Francisco Ryan Tolmasky I 7e4e6932a0 Merge branch 'cpbutton-rounded-hud-support' of https://github.com/primalmotion/cappuccino into primalmotion-cpbutton-rounded-hud-support 2010-12-11 11:47:15 -08:00
Blair DuncanandFrancisco Ryan Tolmasky I 13940c97e7 Manual test for issue 842.
Reviewed by me.
2010-12-11 11:41:15 -08:00
Francisco Ryan Tolmasky I 91d28cbbdd Fix for FireFox plists breaking with text over 4096 bytes.
Closes #842.

Reviewed by me.
2010-12-11 11:29:49 -08:00
Antoine Mercadal adc2d2b513 support for HUD rounded button 2010-12-11 14:34:03 +01:00
Randall Luecke c80116e90d Removed leftover from versioning fixes 2010-12-11 01:01:56 -05:00
Francisco Ryan Tolmasky I f667c39ade Further versioning fix.
Reviewed by me.
2010-12-10 09:04:13 -08:00
Randall Luecke ce0ddb2e1f Test for previous commit 2010-12-10 10:29:59 -05:00
Randall Luecke 3a716c08f8 CPObject -version should be static and zero by default. 2010-12-10 10:01:33 -05:00
Francisco Ryan Tolmasky I d69f46f7ee More capp_linting.
Reviewed by me.
2010-12-09 13:45:29 -08:00
Ross Boucher 3cda75986b Merge branch 'master' of github.com:280north/cappuccino 2010-12-09 13:08:52 -08:00
Francisco Ryan Tolmasky I ffea2de826 Style fixes.
Reviewed by me.
2010-12-09 13:00:52 -08:00
Ross Boucher ac6ccc3257 Merge branch 'master' of https://github.com/dasto/cappuccino into dasto-master
Conflicts:
	Tests/Foundation/CPKeyValueCodingTest.j
2010-12-09 12:59:11 -08:00
Daniel Stolzenberg 29ed8f3116 fixed issues with "CPKeyValueObservingOptionPrior" and "CPKeyValueObservingOptionOld" on dependent keys caused by improper wrapped observation messages 2010-12-09 14:56:55 +01:00
Ross Boucher 3f2dd34ee5 We should be using UID not hash 2010-12-08 16:43:45 -08:00
Ross Boucher df7c8bf508 Remove unwanted global. 2010-12-08 16:11:25 -08:00
Ross Boucher 1e2fdc3e1b Remove tabs; Update some of the toll free bridging code. 2010-12-08 15:44:28 -08:00
Ross Boucher 901f3fe63b Merge branch 'nib2cib-bindings-options' of https://github.com/cacaodev/cappuccino into cacaodev-nib2cib-bindings-options 2010-12-08 14:11:23 -08:00
Ross Boucher a767d2199d Merge branch 'tollfreefix' of https://github.com/hammerdr/cappuccino into hammerdr-tollfreefix 2010-12-08 13:35:22 -08:00
Ross Boucher ceb4432b49 Add a round button to the aristo showcase 2010-12-08 13:32:04 -08:00
Ross Boucher b80c48886a Merge branch 'cpbutton-rounded-bezel-style-support' of https://github.com/primalmotion/cappuccino into primalmotion-cpbutton-rounded-bezel-style-support
Conflicts:
	AppKit/Themes/Aristo/ThemeDescriptors.j
2010-12-08 13:23:14 -08:00
Brian Donovan 55121d501b Call will/didChange manually since this isn't a setter. 2010-12-08 07:38:10 -08:00
Brian Donovan 2c0c8b59a2 Fix documentation typo. 2010-12-07 11:44:48 -08:00
Brian Donovan 788419d64c NSPopUpButton has no public -setSelectedTag, so make it private. 2010-12-07 07:23:50 -08:00
Brian Donovan 735a38d134 NSPopUpButton has no CPValueBinding, use @"selectedIndex". 2010-12-07 07:23:30 -08:00
Francisco Ryan Tolmasky I 8d80903cf2 Merge branch 'CPFontManager-fix' of https://github.com/aparajita/cappuccino into aparajita-CPFontManager-fix 2010-12-06 11:46:52 -08:00
Aparajita Fishman 432c98f5f7 Fix variable name 2010-12-06 14:05:18 -05:00
Klaas Pieter Annema f7495155af Merge branch 'issue702' of https://github.com/stevegeek/cappuccino into stevegeek-issue702 2010-12-06 09:47:08 +01:00
Francisco Ryan Tolmasky I c2ee9a9a5e Fix for rows not showing up in tablviews that were not directly in scrollviews.
Reviewed by Randy.
2010-12-04 18:52:46 -08:00
Francisco Ryan Tolmasky I 71bbd85ba4 Fix for ctrl not being interpreted as command in Linux.
Reviewed by me.
2010-12-04 11:12:28 -08:00
Francisco Ryan Tolmasky I 3776a7bee1 Fix for invisible toolbar items sending their associated menu item as the sender for their actions.
Reviewed by me.
2010-12-04 10:43:34 -08:00
Francisco Ryan Tolmasky I fb51a0f892 Merge branch 'CPMenu-menuWillOpen-fix' of https://github.com/eventualbuddha/cappuccino into eventualbuddha-CPMenu-menuWillOpen-fix 2010-12-04 09:46:22 -08:00
Francisco Ryan Tolmasky I 2d74d9fa92 Slight style fix.
Reviewed by me.
2010-12-04 09:43:35 -08:00
Francisco Ryan Tolmasky I 2014f47046 Merge branch 'master' of github.com:280north/cappuccino 2010-12-04 09:42:56 -08:00
Brian Donovan 79c2edca2d Allow binding to CPPopUpButton's selectedTag. 2010-12-03 16:12:22 -08:00
Klaas Pieter Annema 175f1a9acd add support for windows in CPViewAnimation 2010-12-03 15:08:53 +01:00
Mike Fellows 18e943a65b Expand the KeyEquivalent manual test to include tests for the keys allowed without Cmd/Ctrl modifier. Also include an additional check that each button's callback is being called. 2010-12-03 02:06:04 -08:00
Francisco Ryan Tolmasky I 20f36eaa9a Added platform windows manual test.
Reviewed by me.
2010-12-02 18:41:00 -08:00
Francisco Ryan Tolmasky I 6cbff694ab Fix for CPTextField not found in tests.
Reviewed by me.
2010-12-02 17:20:35 -08:00
Randall Luecke 54e106bb14 Merge branch 'master' of git://github.com/280north/cappuccino
Conflicts:
	AppKit/CPTableView.j
2010-12-02 19:51:40 -05:00
Randall Luecke 3d1992440b Fix drag and drop bug 2010-12-02 19:50:55 -05:00
Francisco Ryan Tolmasky I 1cbaea0e3d Further capp_linting - removing accidental global.
Reviewed by me.
2010-12-02 12:11:57 -08:00
Francisco Ryan Tolmasky I 400bdb5103 Further capp_linting.
Reviewed by me.
2010-12-02 11:44:42 -08:00
Francisco Tolmasky dd560fb78c capp_lint CPAnimation.j.
Reviewed by me.
2010-12-02 10:38:51 -08:00
Ross Boucher e71cbfbde2 Need to re-examine this.
Revert "Make @accessors generating code with static type. Not id only. This is useful when check ivar infomation from class_copyMethodList(YourClass)."

This reverts commit c713a3fb25.
2010-12-02 10:06:10 -08:00
Klaas Pieter Annema eb6c103396 Merge branch 'fixes' of https://github.com/MCF/cappuccino into MCF-fixes 2010-12-02 10:58:14 +01:00
Klaas Pieter Annema 45c585e5c2 fix CPViewAnimation invalid dictionary key strings 2010-12-02 10:54:27 +01:00
Francisco Ryan Tolmasky I 0ab92c77bd More capp_linting.
Reviewed by me.
2010-12-01 22:57:57 -08:00
Francisco Ryan Tolmasky I 2d1fd1b3a5 Merge branch 'master' of github.com:280north/cappuccino 2010-12-01 20:40:55 -08:00
Derek Hammer d4d831b9ac Fixing a bug caused by the function inline. 2010-12-01 20:12:12 -08:00
cncolderandRoss Boucher c713a3fb25 Make @accessors generating code with static type. Not id only. This is useful when check ivar infomation from class_copyMethodList(YourClass). 2010-12-01 19:16:12 -08:00
Francisco Ryan Tolmasky I ff60125183 Some capp_linting.
Reviewed by me.
2010-12-01 11:04:17 -08:00
Klaas Pieter Annema 94d28a2593 Merge branch 'cacaodev-CPSearchField' 2010-12-01 10:35:51 +01:00
cacaodevandKlaas Pieter Annema 43f8b50ef7 revert _searchMenuTemplate -> searchMenuTemplate 2010-12-01 10:35:25 +01:00
cacaodevandKlaas Pieter Annema 7c098753cf CPSearchField:
- Fix recentAutosaveName decoding (setter was needed)
- Fix a bug where 2 search fields in the same app would receive the same recentSearches update when recentAutosaveName set.
- Update recentAutosaveName to use the new CPUserDefaults class instead of CPCookie.
- searchMenuTemplate nib2cib decoding. searchMenutemplate is just an outlet, it's automatically connected.
- Removed CPSearchFieldSeparatorItemTag
- Updated Test app with a nib2cibed search field. Ability to set some options for the regular search field.
- Style and white space.
2010-12-01 10:35:25 +01:00
Stephen Ierodiaconou b46d283dc4 Closes 702: CPBezierPath stroke calls CGContextClosePath 2010-12-01 09:45:46 +02:00
Mike Fellows f9639eb695 Add the space key as an allowable key equivalent 2010-11-30 23:09:02 -08:00
Brian Donovan 9fc0006316 Fix copy-paste error in calling the menuDidOpen: delegate method. 2010-11-30 17:58:26 -08:00
Klaas Pieter Annema a51672cc82 use charAt in CPDecimal, IE doesn't support [] 2010-11-30 16:05:32 +01:00
Klaas Pieter Annema 32decc31db CGContext should close path after fill or stroke 2010-11-29 12:47:38 +01:00
Klaas Pieter Annema 14d9aac98b add the test project used for the bindings fix 2010-11-29 09:49:58 +01:00
Randall Luecke 327962bc01 Fix for intercellSpacing reference and fix for the outlineview... 2010-11-28 13:32:30 -05:00
Randall Luecke 4197bbe73c Fixed some intercell spacing issues 2010-11-27 17:04:10 -05:00
Randall Luecke e3ef20eec3 Fixed up the variable row height test. 2010-11-27 16:48:08 -05:00
Randall Luecke 8ddb80fca2 Rewrote background color drawing code. 2010-11-27 16:45:59 -05:00
Randall Luecke b8eb72f823 Fixes for drag and drop with variable row heights. 2010-11-27 13:19:51 -05:00
Randall Luecke 9003177bb7 Added more variable row height tabletests 2010-11-27 04:04:21 -05:00
Randall Luecke 591142ba84 Some clean up 2010-11-27 03:57:02 -05:00
Randall Luecke 7b4f7f75b0 Made variable rows actually work... 2010-11-27 02:47:15 -05:00
Randall Luecke 31b2cb35f7 Fix syntax errors causing the build to break 2010-11-27 01:09:24 -05:00
Randall Luecke 20eb2a9fb0 instance variable initialized twice from merge 2010-11-27 00:16:27 -05:00
Randall Luecke 37d9bff77f Merge branch 'master' into tableview-variable
Conflicts:
	AppKit/CPTableView.j
2010-11-26 17:44:37 -05:00
Alexander Ljungberg f3f0bf3524 Unit test based on Cocoa example With And Without Bindings 01. 2010-11-26 17:12:46 -03:00
Alexander Ljungberg b9ca57a921 Merge branch 'master' of github.com:280north/cappuccino 2010-11-26 15:57:48 -03:00
Alexander Ljungberg 04546e39a5 Missing semicolon, indentation. 2010-11-26 15:57:04 -03:00
Alexander Ljungberg e6cf98f743 Fixed: [tableview selectedRow] returned nil right after awakening from a cib.
The correct response is CPNotFound.
2010-11-26 15:53:14 -03:00
Alexander Ljungberg a528a503d3 Typo fix. 2010-11-26 13:37:58 -03:00
Klaas Pieter Annema 8345788e59 disable value caching in CPControllerSelectionProxy
More information here http://groups.google.com/group/objectivej-dev/browse_thread/thread/c100f16095073332.
2010-11-24 14:27:59 +01:00
Klaas Pieter Annema 21c2b8f74a trigger notification for correct key path in _CPObservationProxy
Previously _CPObservationProxy would only trigger notifications for the key path it was created with. For example a notification for department would be forwarded to the controller and observer as a notification on department.name because that was the key path the observation proxy was created for.
2010-11-24 14:21:19 +01:00
Brian Donovan 69c004093d CPTokenField did not send its action on end edit.
Also fixes that the CPNotification sent out was CPControlTextDidBeginEditingNotification, not CPControlTextDidEndEditingNotification.
2010-11-23 10:47:59 -08:00
cacaodev 5bec411bdc Fix for nib2cibing bindings options. 2010-11-23 19:38:03 +01:00
Klaas Pieter Annema 34339fbcd9 several bindings / KVC fixes
- setValue:forKeyPath will now get call setValue:forKeyPath again on the value of the first part of the key path
- override valueForKeyPath: and valueForKey: in CPObjectController's CPControllerSelectionProxy to return controller markers when appropriate
- override setValue:forKeyPath: and setValue:forKey: in CPObjectController's CPControllerSelectionProxy to bypass possible controller markers

This commit also removes previous hacks for compound paths and adds test cases for the errors. All this is related to issue #967.
2010-11-23 14:18:22 +01:00
Klaas Pieter Annema b49dc87a86 Merge branch 'fix-967' 2010-11-23 12:16:57 +01:00
Klaas Pieter Annema 535d6c9dc5 make setValue:forKey: handle controller markers 2010-11-23 12:15:53 +01:00
Klaas Pieter Annema 221fad6c3e improve _setCurrentValueIsPlaceholder logic 2010-11-23 12:03:00 +01:00
Klaas Pieter Annema aeb3873f3c fix valueForKeyPath: attempting to call valueForKey: on controller markers 2010-11-23 11:56:46 +01:00
Randall Luecke 4f6c83cb3a Fix for setFont: not working in the table header because of the new theme stuff. 2010-11-23 01:20:38 -05:00
Randall Luecke 2ba5cffe44 More variable row height stuff. 2010-11-23 01:15:47 -05:00
Klaas Pieter Annema 1e85a054ac better fix for long key paths
The previous fix for issue #967 would only work if there was only one object observing a compound key path like selection.customer.name.
2010-11-22 19:13:20 +01:00
Klaas Pieter Annema ca60e50128 small bindings fix in CPObjectController
CPObjectController would attempt to remove observations from the new selection in stead of the old selection. This would throw an error when binding to longer compound key paths like selection.customer.name

Fixes #967
2010-11-22 18:10:34 +01:00
Klaas Pieter Annema 70c13a7588 style cleanup in CPObjectController 2010-11-22 18:10:28 +01:00
Alexander Ljungberg 6653bab492 Cleanup. 2010-11-19 13:08:55 -03:00
Alexander Ljungberg 741c235f08 Fix strange cib loading path caused by non-bundliness of Tests/AppKit. 2010-11-19 13:04:59 -03:00
Alexander Ljungberg 70bc3557b4 Simplify. 2010-11-19 00:38:34 -03:00
Alexander Ljungberg 7509e5c99b Bindings test case based on Cocoa example Simple Bindings Adoption 03.
In this test the bindings and controller are entirely configured in IB. Note: the path to the cib file is a little strange.
2010-11-19 00:23:27 -03:00
Alexander Ljungberg 5a2c401e05 Cleanup. 2010-11-19 00:07:37 -03:00
Alexander Ljungberg 75427973f0 More bindings nib2cib fixes. 2010-11-19 00:06:55 -03:00
Ross Boucher 63d5c442a3 Bug fixes. 2010-11-18 16:52:41 -08:00
Ross Boucher 45f74386b8 Add bindings support to nib2cib 2010-11-18 15:52:54 -08:00
Daniel Brajkovic 6093530175 Added some documentation to CPButton.j 2010-11-18 13:18:01 -06:00
Daniel Brajkovic 6bd064f289 Fixed errors in the incompatibility CPException reasons. For example -setHeaderView instead of setHeaderCell. 2010-11-18 12:33:17 -06:00
Alexander Ljungberg 31d57b0c37 Optimise table view selection notification.
Before the table view would send a CPTableViewSelectionDidChangeNotification whenever the number of rows in the table decreased, regardless of if any selected rows actually became deselected. This could be a needless performance drain in the common case where other program components update and reload on selection changes in a table or outline view.
2010-11-18 15:00:46 -03:00
Alexander Ljungberg 22a185b52e Fixed CPTableViewTest which was both broken and unfinished. 2010-11-18 14:09:18 -03:00
Alexander Ljungberg 0067bd0d16 Browser test for CPSound. 2010-11-18 11:54:05 -03:00
Alexander Ljungberg 6521202e68 Add CPSound to AppKit. 2010-11-18 11:53:37 -03:00
Alexander Ljungberg 67e87c7367 Add missing semicolons, clean up. 2010-11-18 11:23:13 -03:00
Alexander Ljungberg a4eeb91290 Merge branch 'CPSound' of https://github.com/primalmotion/cappuccino into primalmotion-CPSound 2010-11-18 11:13:13 -03:00
Antoine Mercadal c0b1322c77 remove stupid test 2010-11-18 12:14:19 +01:00
Antoine Mercadal 3c18282510 add support for theme state rounded 2010-11-18 12:07:44 +01:00
Randall Luecke 55674e31ea Initial work on variable row heights. No drawing support at all yet. 2010-11-18 01:22:51 -05:00
Alexander Ljungberg 39a69b6850 Bindings test case based on Cocoa example Simple Bindings Adoption 02. 2010-11-18 00:06:46 -03:00
Alexander Ljungberg 2b8a5d6176 Clean up and simplify. 2010-11-17 23:54:48 -03:00
Alexander Ljungberg eb692e672e Bindings test case based on Cocoa example Simple Bindings Adoption 01. 2010-11-17 23:51:33 -03:00
Alexander Ljungberg 381a6a999b Fixed a bad var statement in CPDecimal. Cleanup. 2010-11-17 21:58:58 -03:00
Alexander Ljungberg e276a830d3 Test token field represented object autocomplete. 2010-11-17 21:43:24 -03:00
Alexander Ljungberg e4ee9284b4 Merge branch 'cptokenfield-fixes' of https://github.com/miLibris/cappuccino into miLibris-cptokenfield-fixes 2010-11-17 21:08:43 -03:00
Alexander Ljungberg 9e441f69b8 Merge branch 'CPCollectionView-setContent-fix' of https://github.com/eventualbuddha/cappuccino into eventualbuddha-CPCollectionView-setContent-fix 2010-11-17 20:45:45 -03:00
Alexander Ljungberg 0d2b13dd75 Merge branch 'CPArrayController-removeObject-fix' of https://github.com/eventualbuddha/cappuccino into eventualbuddha-CPArrayController-removeObject-fix 2010-11-17 20:12:44 -03:00
Alexander Ljungberg 2df07344c8 Merge branch 'button-inset' of https://github.com/aparajita/cappuccino into aparajita-button-inset 2010-11-17 19:59:43 -03:00
Alexander Ljungberg 38ad5a8e2c Regenerated nib with latest text field height fix. 2010-11-17 19:58:20 -03:00
Francisco Ryan Tolmasky I bd15d2f331 Fix for [CPUndoManager removeAllActions] not clearing the current groupings as well.
Closes #1002.

Reviewed by me.
2010-11-17 12:21:09 -08:00
Klaas Pieter Annema 80ec35fd0a Merge branch 'hover-states' 2010-11-17 10:11:11 +01:00
Francisco Ryan Tolmasky I fb8d834036 Improved key view loop algorithm.
Reviewed by me.
2010-11-16 19:33:08 -08:00
Francisco Ryan Tolmasky I 4191153d0b Fix for key views not being properly auto-calculated.
Closes #965.

Reviewed by me.
2010-11-16 15:24:09 -08:00
Aparajita FishmanandRandall Luecke ace66b2b2f Sizing code had been added to CPTextField initWithCoder that required resizing in NSTextField NS_initWithCoder to be removed. However, the sizing code was removed, so this code has to be re-inserted. 2010-11-16 10:29:19 -05:00
Klaas Pieter Annema c8afcde4e5 implement NSTableColumn data cell text color support 2010-11-16 11:56:00 +01: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
Luc Vauvillier 8b9a0edeba Fix CPTokenField autocompletion to deal with represented objects 2010-11-15 15:51:21 +01:00
Klaas Pieter Annema 923770d95a style cleanup 2010-11-15 14:27:43 +01:00
Klaas Pieter Annema 011b8d250a remove second implementation of _processKeyboardUIKey: 2010-11-15 14:25:47 +01:00
Luc Vauvillier 0f8aa1e644 Support object representation in CPTokenField
Add some tests
2010-11-15 13:14:53 +01:00
Francisco Ryan Tolmasky I 9179a31a93 Style fixes.
Reviewed by me.
2010-11-13 12:41:31 -08:00
Francisco Ryan Tolmasky I c9d32b4163 Merge branch 'CPTreeNode-descendantNodeAtIndexPath' of https://github.com/luuse/cappuccino into luuse-CPTreeNode-descendantNodeAtIndexPath 2010-11-13 10:26:07 -08:00
Andreas 57c691c2e2 Make CPBundle post a notification on successfull load 2010-11-13 15:38:14 +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
Andreas Falk 8a75c9078e Fix display names in CFBundle 2010-11-13 13:36:24 +01:00
Andreas Falk fbcf84e63f Fix some broken things after cherry-pick 2010-11-13 13:03:01 +01:00
Andreas ea5ab5e921 Add CPIndexPath implementation and tests 2010-11-13 12:22:06 +01:00
Andreas 3a8773baec Add -descendantNodeAtIndexPath: and tests to CPTreeNode 2010-11-13 12:06:43 +01:00
cacaodev 602a2c47c2 CPScanner fixes with tests. 2010-11-13 02:29:04 +01:00
Francisco Ryan Tolmasky I ab4dd1ac6d Got rid of nonsensical tasks in ThemeDescriptor Jakefile.
Reviewed by me.
2010-11-12 15:47:25 -08:00
Brian Donovan 6f38b2aa0d -[CPCollectionView setContent:] did not always call reloadContent:.
This would break key-value binding setups where a CPCollectionView's content property was hooked up to a CPArrayController's content or arrangedObjects property since the CPArrayController maintains the same object and calls setValue:forKey: with the same object the CPCollectionView already has. Therefore we cannot skip calling reloadContent even when the incoming content array is the same one we got before, because most likely the contents have changed out from under us.
2010-11-11 21:39:07 -08:00
Brian Donovan 929ec28436 CPArrayController did not allow removing objects without a selection.
CPArrayController was erroneously using canRemove to determine whether explicit removal could take place, when in fact the documentation for [NSObjectController canRemove] (NSArrayController does not override canRemove) states that it returns "YES if an object can be removed from the receiver using remove:, otherwise NO", implying that it should only be used to check whether there is a selected element that can be removed (for example, to bind the enabled state of a toolbar button to a CPArrayController's canRemove property). It should not be used to decide whether a specific object can be removed or not.
2010-11-11 17:45:18 -08:00
Alexander Ljungberg 04a19543a5 Fix CPTabView decoding to work better with nib2cib. 2010-11-11 20:21:24 -03:00
Alexander Ljungberg 5d505f5271 Merge branch 'CPString-copy' of https://github.com/cacaodev/cappuccino into cacaodev-CPString-copy 2010-11-11 16:57:49 -03:00
Antoine Mercadal 60ff3ca0a1 Support for HUD style
use [alert setTheme:[CPTheme defaultHUDTheme]] or [alert setTheme:[CPTheme defaultTheme]] to switch theme.
Add deprecated procies setWindowStyle: and windowStyles;
2010-11-11 18:24:17 +01:00
Alexander Ljungberg e4f5d9b32f Fixed some comments referencing NS* classes. 2010-11-11 13:42:25 -03:00
Antoine Mercadal 6b42ef3cb1 fix: CPAlert fails to runModal if ran sheetModal before 2010-11-11 17:38:39 +01:00
Alexander Ljungberg 345b9d9297 Fix some comments. 2010-11-11 13:38:16 -03:00
Alexander Ljungberg 4bad3c2823 Merge branch 'CPPredicate' of https://github.com/cacaodev/cappuccino into cacaodev-CPPredicate 2010-11-11 12:59:04 -03:00
Alexander Ljungberg 38033d9dcb Fixed the CPAlert manual test which did not work after the recent changes. 2010-11-11 12:46:25 -03:00
Nicholas Small 5c961d4f16 Restore CPAlert -setTitle: functionality. 2010-11-10 17:43:21 -05:00
Nicholas Small c21cdc2916 Cleanup CPAlert. 2010-11-10 17:39:56 -05:00
Nicholas Small 1a797b10c3 Merge branch 'CPAlert-Cocoa-Compliance' of https://github.com/primalmotion/cappuccino into primalmotion-CPAlert-Cocoa-Compliance 2010-11-10 13:46:50 -05:00
Antoine Mercadal 3bfa427134 Add setTitle: and title, deprecated proxies for setMessageText: and messageText
Add some missing Cocoa accessors
Fix acessors for messageText and informativeText that returned CPTextField instead of CPString
2010-11-10 11:02:27 +01:00
Antoine Mercadal 9a8c4bd431 move CPAlertLabelOffset to a theme attribute 2010-11-10 10:25:23 +01:00
Antoine Mercadal dc72b55361 remove the title of the panel. Cocoa doesn't display any title 2010-11-09 18:33:39 +01:00
Antoine Mercadal ee4ef882dd add X and Y offet theme properties for supression button 2010-11-09 18:27:26 +01:00
Antoine Mercadal 23c2f4bb8c remove the movable thing and remove the bezel-color them attribute 2010-11-09 18:08:13 +01:00
Antoine Mercadal bd01955f39 support for setShowsSupressionButton 2010-11-09 18:02:24 +01:00
Antoine Mercadal 3f1e1e57d8 update help button art 2010-11-09 18:02:06 +01:00
Antoine Mercadal ee343c7533 make window not movable by dragging background if sheet + capp_lint/sorting/cleaning/commenting 2010-11-09 17:01:11 +01:00
Antoine Mercadal 961071e3fa refactor a method 2010-11-09 16:55:33 +01:00
Antoine Mercadal 0219341ee8 add support for setShowHelp: 2010-11-09 16:41:41 +01:00
Aparajita Fishman 5df3c7838d Increased content inset a bit to match Cocoa, whitespace cleanup. 2010-11-09 09:27:11 -05:00
Antoine Mercadal bf63147ca3 Cleaning CPAlert, add accessoryView 2010-11-09 15:21:25 +01:00
Klaas Pieter Annema b7d7b99a82 Merge branch 'CPDecimalNumber' 2010-11-09 10:38:58 +01:00
Brian DonovanandKlaas Pieter Annema 5a0129018a Fix spelling of "separator". 2010-11-09 10:33:49 +01:00
Klaas Pieter Annema e48a437c88 fix failing CPUserDefaults test 2010-11-09 10:28:36 +01:00
Antoine Mercadal 187c32d231 fix CPStepper test cases 2010-11-09 00:46:47 +01:00
Antoine Mercadal c680e31817 add test case for CPStepper 2010-11-09 00:37:27 +01:00
Antoine Mercadal cc177eeb2b add artwork 2010-11-09 00:37:14 +01:00
Antoine Mercadal 918db24c63 add CPStepper to Aristo 2010-11-09 00:36:56 +01:00
Antoine Mercadal 7e005f4559 use setNeedsLayout to layout subviews 2010-11-09 00:36:28 +01:00
Antoine Mercadal 5d49c1346a implement CPStepper 2010-11-08 23:20:05 +01:00
Antoine Mercadal f6147850b9 use document.createElement('audio') instead of new Audio(). work better 2010-11-08 22:16:21 +01:00
Nicholas Small 731e50da32 Clean up value accessors in CPUserDefaults. 2010-11-08 12:35:23 -05:00
Nicholas Small 5078c3e9cf Merge branch 'fix-cpuserdefaults-protocol' of https://github.com/primalmotion/cappuccino into primalmotion-cpuserdefaults-fixes 2010-11-08 11:52:43 -05:00
Klaas Pieter Annema de0a09899a Merge branch 'sizeToFit-fix' of https://github.com/aparajita/cappuccino into aparajita-sizeToFit-fix 2010-11-08 10:08:50 +01:00
Klaas Pieter Annema 4041ef8746 Merge branch 'CPView-ephemeral-subview' of https://github.com/aparajita/cappuccino into aparajita-CPView-ephemeral-subview 2010-11-08 09:59:52 +01:00
cacaodev 3b35219beb Fix [[string copy] isEqual:[string copy]] == NO 2010-11-07 21:43:02 +01:00
cacaodev ca289e081e CPPredicate parsing support:
"($)path.($)variable"
 "SUBQUERY(collection, $x,$x = 2)"
 "sum:(arg1, ...)"
 "FUNCTION(target, selector, arg1, ...)
 "object[expression]"
 "set UNION|INTERSECT|MINUS otherset"
Fixed a bug where CPExpression_set was evaluating to an expression instead of a set.
Replaced parsing exceptions with a generic function indicating where it failed.
2010-11-07 17:56:22 +01:00
Aparajita Fishman 5cd00d71c7 Fixed sizeToFit drawing when there is no image, setNeedsDisplay is no longer needed after sizeToFit. 2010-11-06 17:12:09 -04:00
Antoine Mercadal ea924fbb26 some small glitch fix 2010-11-06 18:59:02 +01:00
Antoine Mercadal da23a89910 update header 2010-11-06 18:38:52 +01:00
Antoine Mercadal e4b47090ba added CPSound, an HTML5 wrapper for NSSound 2010-11-06 18:37:17 +01:00
Antoine Mercadal 386ded05fd remove useless _searchListNeedsReload 2010-11-06 10:19:21 +01:00
Alexander Ljungberg e3b6cbcee9 Merge branch 'CPArrayControllerFixes' of https://github.com/dasto/cappuccino into dasto-CPArrayControllerFixes 2010-11-05 15:48:10 -03:00
Alexander Ljungberg fd7651e895 Merge branch 'base-conversion' of https://github.com/aparajita/cappuccino into aparajita-base-conversion 2010-11-05 15:29:12 -03:00
Alexander Ljungberg 8ca2f53828 Merge branch 'CPPredicate' of https://github.com/cacaodev/cappuccino into cacaodev-CPPredicate 2010-11-05 14:52:37 -03:00
Alexander Ljungberg fc385935ef Test nib2cib for CPTabView. 2010-11-05 13:52:59 -03:00
Alexander Ljungberg ed1c5714a3 Closes #971. Fixed: nib2cib did not work with the new CPTabView. 2010-11-05 13:51:51 -03:00
Alexander Ljungberg dfe03458d0 Fixed: decoding a CPTabView would result in "TypeError: Result of expression 'aRect' [null] is not an object" due to incomplete initialisation. 2010-11-05 13:30:57 -03:00
Antoine Mercadal c55cd03db1 more robust tests for CPUserDefaults 2010-11-05 17:28:40 +01:00
Antoine Mercadal 6a2b347b21 authorize string in setURL:forKey: 2010-11-05 17:28:18 +01:00
Antoine Mercadal b96abb5fd4 fix typo 2010-11-05 17:01:24 +01:00
Alexander Ljungberg 4974a47c94 Merge branch 'master' of github.com:280north/cappuccino 2010-11-05 12:03:25 -03:00
Alexander Ljungberg 7e229652f1 Merge branch 'fix-cptabview-height-resizing' of https://github.com/primalmotion/cappuccino into primalmotion-fix-cptabview-height-resizing 2010-11-05 11:56:19 -03:00
Alexander Ljungberg 81f2959417 Visually test tab view resizing. 2010-11-05 11:52:11 -03:00
Daniel Stolzenberg 9d46c688ed fixed support for "contentSet" in CPArrayController.j, where sets were not converted to arrays 2010-11-05 15:02:31 +01:00
Antoine Mercadal 60a8ddd306 be less restrictive on setInteger, setFloat and setDouble 2010-11-05 14:42:22 +01:00
Klaas Pieter Annema 4817a87499 fix CPBox drawing the separator style between pixels 2010-11-05 13:05:43 +01:00
Antoine Mercadal 91ce1c3f6c add stringArrayForKey: 2010-11-05 11:52:43 +01:00
Antoine Mercadal 0c9cba4e71 add test cases for CPUserDefaults 2010-11-05 11:47:23 +01:00
Antoine Mercadal c833de2e0a set _searchListNeedsReload to YES after setting defaults 2010-11-05 11:37:46 +01:00
Antoine Mercadal 6824e42c69 fix some small bugs 2010-11-05 11:32:18 +01:00
Antoine Mercadal 67a41534bd make CPUserDefault more Cocoa compliant 2010-11-05 11:08:27 +01:00
Klaas Pieter Annema 3d0d522f76 implement coding support for autosaveName in CPTableView 2010-11-05 11:02:37 +01:00
Klaas Pieter Annema accd29804c implement table column order and width autosaving 2010-11-05 11:02:26 +01:00
Klaas Pieter Annema 0c62609e76 made CPTableView aware of a resize in CPTableColumn 2010-11-05 11:02:05 +01:00
Aparajita Fishman 6148654604 Added convertTo/FromBase methods for completeness (and convenience). 2010-11-04 23:01:28 -04:00
Nicholas Small 40c1957484 Update documentation in CPUserDefaults. 2010-11-04 16:06:53 -04:00
Nicholas Small 6f754d9810 Added CPUserDefaults.j 2010-11-04 15:53:53 -04:00
Antoine Mercadal 9a4c9e4306 add test for CPTabView height resizing 2010-11-04 10:41:24 +01:00
Randall Luecke c52b40657a Removed frame resizing in the textfield's initWithCoder: 2010-11-03 22:54:09 -04:00
Daniel Stolzenberg db2c88f2e5 Merge branch 'master' of git://github.com/280north/cappuccino 2010-11-02 13:49:52 +01:00
Antoine Mercadal b9095b2176 box is now resized using CPViewHeightSizable 2010-11-02 13:02:24 +01:00
Daniel Stolzenberg ec9fac6629 Merge branch 'master' of git://github.com/280north/cappuccino 2010-11-01 10:13:59 +01:00
Daniel Stolzenberg b2dac594dc fixed 4 spaces for tab formatting issues in CPKeyValueCodingTest.j 2010-11-01 09:47:19 +01:00
Daniel Stolzenberg 28029030b6 fixed 4 spaces for tab formatting issues 2010-11-01 09:38:19 +01:00
cacaodev 4b1fbf1eff Implemented subquery expressions.
Added missing getters in CPExpression.
Added a type: argument to FunctionExpression initializer used by  subclasses to init super with their own type.
Fixed evaluation with bindings dictionary in CPExpression_variable. Allow values in bindings to be a constant or an expression (per cocoa).

Tests: added tests for subqueryExpressions, for variableExpression evaluation where the value in the bindings dictionary can be either a constant or another expression.
Parsing a simple variable expression works (e.g. '$x = 12'), parsing a variable in a combined path (e.g.
'$x.path = 12' won't yet.
2010-10-29 18:58:29 +02:00
Daniel Stolzenberg 24fbecb2e6 Merge branch 'master' of git://github.com/280north/cappuccino 2010-10-28 09:20:52 +02:00
Daniel Stolzenberg 4a142b5c02 implemented missing features of KVO for unordered to-many relationships in CPKeyValueCoding.j 2010-10-27 19:08:34 +02:00
Daniel Stolzenberg dfba974572 enabled subclasses of CPSet to use CPObjects "addObserver:/removeObserver:" methods without throwing exception 2010-10-27 12:35:50 +02:00
Daniel Stolzenberg c1fd31fa23 removed unnecessary @import "CPArray+KVO.j" statement in CPKeyValueCoding.j 2010-10-27 12:13:47 +02:00
Daniel Stolzenberg fd3e10f793 added some comments to original behaviour of Cocoa in CPKeyValueCoding.j 2010-10-27 12:07:50 +02:00
Daniel Stolzenberg 6a7358920b implemented CPKeyValueCodingTests for CPNull-nil-conversion and CPDictionary KVC-compliance 2010-10-27 10:43:31 +02:00
Daniel Stolzenberg c0aa180e83 improved Cocoa compatibility, enhanced usage of accessor pattern in "removeAllObjects" in CPSet+KVO.j 2010-10-27 10:41:48 +02:00
Daniel Stolzenberg 82cf7df7e9 implemented missing "setValue:forKey:" test for CPKeyValueCoding.j 2010-10-26 18:10:31 +02:00
Daniel Stolzenberg 4c58c602ff implemented Tests for CPKeyValueCoding "valueForKey:" 2010-10-26 17:09:12 +02:00
Daniel Stolzenberg 14e4b71d20 removed unnecessary ".isa" statements in CPKeyValueCoding.j 2010-10-26 17:07:13 +02:00
Daniel Stolzenberg 6483ea233c imported new implementation for unordered to-many relationships in CPKeyValueObserving.j/CPSet+KVO.j 2010-10-26 14:23:24 +02:00
Daniel Stolzenberg 895ed4f6ff implemented missing replacement methods for accessor patterns in CPKeyValueObserving.j 2010-10-26 14:20:54 +02:00
Daniel Stolzenberg 5ff7e66981 implemented "will/didChangeValueForKey:withSetMutation:usingObjects:" in _CPKVOModelSubclass in CPKeyValueObserving.j 2010-10-26 14:17:39 +02:00
Daniel Stolzenberg a2ff814796 added missing accessor patterns in "_replaceSetterForKey:" in CPKeyValueObserving.j 2010-10-26 14:13:21 +02:00
Daniel Stolzenberg c1e42a2f3e refactored duplicated method copying implementation 2010-10-26 14:11:47 +02:00
Daniel Stolzenberg 9e1c07b195 added "CPKeyValueSetMutationKind" definitions to CPKeyValueObserving.j 2010-10-26 14:08:56 +02:00
Daniel Stolzenberg c71c732fc0 added "will/didChangeValueForKey:withSetMutation:usingObjects:" stubs to CPObject in CPKeyValueObserving.j 2010-10-26 14:06:56 +02:00
Daniel Stolzenberg b3e0ec60df fixed bug in "_modifierForKey()" where self was used in a plain JS-function 2010-10-26 13:57:57 +02:00
Daniel Stolzenberg 513cc2cac7 removed unnecessary if-statement (because it never gets executed) 2010-10-26 13:04:25 +02:00
Daniel Stolzenberg b0feeb3d31 improved cocoa compatibility by _CPKVCArray-proxy inheriting from CPMutableArray, fixed wrong mutable accessors patterns in "CPArray+KVO.j" 2010-10-26 12:53:21 +02:00
Daniel Stolzenberg 9c7b3475d8 fixed bug in "mutableArrayValueForKeyPath:" in CPArray+KVO.j which was not calling itself recursively 2010-10-26 12:50:33 +02:00
Daniel Stolzenberg 99e4a4fb4f implemented missing "setValuesForKeysWithDictionary:" method in "CPKeyValueCoding.j" 2010-10-26 12:48:32 +02:00
Daniel Stolzenberg 7b7b46a61e unified implementations of "_accessorForKey", "_modifierForKey" and "_ivarForKey" in CPKeyValueCoding.j 2010-10-26 12:39:47 +02:00
Daniel Stolzenberg ed4a264108 removed duplicated (and buggy) implementations of "valueForKey:" and "setValue:forKey:" in CPArray.j 2010-10-26 12:24:20 +02: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
Derek Hammer ae5d56471f Inlining function, fixing a style issue. 2010-10-14 19:31:04 -05:00
Aparajita Fishman bafb23ae44 Allow ephemeral subviews to be created when the parent view has an empty frame, de-lint 2010-10-09 08:14:00 -04: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
Klaas Pieter Annema c481d55976 fix hovered state being removed when the mouse leaves a subview of a control 2010-09-17 13:21:54 +02:00
Klaas Pieter Annema 7aa7d61984 Implement hover states.
- Set CPWindow _acceptsMouseMovedEvents default to YES
- Add CPThemeStateHovered to CPTheme
- Add hovered logic to CPControl is hovered
2010-09-17 12:06:01 +02:00
Derek Hammer fc545ed995 Adding support for CPURL 2010-09-06 14:18:53 -05:00
Derek Hammer f85ab24993 Finishing the rest to make them inherit properties of superclasses. 2010-09-06 14:02:52 -05:00
Derek Hammer 4e1766485f Updating CPDictionary and CPString to both actually subclass.. not just create a new object without inherited properties. 2010-09-06 13:46:27 -05:00
Derek Hammer 8e5471d0fe Updating CPData and CPDate to be subclassable. Only non-subclassable toll free bridged object is CPURL at this point. 2010-09-06 13:45:46 -05:00
Derek Hammer a09878dcb4 Adding self checks in toll free bridged objects so that they are subclassable. 2010-09-06 12:07:50 -05:00
Klaas Pieter Annema b3f2ba035e add CPDecimal and CPDecimalNumber to Foundation.j 2010-08-25 15:07:04 +02:00
Klaas Pieter Annema 10a620017d Merge remote branch 'stevegeek/CPDecimalNumber' into CPDecimalNumber 2010-08-25 15:06:47 +02:00
Stephen Ierodiaconou c10b06e29b Merge branch 'master' of git://github.com/280north/cappuccino into CPDecimalNumber 2010-06-13 00:03:13 +03:00
Stephen Ierodiaconou 411a634242 Merge branch 'CPDecimalNumber' of http://github.com/klaaspieter/cappuccino into CPDecimalNumber 2010-05-23 10:35:44 +03:00
Stephen Ierodiaconou 4ab421f183 Merge branch 'master' of git://github.com/280north/cappuccino into CPDecimalNumber 2010-05-23 10:26:17 +03:00
Klaas Pieter Annema 8e3e15080b made CPDecimalCreateWithString work with empty string 2010-05-06 14:13:29 +02:00
Klaas Pieter Annema fd625c96d6 made CPDecimalNumber a subclass of CPNumber 2010-05-05 12:14:55 +02:00
Klaas Pieter Annema 4f721fc1e2 added description to CPDecimalNumber 2010-05-05 12:13:47 +02:00
Klaas Pieter Annema 373210e610 fixed several global declarations of i in for loops 2010-05-05 12:13:24 +02:00
Stephen Ierodiaconou 0ddb17862c Merge branch 'master' of git://github.com/280north/cappuccino into CPDecimalNumber 2009-11-28 17:02:43 +00:00
Stephen Ierodiaconou aae415c1ee Merge branch 'master' of git://github.com/280north/cappuccino into CPDecimalNumber 2009-10-18 21:05:19 +01:00
Stephen Ierodiaconou c79b2456f5 Some style changes to CPDecimal 2009-10-16 12:35:59 +01:00
Stephen Ierodiaconou 5104d323bb Merge branch 'master' of git://github.com/280north/cappuccino 2009-10-14 14:30:13 +01:00
Stephen Ierodiaconou 80c4be6e5f Merge branch 'master' of git://github.com/280north/cappuccino 2009-10-11 19:34:13 +01:00
Stephen Ierodiaconou 970859311d Merge branch 'master' of git://github.com/280north/cappuccino 2009-10-09 15:21:43 +01:00
Stephen Ierodiaconou 449581e7c4 Merge branch 'master' of git://github.com/280north/cappuccino 2009-10-08 21:39:23 +01:00
Stephen Ierodiaconou 02a8fc7f72 Merge branch 'master' of git://github.com/280north/cappuccino 2009-10-08 21:32:59 +01:00
stevegeek 7bbeee8234 Merge branch 'master' of git://github.com/280north/cappuccino 2009-10-02 14:22:33 +01:00
stevegeek 00532fe7ac First CPDecimal and CPDecimalNumber commits (and tests).
These implementations are mostly complete but require optimisation.
2009-09-28 13:59:18 +01:00
stevegeek 073a934b2b Merge branch 'master' of git://github.com/280north/cappuccino 2009-09-28 11:55:10 +01:00
stevegeek ea7631de9e Merge branch 'master' of git://github.com/280north/cappuccino 2009-09-23 23:20:19 +01:00
stevegeek 81e15c91f4 Merge branch 'master' of git://github.com/280north/cappuccino 2009-09-21 09:30:21 +01:00
Stephen Ierodiaconou b8afbb66a7 Merge branch 'master' of git://github.com/280north/cappuccino 2009-09-20 10:35:33 +01:00
stephen 9e9eba695f Merge branch 'master' of git://github.com/280north/cappuccino
Conflicts:

	Foundation/CPArray.j
	Foundation/CPAttributedString.j
	Foundation/CPCountedSet.j
	Foundation/CPIndexSet.j
	Foundation/CPJSONPConnection.j
	Foundation/CPSet.j
	Foundation/CPTimer.j
2009-05-31 12:09:43 +01:00
Stephen Ierodiaconou c6e3cad944 Update to docs of replaceCharactersInRange in CPAttributedString. 2009-05-28 01:51:19 +01:00
Stephen Ierodiaconou 3af0e3249a Added a new group Cocoa Compatability for the empty compatability
classes like CPMutableArray
2009-05-28 01:34:40 +01:00
Stephen Ierodiaconou 510a836b90 Added briefs to all Foundation and made some cleanups to docs 2009-05-28 01:24:48 +01:00
Stephen Ierodiaconou 25f415045a All Foundation classes briefed 2009-05-28 01:14:27 +01:00
Stephen Ierodiaconou 0af9c18ef2 adding briefs and unifying class header structure 2009-05-28 00:15:57 +01:00
960 changed files with 122905 additions and 19792 deletions
+5
View File
@@ -5,3 +5,8 @@ Demos
./Aristo
WebSite
.push-package
*.xcodeproj/*.pbxuser
*.xcodeproj/*.perspectivev3
xcuserdata/
!*.xcodeproj/project.pbxproj
target
+2
View File
@@ -0,0 +1,2 @@
rvm_install_on_use_flag=1
rvm jruby-head@buildr
+12 -2
View File
@@ -24,6 +24,7 @@
@import "CPAlert.j"
@import "CPAnimation.j"
@import "CPApplication.j"
@import "CPArrayController.j"
@import "CPBezierPath.j"
@import "CPBox.j"
@import "CPBrowser.j"
@@ -31,10 +32,12 @@
@import "CPButtonBar.j"
@import "CPCheckBox.j"
@import "CPCib.j"
@import "CPCibBindingConnector.j"
@import "CPCibConnector.j"
@import "CPCibControlConnector.j"
@import "CPCibLoading.j"
@import "CPCibOutletConnector.j"
@import "CPCibRuntimeAttributesConnector.j"
@import "CPClipView.j"
@import "CPCollectionView.j"
@import "CPCollectionViewItem.j"
@@ -57,6 +60,7 @@
@import "CPImage.j"
@import "CPImageView.j"
@import "CPKeyBinding.j"
@import "CPLevelIndicator.j"
@import "CPMenu.j"
@import "CPMenuItem.j"
@import "CPOpenPanel.j"
@@ -64,9 +68,12 @@
@import "CPPanel.j"
@import "CPPasteboard.j"
@import "CPPopUpButton.j"
@import "CPPredicateEditor.j"
@import "CPPredicateEditorRowTemplate.j"
@import "CPProgressIndicator.j"
@import "CPRadio.j"
@import "CPResponder.j"
@import "CPRuleEditor.j"
@import "CPScroller.j"
@import "CPScrollView.j"
@import "CPSearchField.j"
@@ -74,20 +81,23 @@
@import "CPSegmentedControl.j"
@import "CPShadow.j"
@import "CPSlider.j"
@import "CPSound.j"
@import "CPSplitView.j"
@import "CPStepper.j"
@import "CPTableColumn.j"
@import "CPTableView.j"
@import "CPTabView.j"
@import "CPText.j"
@import "CPTextField.j"
@import "CPTokenField.j"
@import "CPToolbar.j"
@import "CPToolbarItem.j"
@import "CPTokenField.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"
@import "CPArrayController.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>
+600 -364
View File
@@ -6,7 +6,9 @@
* 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
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -75,22 +77,587 @@ CPCriticalAlertStyle = 2;
*/
@implementation CPAlert : CPView
{
CPPanel _alertPanel;
BOOL _showHelp @accessors(property=showsHelp);
BOOL _showSuppressionButton @accessors(property=showsSuppressionButton);
CPTextField _messageLabel;
CPTextField _informativeLabel;
CPImageView _alertImageView;
CPAlertStyle _alertStyle @accessors(property=alertStyle);
CPString _title @accessors(property=title);
CPView _accessoryView @accessors(property=accessoryView);
CPImage _icon @accessors(property=icon);
CPAlertStyle _alertStyle;
CPString _windowTitle;
int _windowStyle;
CPArray _buttons;
CPArray _buttons @accessors(property=buttons,readonly);
CPCheckBox _suppressionButton @accessors(property=suppressionButton,readonly);
id _delegate;
SEL _didEndSelector;
id _delegate @accessors(property=delegate);
id _modalDelegate;
SEL _didEndSelector;
CPWindow _window @accessors(property=window,readonly);
int _defaultWindowStyle;
CPImageView _alertImageView;
CPTextField _informativeLabel;
CPTextField _messageLabel;
CPButton _alertHelpButton;
BOOL _needsLayout;
}
#pragma mark Creating Alerts
/*!
Returns a CPAlert object with the provided info
@param aMessage the main body text of the alert
@param defaultButton the title of the default button
@param alternateButton if not nil, the title of a second button
@param otherButton if not nil, the title of the third button
@param informativeText if not nil the informative text of the alert
@return fully initialized CPAlert
*/
+ (CPAlert)alertWithMessageText:(CPString)aMessage defaultButton:(CPString)defaultButtonTitle alternateButton:(CPString)alternateButtonTitle otherButton:(CPString)otherButtonTitle informativeTextWithFormat:(CPString)informativeText
{
var alert = [[CPAlert alloc] init];
[alert setMessageText:aMessage];
[alert addButtonWithTitle:defaultButtonTitle];
if (alternateButtonTitle)
[alert addButtonWithTitle:alternateButtonTitle];
if (otherButtonTitle)
[alert addButtonWithTitle:otherButtonTitle];
if (informativeText)
[alert setInformativeText:informativeText];
return alert;
}
/*!
Return an CPAlert with type error
@param anErrorMessage the message of the alert
@return fully initialized CPAlert
*/
+ (CPAlert)alertWithError:(CPString)anErrorMessage
{
var alert = [[CPAlert alloc] init];
[alert setMessageText:anErrorMessage];
[alert setAlertStyle:CPCriticalAlertStyle];
return alert;
}
/*!
Initializes a \c CPAlert panel with the default alert style \c CPWarningAlertStyle.
*/
- (id)init
{
self = [super init];
if (self)
{
_buttons = [];
_alertStyle = CPWarningAlertStyle;
_showHelp = NO;
_needsLayout = YES;
_defaultWindowStyle = CPTitledWindowMask;
_messageLabel = [CPTextField labelWithTitle:@"Alert"];
_alertImageView = [[CPImageView alloc] init];
_informativeLabel = [[CPTextField alloc] init];
_suppressionButton = [CPCheckBox checkBoxWithTitle:@"Do not show this message again"];
_alertHelpButton = [[CPButton alloc] initWithFrame:CGRectMake(0.0, 0.0, 16.0, 16.0)];
[_alertHelpButton setTarget:self];
[_alertHelpButton setAction:@selector(_showHelp:)];
}
return self;
}
#pragma mark Accessors
/*!
set the theme to use
@param the theme to use
*/
- (void)setTheme:(CPTheme)aTheme
{
if (aTheme === [self theme])
return;
if (aTheme === [CPTheme defaultHudTheme])
_defaultWindowStyle = CPTitledWindowMask | CPHUDBackgroundWindowMask;
else
_defaultWindowStyle = CPTitledWindowMask;
_window = nil; // will be regenerated at next layout
_needsLayout = YES;
[super setTheme:aTheme];
}
/*! @deprecated
*/
- (void)setWindowStyle:(int)aStyle
{
CPLog.warn("DEPRECATED: setWindowStyle: is deprecated. use setTheme: instead");
[self setTheme:(aStyle === CPHUDBackgroundWindowMask) ? [CPTheme defaultHudTheme] : [CPTheme defaultTheme]];
}
/*! @deprecated
*/
- (int)windowStyle
{
CPLog.warn("DEPRECATED: windowStyle: is deprecated. use theme instead");
return _defaultWindowStyle;
}
/*!
set the text of the alert's message
@param aText CPString containing the text
*/
- (void)setMessageText:(CPString)aText
{
[_messageLabel setStringValue:aText];
_needsLayout = YES;
}
/*!
return the content of the message text
@return CPString containing the message text
*/
- (CPString)messageText
{
return [_messageLabel stringValue];
}
/*!
set the text of the alert's informative text
@param aText CPString containing the informative text
*/
- (void)setInformativeText:(CPString)aText
{
[_informativeLabel setStringValue:aText];
_needsLayout = YES;
}
/*!
return the content of the message text
@return CPString containing the message text
*/
- (CPString)informativeText
{
return [_informativeLabel stringValue];
}
/*!
Sets the title of the alert window.
This API is not present in Cocoa.
@param aTitle CPString containing the window title
*/
- (void)setTitle:(CPString)aTitle
{
_title = aTitle;
[_window setTitle:aTitle];
}
/*!
set the accessory view
@param aView the accessory view
*/
- (void)setAccessoryView:(CPView)aView
{
_accessoryView = aView;
_needsLayout = YES;
}
/*!
set if alert shows the suppression button
@param shouldShowSuppressionButton YES or NO
*/
- (void)setShowsSuppressionButton:(BOOL)shouldShowSuppressionButton
{
_showSuppressionButton = shouldShowSuppressionButton;
_needsLayout = YES;
}
#pragma mark Accessing Buttons
/*!
Adds a button with a given title to the receiver.
Buttons will be added starting from the right hand side of the \c CPAlert panel.
The first button will have the index 0, the second button 1 and so on.
The first button will automatically be given a key equivalent of Return,
and any button titled "Cancel" will be given a key equivalent of Escape.
You really shouldn't need more than 3 buttons.
@param title the title of the button
*/
- (void)addButtonWithTitle:(CPString)aTitle
{
var bounds = [[_window contentView] bounds],
count = [_buttons count],
button = [[CPButton alloc] initWithFrame:CGRectMakeZero()];
[button setTitle:aTitle];
[button setTag:count];
[button setTarget:self];
[button setAction:@selector(_takeReturnCodeFrom:)];
[[_window contentView] addSubview:button];
if (count == 0)
[button setKeyEquivalent:CPCarriageReturnCharacter];
else if ([aTitle lowercaseString] === @"cancel")
[button setKeyEquivalent:CPEscapeFunctionKey];
[_buttons insertObject:button atIndex:0];
}
#pragma mark Layout
/*!
@ignore
*/
- (void)_layoutMessageView
{
var inset = [self currentValueForThemeAttribute:@"content-inset"],
sizeWithFontCorrection = 6.0,
messageLabelWidth,
messageLabelTextSize;
[_messageLabel setTextColor:[self currentValueForThemeAttribute:@"message-text-color"]];
[_messageLabel setFont:[self currentValueForThemeAttribute:@"message-text-font"]];
[_messageLabel setTextShadowColor:[self currentValueForThemeAttribute:@"message-text-shadow-color"]];
[_messageLabel setTextShadowOffset:[self currentValueForThemeAttribute:@"message-text-shadow-offset"]];
[_messageLabel setAlignment:[self currentValueForThemeAttribute:@"message-text-alignment"]];
[_messageLabel setLineBreakMode:CPLineBreakByWordWrapping];
messageLabelWidth = CGRectGetWidth([[_window contentView] frame]) - inset.left - inset.right;
messageLabelTextSize = [[_messageLabel stringValue] sizeWithFont:[_messageLabel font] inWidth:messageLabelWidth];
[_messageLabel setFrame:CGRectMake(inset.left, inset.top, messageLabelTextSize.width, messageLabelTextSize.height + sizeWithFontCorrection)];
}
/*!
@ignore
*/
- (void)_layoutInformativeView
{
var inset = [self currentValueForThemeAttribute:@"content-inset"],
defaultElementsMargin = [self currentValueForThemeAttribute:@"default-elements-margin"],
sizeWithFontCorrection = 6.0,
informativeLabelWidth,
informativeLabelOriginY,
informativeLabelTextSize;
[_informativeLabel setTextColor:[self currentValueForThemeAttribute:@"informative-text-color"]];
[_informativeLabel setFont:[self currentValueForThemeAttribute:@"informative-text-font"]];
[_informativeLabel setTextShadowColor:[self currentValueForThemeAttribute:@"informative-text-shadow-color"]];
[_informativeLabel setTextShadowOffset:[self currentValueForThemeAttribute:@"informative-text-shadow-offset"]];
[_informativeLabel setAlignment:[self currentValueForThemeAttribute:@"informative-text-alignment"]];
[_informativeLabel setLineBreakMode:CPLineBreakByWordWrapping];
informativeLabelWidth = CGRectGetWidth([[_window contentView] frame]) - inset.left - inset.right,
informativeLabelOriginY = [_messageLabel frameOrigin].y + [_messageLabel frameSize].height + defaultElementsMargin,
informativeLabelTextSize = [[_informativeLabel stringValue] sizeWithFont:[_informativeLabel font] inWidth:informativeLabelWidth];
[_informativeLabel setFrame:CGRectMake(inset.left, informativeLabelOriginY, informativeLabelTextSize.width, informativeLabelTextSize.height + sizeWithFontCorrection)];
}
/*!
@ignore
*/
- (void)_layoutAccessoryView
{
if (!_accessoryView)
return;
var inset = [self currentValueForThemeAttribute:@"content-inset"],
defaultElementsMargin = [self currentValueForThemeAttribute:@"default-elements-margin"],
accessoryViewWidth = CGRectGetWidth([[_window contentView] frame]) - inset.left - inset.right,
accessoryViewOriginY = CGRectGetMaxY([_informativeLabel frame]) + defaultElementsMargin;
[_accessoryView setFrameOrigin:CGPointMake(inset.left, accessoryViewOriginY)];
[[_window contentView] addSubview:_accessoryView];
}
/*!
@ignore
*/
- (void)_layoutSuppressionButton
{
if (!_showSuppressionButton)
return;
var inset = [self currentValueForThemeAttribute:@"content-inset"],
suppressionViewXOffset = [self currentValueForThemeAttribute:@"suppression-button-x-offset"],
suppressionViewYOffset = [self currentValueForThemeAttribute:@"suppression-button-y-offset"],
defaultElementsMargin = [self currentValueForThemeAttribute:@"default-elements-margin"],
suppressionButtonViewOriginY = CGRectGetMaxY([(_accessoryView || _informativeLabel) frame]) + defaultElementsMargin + suppressionViewYOffset;
[_suppressionButton setTextColor:[self currentValueForThemeAttribute:@"suppression-button-text-color"]];
[_suppressionButton setFont:[self currentValueForThemeAttribute:@"suppression-button-text-font"]];
[_suppressionButton setTextShadowColor:[self currentValueForThemeAttribute:@"suppression-button-text-shadow-color"]];
[_suppressionButton setTextShadowOffset:[self currentValueForThemeAttribute:@"suppression-button-text-shadow-offset"]];
[_suppressionButton sizeToFit];
[_suppressionButton setFrameOrigin:CGPointMake(inset.left + suppressionViewXOffset, suppressionButtonViewOriginY)];
[[_window contentView] addSubview:_suppressionButton];
}
/*!
@ignore
*/
- (CGSize)_layoutButtonsFromView:(CPView)lastView
{
var inset = [self currentValueForThemeAttribute:@"content-inset"],
minimumSize = [self currentValueForThemeAttribute:@"size"],
buttonOffset = [self currentValueForThemeAttribute:@"button-offset"],
helpLeftOffset = [self currentValueForThemeAttribute:@"help-image-left-offset"],
aRepresentativeButton = [_buttons objectAtIndex:0],
defaultElementsMargin = [self currentValueForThemeAttribute:@"default-elements-margin"],
panelSize = [[_window contentView] frame].size,
buttonsOriginY,
offsetX;
[aRepresentativeButton setTheme:[self theme]];
[aRepresentativeButton sizeToFit];
panelSize.height = CGRectGetMaxY([lastView frame]) + defaultElementsMargin + [aRepresentativeButton frameSize].height;
if (panelSize.height < minimumSize.height)
panelSize.height = minimumSize.height;
buttonsOriginY = panelSize.height - [aRepresentativeButton frameSize].height + buttonOffset;
offsetX = panelSize.width - inset.right;
for (var i = [_buttons count] - 1; i >= 0 ; i--)
{
var button = _buttons[i];
[button setTheme:[self theme]];
[button sizeToFit];
var buttonFrame = [button frame],
width = MAX(80.0, CGRectGetWidth(buttonFrame)),
height = CGRectGetHeight(buttonFrame);
offsetX -= width;
[button setFrame:CGRectMake(offsetX, buttonsOriginY, width, height)];
offsetX -= 10;
}
if (_showHelp)
{
var helpImage = [self currentValueForThemeAttribute:@"help-image"],
helpImagePressed = [self currentValueForThemeAttribute:@"help-image-pressed"],
helpImageSize = helpImage ? [helpImage size] : CGSizeMakeZero(),
helpFrame = CGRectMake(helpLeftOffset, buttonsOriginY, helpImageSize.width, helpImageSize.height);
[_alertHelpButton setImage:helpImage];
[_alertHelpButton setAlternateImage:helpImagePressed];
[_alertHelpButton setBordered:NO];
[_alertHelpButton setFrame:helpFrame];
}
panelSize.height += [aRepresentativeButton frameSize].height + inset.bottom + buttonOffset;
return panelSize;
}
/*!
@ignore
*/
- (void)layout
{
if (!_needsLayout)
return;
if (!_window)
[self _createWindowWithStyle:nil];
var iconOffset = [self currentValueForThemeAttribute:@"image-offset"],
theImage = _icon,
finalSize;
if (!theImage)
switch (_alertStyle)
{
case CPWarningAlertStyle:
theImage = [self currentValueForThemeAttribute:@"warning-image"];
break;
case CPInformationalAlertStyle:
theImage = [self currentValueForThemeAttribute:@"information-image"];
break;
case CPCriticalAlertStyle:
theImage = [self currentValueForThemeAttribute:@"error-image"];
break;
}
[_alertImageView setImage:theImage];
var imageSize = theImage ? [theImage size] : CGSizeMakeZero();
[_alertImageView setFrame:CGRectMake(iconOffset.x, iconOffset.y, imageSize.width, imageSize.height)];
[self _layoutMessageView];
[self _layoutInformativeView];
[self _layoutAccessoryView];
[self _layoutSuppressionButton];
var lastView = _informativeLabel;
if (_showSuppressionButton)
lastView = _suppressionButton;
else if (_accessoryView)
lastView = _accessoryView
finalSize = [self _layoutButtonsFromView:lastView];
if ([_window styleMask] & CPDocModalWindowMask)
finalSize.height -= 26; // adjust the absence of title bar
[_window setFrameSize:finalSize];
[_window center];
_needsLayout = NO;
}
#pragma mark Displaying Alerts
/*!
Displays the \c CPAlert panel as a modal dialog. The user will not be
able to interact with any other controls until s/he has dismissed the alert
by clicking on one of the buttons.
*/
- (void)runModal
{
if (!([_window styleMask] & _defaultWindowStyle))
{
_needsLayout = YES;
[self _createWindowWithStyle:_defaultWindowStyle];
}
[self layout];
[CPApp runModalForWindow:_window];
}
/*!
Runs the receiver modally as an alert sheet attached to a specified window.
@param window The parent window for the sheet.
@param modalDelegate The delegate for the modal-dialog session.
@param alertDidEndSelector Message the alert sends to modalDelegate after the sheet is dismissed.
@param contextInfo Contextual data passed to modalDelegate in didEndSelector message.
*/
- (void)beginSheetModalForWindow:(CPWindow)aWindow modalDelegate:(id)modalDelegate didEndSelector:(SEL)alertDidEndSelector contextInfo:(id)contextInfo
{
if (!([_window styleMask] & CPDocModalWindowMask))
{
_needsLayout = YES;
[self _createWindowWithStyle:CPDocModalWindowMask];
}
[self layout];
_modalDelegate = modalDelegate;
_didEndSelector = alertDidEndSelector;
[CPApp beginSheet:_window modalForWindow:aWindow modalDelegate:self didEndSelector:@selector(_alertDidEnd:returnCode:contextInfo:) contextInfo:contextInfo];
}
/*!
Runs the receiver modally as an alert sheet attached to a specified window.
@param window The parent window for the sheet.
*/
- (void)beginSheetModalForWindow:(CPWindow)aWindow
{
[self beginSheetModalForWindow:aWindow modalDelegate:nil didEndSelector:nil contextInfo:nil];
}
#pragma mark Private
/*!
@ignore
*/
- (void)_createWindowWithStyle:(int)forceStyle
{
var frame = CGRectMakeZero();
frame.size = [self currentValueForThemeAttribute:@"size"];
_window = [[CPWindow alloc] initWithContentRect:frame styleMask:forceStyle || _defaultWindowStyle];
if (_title)
[_window setTitle:_title];
var contentView = [_window contentView],
count = [_buttons count];
if (count)
while (count--)
[contentView addSubview:_buttons[count]];
else
[self addButtonWithTitle:@"OK"];
[contentView addSubview:_messageLabel];
[contentView addSubview:_alertImageView];
[contentView addSubview:_informativeLabel];
if (_showHelp)
[contentView addSubview:_alertHelpButton];
}
/*!
@ignore
*/
- (@action)_showHelp:(id)aSender
{
if ([_delegate respondsToSelector:@selector(alertShowHelp:)])
[_delegate alertShowHelp:self];
}
/*
@ignore
*/
- (@action)_takeReturnCodeFrom:(id)aSender
{
if ([_window isSheet])
[CPApp endSheet:_window returnCode:[aSender tag]];
else
{
[CPApp abortModal];
[_window close];
[self _alertDidEnd:_window returnCode:[aSender tag] contextInfo:nil];
}
}
/*!
@ignore
*/
- (void)_alertDidEnd:(CPWindow)aWindow returnCode:(int)returnCode contextInfo:(id)contextInfo
{
if ([_delegate respondsToSelector:@selector(alertDidEnd:returnCode:)])
[_delegate alertDidEnd:self returnCode:returnCode];
if (_didEndSelector)
objj_msgSend(_modalDelegate, _didEndSelector, self, returnCode, contextInfo);
_modalDelegate = nil;
_didEndSelector = nil;
}
#pragma mark Theme Attributes
+ (CPString)defaultThemeClass
{
return @"alert";
@@ -104,7 +671,17 @@ CPCriticalAlertStyle = 2;
CGPointMake(15, 12),
[CPNull null],
[CPNull null],
[CPNull null]
[CPNull null],
[CPNull null],
[CPNull null],
[CPNull null],
0.0,
0.0,
3.0,
[CPColor blackColor],
[CPFont systemFontOfSize:12.0],
[CPNull null],
0.0
]
forKeys:[@"size", @"content-inset", @"informative-offset", @"button-offset",
@"message-text-alignment", @"message-text-color", @"message-text-font", @"message-text-shadow-color", @"message-text-shadow-offset",
@@ -112,359 +689,18 @@ CPCriticalAlertStyle = 2;
@"image-offset",
@"information-image",
@"warning-image",
@"error-image"
@"error-image",
@"help-image",
@"help-image-left-offset",
@"help-image-pressed",
@"suppression-button-y-offset",
@"suppression-button-x-offset",
@"default-elements-margin",
@"suppression-button-text-color",
@"suppression-button-text-font",
@"suppression-button-text-shadow-color",
@"suppression-button-text-shadow-offset"
]];
}
/*!
Initializes a \c CPAlert panel with the default alert style \c CPWarningAlertStyle.
*/
- (id)init
{
if (self = [super init])
{
_buttons = [CPArray array];
_alertStyle = CPWarningAlertStyle;
_alertPanel = nil;
_windowStyle = nil;
_didEndSelector = nil;
_messageLabel = [CPTextField labelWithTitle:@"Alert"];
_alertImageView = [[CPImageView alloc] initWithFrame:CGRectMakeZero()];
_informativeLabel = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
}
return self;
}
/*!
Sets the window appearance. If CPHUDBackgroundWindowMask is set, the default HUD theme
will be activated.
@param styleMask - Either CPHUDBackgroundWindowMask or nil for standard.
*/
- (void)setWindowStyle:(int)styleMask
{
_windowStyle = styleMask;
[self setTheme:(_windowStyle & CPHUDBackgroundWindowMask) ? [CPTheme defaultHudTheme] : [CPTheme defaultTheme]];
// We'll need to recreate the panel to get the new window style.
_alertPanel = nil;
}
- (void)_createPanel
{
var frame = CGRectMakeZero();
frame.size = [self currentValueForThemeAttribute:@"size"];
_alertPanel = [[CPPanel alloc] initWithContentRect:frame styleMask:_windowStyle ? _windowStyle | CPTitledWindowMask : CPTitledWindowMask];
var contentView = [_alertPanel contentView],
count = [_buttons count];
if (count)
{
while (count--)
[contentView addSubview:_buttons[count]];
}
else
[self addButtonWithTitle:@"OK"];
[contentView addSubview:_messageLabel];
[contentView addSubview:_alertImageView];
[contentView addSubview:_informativeLabel];
}
/*!
Sets the window's title. If this is not defined, a default title based on your warning level will be used.
@param aTitle the title to use in place of the default. Set to nil to use default.
*/
- (void)setTitle:(CPString)aTitle
{
_windowTitle = aTitle;
}
/*!
Gets the window's title.
*/
- (CPString)title
{
return _windowTitle;
}
/*!
Gets the window's style.
*/
- (int)windowStyle
{
return _windowStyle;
}
/*!
Sets the receivers delegate.
@param delegate - Delegate for the alert. nil removes the delegate.
*/
- (void)setDelegate:(id)delegate
{
_delegate = delegate;
}
/*!
Gets the receiver's delegate.
*/
- (void)delegate
{
return _delegate;
}
/*!
Sets the alert style of the receiver.
@param style - Alert style for the alert.
*/
- (void)setAlertStyle:(CPAlertStyle)style
{
_alertStyle = style;
}
/*!
Gets the alert style.
*/
- (CPAlertStyle)alertStyle
{
return _alertStyle;
}
/*!
Sets the receivers message text, or title, to a given text.
@param messageText - Message text for the alert.
*/
- (void)setMessageText:(CPString)messageText
{
[_messageLabel setStringValue:messageText];
}
/*!
Returns the receiver's message text body.
*/
- (CPString)messageText
{
return [_messageLabel stringValue];
}
/*!
Sets the receiver's informative text, shown below the message text.
@param informativeText - The informative text.
*/
- (void)setInformativeText:(CPString)informativeText
{
[_informativeLabel setStringValue:informativeText];
}
/*!
Returns the receiver's informative text.
*/
- (CPString)informativeText
{
return [_informativeLabel stringValue];
}
/*!
Adds a button with a given title to the receiver.
Buttons will be added starting from the right hand side of the \c CPAlert panel.
The first button will have the index 0, the second button 1 and so on.
The first button will automatically be given a key equivalent of Return,
and any button titled "Cancel" will be given a key equivalent of Escape.
You really shouldn't need more than 3 buttons.
*/
- (void)addButtonWithTitle:(CPString)title
{
var bounds = [[_alertPanel contentView] bounds],
button = [[CPButton alloc] initWithFrame:CGRectMakeZero()],
_buttonCount = [_buttons count];
[button setTitle:title];
[button setTarget:self];
[button setTag:_buttonCount];
[button setAction:@selector(_dismissAlert:)];
[[_alertPanel contentView] addSubview:button];
if (_buttonCount == 0)
[button setKeyEquivalent:CPCarriageReturnCharacter];
else if ([title lowercaseString] === "cancel")
[button setKeyEquivalent:CPEscapeFunctionKey];
else
[button setKeyEquivalent:nil];
[_buttons insertObject:button atIndex:0];
}
- (void)layoutPanel
{
if (!_alertPanel)
[self _createPanel];
var inset = [self currentValueForThemeAttribute:@"content-inset"],
iconOffset = [self currentValueForThemeAttribute:@"image-offset"],
theTitle,
theImage;
switch (_alertStyle)
{
case CPWarningAlertStyle: theImage = [self currentValueForThemeAttribute:@"warning-image"];
theTitle = @"Warning";
break;
case CPInformationalAlertStyle: theImage = [self currentValueForThemeAttribute:@"information-image"];
theTitle = @"Information";
break;
case CPCriticalAlertStyle: theImage = [self currentValueForThemeAttribute:@"error-image"];
theTitle = @"Error";
break;
}
[_alertImageView setImage:theImage];
var imageSize = theImage ? [theImage size] : CGSizeMakeZero();
[_alertImageView setFrame:CGRectMake(iconOffset.x, iconOffset.y, imageSize.width, imageSize.height)];
[_alertPanel setTitle:_windowTitle ? _windowTitle : theTitle];
[_alertPanel setFloatingPanel:YES];
[_alertPanel center];
[_messageLabel setTextColor:[self currentValueForThemeAttribute:@"message-text-color"]];
[_messageLabel setFont:[self currentValueForThemeAttribute:@"message-text-font"]];
[_messageLabel setTextShadowColor:[self currentValueForThemeAttribute:@"message-text-shadow-color"]];
[_messageLabel setTextShadowOffset:[self currentValueForThemeAttribute:@"message-text-shadow-offset"]];
[_messageLabel setAlignment:[self currentValueForThemeAttribute:@"message-text-alignment"]];
[_messageLabel setLineBreakMode:CPLineBreakByWordWrapping];
[_informativeLabel setTextColor:[self currentValueForThemeAttribute:@"informative-text-color"]];
[_informativeLabel setFont:[self currentValueForThemeAttribute:@"informative-text-font"]];
[_informativeLabel setTextShadowColor:[self currentValueForThemeAttribute:@"informative-text-shadow-color"]];
[_informativeLabel setTextShadowOffset:[self currentValueForThemeAttribute:@"informative-text-shadow-offset"]];
[_informativeLabel setLineBreakMode:CPLineBreakByWordWrapping];
// FIXME sizeWithFontCorrection shouldn't be needed.
var bounds = [[_alertPanel contentView] bounds],
offsetX = CGRectGetWidth(bounds) - inset.right,
informativeOffset = [self currentValueForThemeAttribute:@"informative-offset"],
buttonOffset = [self currentValueForThemeAttribute:@"button-offset"],
textWidth = offsetX - inset.left,
messageSize = [([_messageLabel stringValue] || " ") sizeWithFont:[_messageLabel font] inWidth:textWidth],
informationString = [_informativeLabel stringValue],
informativeSize = [(informationString || " ") sizeWithFont:[_informativeLabel font] inWidth:textWidth],
sizeWithFontCorrection = 6.0;
[_messageLabel setFrame:CGRectMake(inset.left, inset.top, textWidth, messageSize.height + sizeWithFontCorrection)];
[_informativeLabel setFrame:CGRectMake(inset.left, CGRectGetMaxY([_messageLabel frame]) + informativeOffset, textWidth, informativeSize.height + sizeWithFontCorrection)];
// Don't let an empty informative label partially cover the buttons.
[_informativeLabel setHidden:!informationString];
var aRepresentativeButton = _buttons[0],
buttonY = MAX(CGRectGetMaxY([_alertImageView frame]), CGRectGetMaxY(informationString ? [_informativeLabel frame] : [_messageLabel frame])) + buttonOffset; // the lower of the bottom of the text and the bottom of the icon.
[aRepresentativeButton setTheme:[self theme]];
[aRepresentativeButton sizeToFit];
// Make the window just tall enough to fit everything. Bit of a hack really.
var minimumSize = [self currentValueForThemeAttribute:@"size"],
desiredHeight = MAX(minimumSize.height, buttonY + CGRectGetHeight([aRepresentativeButton bounds]) + inset.bottom),
deltaY = desiredHeight - CGRectGetHeight(bounds),
frameSize = CGSizeMakeCopy([_alertPanel frame].size);
frameSize.height += deltaY;
[_alertPanel setFrameSize:frameSize];
var count = [_buttons count];
while (count--)
{
var button = _buttons[count];
[button setTheme:[self theme]];
[button sizeToFit];
var buttonBounds = [button bounds],
width = MAX(80.0, CGRectGetWidth(buttonBounds)),
height = CGRectGetHeight(buttonBounds);
offsetX -= width;
[button setFrame:CGRectMake(offsetX, buttonY, width, height)];
offsetX -= 10;
}
}
/*!
Displays the \c CPAlert panel as a modal dialog. The user will not be
able to interact with any other controls until s/he has dismissed the alert
by clicking on one of the buttons.
*/
- (void)runModal
{
[self layoutPanel];
[CPApp runModalForWindow:_alertPanel];
}
/*!
Runs the receiver modally as an alert sheet attached to a specified window.
@param window The parent window for the sheet.
@param modalDelegate The delegate for the modal-dialog session.
@param alertDidEndSelector Message the alert sends to modalDelegate after the sheet is dismissed.
@param contextInfo Contextual data passed to modalDelegate in didEndSelector message.
*/
- (void)beginSheetModalForWindow:(CPWindow)window modalDelegate:(id)modalDelegate didEndSelector:(SEL)alertDidEndSelector contextInfo:(void)contextInfo
{
if (!(_windowStyle & CPDocModalWindowMask))
[self setWindowStyle:CPDocModalWindowMask];
[self layoutPanel];
_didEndSelector = alertDidEndSelector;
_modalDelegate = modalDelegate;
[CPApp beginSheet:_alertPanel modalForWindow:window modalDelegate:self didEndSelector:@selector(_alertDidEnd:returnCode:contextInfo:) contextInfo:contextInfo];
}
/*!
Runs the receiver modally as an alert sheet attached to a specified window.
@param window The parent window for the sheet.
*/
- (void)beginSheetModalForWindow:(CPWindow)window
{
if (!(_windowStyle & CPDocModalWindowMask))
[self setWindowStyle:CPDocModalWindowMask];
[self layoutPanel];
[CPApp beginSheet:_alertPanel modalForWindow:window modalDelegate:self didEndSelector:@selector(_alertDidEnd:returnCode:contextInfo:) contextInfo:nil];
}
- (void)_alertDidEnd:(CPWindow)aSheet returnCode:(CPInteger)returnCode contextInfo:(id)contextInfo
{
if ([_delegate respondsToSelector:@selector(alertDidEnd:returnCode:)])
[_delegate alertDidEnd:self returnCode:returnCode];
if (_didEndSelector)
objj_msgSend(_modalDelegate, _didEndSelector, self, returnCode, contextInfo);
_didEndSelector = nil;
_modalDelegate = nil;
}
/* @ignore */
- (void)_dismissAlert:(CPButton)button
{
if ([_alertPanel isSheet])
[CPApp endSheet:_alertPanel returnCode:[button tag]];
else
{
[CPApp abortModal];
[_alertPanel close];
[self _alertDidEnd:nil returnCode:[button tag] contextInfo:nil];
}
}
@end
+91 -14
View File
@@ -21,6 +21,7 @@
*/
@import <Foundation/CPObject.j>
@import <Foundation/CPTimer.j>
@import "CAMediaTimingFunction.j"
@@ -312,7 +313,7 @@ ACTUAL_FRAME_RATE = 0;
[_timingFunction getControlPointAtIndex:1 values:c1];
[_timingFunction getControlPointAtIndex:2 values:c2];
return CubicBezierAtTime(t,c1[0],c1[1],c2[0],c2[1],_duration);
return CubicBezierAtTime(t, c1[0], c1[1], c2[0], c2[1], _duration);
}
@end
@@ -320,28 +321,104 @@ ACTUAL_FRAME_RATE = 0;
// currently used function to determine time
// 1:1 conversion to js from webkit source files
// UnitBezier.h, WebCore_animation_AnimationBase.cpp
var CubicBezierAtTime = function CubicBezierAtTime(t,p1x,p1y,p2x,p2y,duration)
var CubicBezierAtTime = function CubicBezierAtTime(t, p1x, p1y, p2x, p2y, duration)
{
var ax=0,bx=0,cx=0,ay=0,by=0,cy=0;
var ax = 0,
bx = 0,
cx = 0,
ay = 0,
by = 0,
cy = 0;
// `ax t^3 + bx t^2 + cx t' expanded using Horner's rule.
function sampleCurveX(t) {return ((ax*t+bx)*t+cx)*t;};
function sampleCurveY(t) {return ((ay*t+by)*t+cy)*t;};
function sampleCurveDerivativeX(t) {return (3.0*ax*t+2.0*bx)*t+cx;};
function sampleCurveX(t)
{
return ((ax * t + bx) * t + cx) * t;
}
function sampleCurveY(t)
{
return ((ay * t + by) * t + cy) * t;
}
function sampleCurveDerivativeX(t)
{
return (3.0 * ax * t + 2.0 * bx) * t + cx;
}
// The epsilon value to pass given that the animation is going to run over |duration| seconds. The longer the animation, the more precision is needed in the timing function result to avoid ugly discontinuities.
function solveEpsilon(duration) {return 1.0/(200.0*duration);};
function solve(x,epsilon) {return sampleCurveY(solveCurveX(x,epsilon));};
function solveEpsilon(duration)
{
return 1.0 / (200.0 * duration);
}
function solve(x, epsilon)
{
return sampleCurveY(solveCurveX(x, epsilon));
}
// Given an x value, find a parametric value it came from.
function solveCurveX(x,epsilon) {var t0,t1,t2,x2,d2,i;
function fabs(n) {if(n>=0) {return n;}else {return 0-n;}};
function solveCurveX(x, epsilon)
{
var t0,
t1,
t2 = x,
x2,
d2,
i = 0;
// First try a few iterations of Newton's method -- normally very fast.
for(t2=x, i=0; i<8; i++) {x2=sampleCurveX(t2)-x; if(fabs(x2)<epsilon) {return t2;} d2=sampleCurveDerivativeX(t2); if(fabs(d2)<1e-6) {break;} t2=t2-x2/d2;}
for (; i < 8; i++)
{
x2 = sampleCurveX(t2) - x;
if (ABS(x2) < epsilon)
return t2;
d2 = sampleCurveDerivativeX(t2);
if (ABS(d2) < 1e-6)
break;
t2 = t2 - x2 / d2;
}
// Fall back to the bisection method for reliability.
t0=0.0; t1=1.0; t2=x; if(t2<t0) {return t0;} if(t2>t1) {return t1;}
while(t0<t1) {x2=sampleCurveX(t2); if(fabs(x2-x)<epsilon) {return t2;} if(x>x2) {t0=t2;}else {t1=t2;} t2=(t1-t0)*.5+t0;}
t0 = 0.0;
t1 = 1.0;
t2 = x;
if (t2 < t0)
return t0;
if (t2 > t1)
return t1;
while (t0 < t1)
{
x2 = sampleCurveX(t2);
if (ABS(x2 - x) < epsilon)
return t2;
if (x > x2)
t0 = t2;
else
t1 = t2;
t2 = (t1 - t0) * 0.5 + t0;
}
return t2; // Failure.
};
// Calculate the polynomial coefficients, implicit first and last control points are (0,0) and (1,1).
cx=3.0*p1x; bx=3.0*(p2x-p1x)-cx; ax=1.0-cx-bx; cy=3.0*p1y; by=3.0*(p2y-p1y)-cy; ay=1.0-cy-by;
cx = 3.0 * p1x;
bx = 3.0 * (p2x - p1x) - cx;
ax = 1.0 - cx - bx;
cy = 3.0 * p1y;
by = 3.0 * (p2y - p1y) - cy;
ay = 1.0 - cy - by;
// Convert from input time to parametric value in curve, then from that to output time.
return solve(t, solveEpsilon(duration));
};
+191 -23
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:
@@ -90,7 +90,6 @@ CPRunContinuesResponse = -1002;
CPWindow _previousKeyWindow;
CPWindow _previousMainWindow;
CPMenu _mainMenu;
CPDocumentController _documentController;
CPModalSession _currentSession;
@@ -108,7 +107,7 @@ CPRunContinuesResponse = -1002;
CPPanel _aboutPanel;
CPThemeBlend _themeBlend @accessors(property=themeBlend);
CPArray _themeBlends @accessors(property=themeBlends);
}
/*!
@@ -142,6 +141,8 @@ CPRunContinuesResponse = -1002;
_windows = [];
[_windows addObject:nil];
_themeBlends = [];
}
return self;
@@ -293,11 +294,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)
@@ -310,11 +321,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)
@@ -530,7 +568,7 @@ CPRunContinuesResponse = -1002;
- (BOOL)_handleKeyEquivalent:(CPEvent)anEvent
{
return [[self keyWindow] performKeyEquivalent:anEvent] ||
[_mainMenu performKeyEquivalent:anEvent];
[[self mainMenu] performKeyEquivalent:anEvent];
}
/*!
@@ -574,6 +612,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])
@@ -637,7 +679,7 @@ CPRunContinuesResponse = -1002;
*/
- (CPMenu)mainMenu
{
return _mainMenu;
return [self menu];
}
/*!
@@ -645,21 +687,30 @@ CPRunContinuesResponse = -1002;
@param aMenu the menu to set for the application
*/
- (void)setMainMenu:(CPMenu)aMenu
{
[self setMenu:aMenu];
}
- (void)setMenu:(CPMenu)aMenu
{
if ([aMenu _menuName] === "CPMainMenu")
{
if (_mainMenu === aMenu)
if ([self menu] === aMenu)
return;
_mainMenu = aMenu;
[super setMenu:aMenu];
if ([CPPlatform supportsNativeMainMenu])
window.cpSetMainMenu(_mainMenu);
window.cpSetMainMenu([self menu]);
}
else
[aMenu _setMenuName:@"CPMainMenu"];
}
/*!
Opens the shared color panel.
@param aSender
*/
- (void)orderFrontColorPanel:(id)aSender
{
[[CPColorPanel sharedColorPanel] orderFront:self];
@@ -828,16 +879,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;
@@ -867,6 +940,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];
@@ -885,11 +971,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)
@@ -898,6 +1004,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)
@@ -908,7 +1030,7 @@ CPRunContinuesResponse = -1002;
return;
}
if ([args class] != CPArray)
if (![args isKindOfClass:CPArray])
args = [CPArray arrayWithObject:args];
_args = args;
@@ -939,6 +1061,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;
@@ -1019,6 +1158,16 @@ CPRunContinuesResponse = -1002;
userInfo:nil];
}
- (CPThemeBlend)themeBlend
{
return (_themeBlends.length > 0 ? _themeBlends[0] : nil);
}
- (void)setThemeBlend:(CPThemeBlend)aThemeBlend
{
_themeBlends[0] = aThemeBlend;
}
+ (CPString)defaultThemeName
{
return ([[CPBundle mainBundle] objectForInfoDictionaryKey:"CPDefaultTheme"] || @"Aristo");
@@ -1081,15 +1230,14 @@ function CPApplicationMain(args, namedArgs)
[_CPAppBootstrapper performActions];
}
var _CPAppBootstrapperActions = nil;
var _CPAppBootstrapperActions = nil,
_CPAppThemeURLsToLoad = [];
@implementation _CPAppBootstrapper : CPObject
{
}
+ (CPArray)actions
{
return [@selector(bootstrapPlatform), @selector(loadDefaultTheme), @selector(loadMainCibFile)];
return [@selector(bootstrapPlatform), @selector(loadThemes), @selector(loadMainCibFile)];
}
+ (void)performActions
@@ -1113,17 +1261,30 @@ var _CPAppBootstrapperActions = nil;
return [CPPlatform bootstrap];
}
+ (BOOL)loadDefaultTheme
+ (BOOL)loadThemes
{
var defaultThemeName = [CPApplication defaultThemeName],
themeURL = nil;
_CPAppThemeURLsToLoad.push([CPApplication defaultThemeName]);
if (defaultThemeName === @"Aristo")
themeURL = [[CPBundle bundleForClass:[CPApplication class]] pathForResource:defaultThemeName + @".blend"];
var auxiliaryThemes = ([[CPBundle mainBundle] objectForInfoDictionaryKey:@"CPAuxiliaryThemes"] || []);
_CPAppThemeURLsToLoad = _CPAppThemeURLsToLoad.concat(auxiliaryThemes);
[self loadNextTheme];
return YES;
}
+ (BOOL)loadNextTheme
{
var themeName = _CPAppThemeURLsToLoad.shift();
if (themeName === @"Aristo")
themeURL = [[CPBundle bundleForClass:[CPApplication class]] pathForResource:themeName + @".blend"];
else
themeURL = [[CPBundle mainBundle] pathForResource:defaultThemeName + @".blend"];
themeURL = [[CPBundle mainBundle] pathForResource:themeName + @".blend"];
var blend = [[CPThemeBlend alloc] initWithContentsOfURL:themeURL];
[blend loadWithDelegate:self];
return YES;
@@ -1131,10 +1292,17 @@ var _CPAppBootstrapperActions = nil;
+ (void)blendDidFinishLoading:(CPThemeBlend)aThemeBlend
{
[[CPApplication sharedApplication] setThemeBlend:aThemeBlend];
[CPTheme setDefaultTheme:[CPTheme themeNamed:[CPApplication defaultThemeName]]];
var themeBlends = [CPApp themeBlends];
[self performActions];
[themeBlends addObject:aThemeBlend];
if ([themeBlends count] === 1)
[CPTheme setDefaultTheme:[CPTheme themeNamed:[CPApplication defaultThemeName]]];
if (_CPAppThemeURLsToLoad.length === 0)
[self performActions];
else
[self loadNextTheme];
}
+ (BOOL)loadMainCibFile
+418 -44
View File
@@ -1,5 +1,3 @@
/*
* CPArrayController.j
* AppKit
@@ -29,7 +27,14 @@
@import "CPObjectController.j"
@import "CPKeyValueBinding.j"
/*!
@class CPArrayController
CPArrayController is a bindings compatible class that manages an array.
CPArrayController also provides selection management and sorting capabilities.
*/
@implementation CPArrayController : CPObjectController
{
BOOL _avoidsEmptySelection;
@@ -39,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
@@ -61,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
@@ -102,55 +112,176 @@
return [CPSet setWithObjects:"selectionIndexes"];
}
- (id)init
{
self = [super init];
if (self)
{
_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]]];
}
/*!
Returns YES if the selection should try to be preserved when the content changes, otherwise NO.
@return BOOL YES if the selection is preserved, otherwise NO.
*/
- (BOOL)preservesSelection
{
return _preservesSelection;
}
/*!
Sets whether the selection is kept when the content changes.
@param BOOL aFlag - YES if the selection should be kept, otherwise NO.
*/
- (void)setPreservesSelection:(BOOL)value
{
_preservesSelection = value;
}
/*!
@return BOOL - Returns YES if new objects are automatically selected, otherwise NO.
*/
- (BOOL)selectsInsertedObjects
{
return _selectsInsertedObjects;
}
/*!
Sets whether the controller will automatically select objects as they are inserted.
@return BOOL - YES if new objects are selected, otherwise NO.
*/
- (void)setSelectsInsertedObjects:(BOOL)value
{
_selectsInsertedObjects = value;
}
/*!
@return BOOL - YES if the controller should try to avoid an empty selection otherwise NO.
*/
- (BOOL)avoidsEmptySelection
{
return _avoidsEmptySelection;
}
/*!
Sets whether the controller should try to avoid an empty selection.
@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.
@param id value - the content object of the controller.
*/
- (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 = [];
@@ -184,7 +315,7 @@
// We need to be in control of when notifications fire.
_contentObject = value;
if (_clearsFilterPredicateOnInsertion)
if (_clearsFilterPredicateOnInsertion && _filterPredicate != nil)
[self __setFilterPredicate:nil]; // Causes a _rearrangeObjects.
else
[self _rearrangeObjects];
@@ -198,32 +329,53 @@
[self didChangeValueForKey:@"filterPredicate"];
}
/*!
@ignore
*/
- (void)_setContentArray:(id)anArray
{
[self setContent:anArray];
}
/*!
@ignore
*/
- (void)_setContentSet:(id)aSet
{
[self setContent:aSet];
[self setContent:[aSet allObjects]];
}
/*!
Returns the content array of the controller.
@return id the content array of the receiver
*/
- (id)contentArray
{
return [self content];
}
/*!
Returns the content of the receiver as a CPSet.
@return id - the content of the controller as a set.
*/
- (id)contentSet
{
return [self content];
return [CPSet setWithArray:[self content]];
}
/*!
Sorts and filters a given array and returns it.
@param CPArray anArray - an array of objects.
@return CPArray - the array of sorted objects.
*/
- (CPArray)arrangeObjects:(CPArray)objects
{
var filterPredicate = [self filterPredicate],
sortDescriptors = [self sortDescriptors];
if (filterPredicate && sortDescriptors)
if (filterPredicate && [sortDescriptors count] > 0)
{
var sortedObjects = [objects filteredArrayUsingPredicate:filterPredicate];
[sortedObjects sortUsingDescriptors:sortDescriptors];
@@ -231,12 +383,15 @@
}
else if (filterPredicate)
return [objects filteredArrayUsingPredicate:filterPredicate];
else if (sortDescriptors)
else if ([sortDescriptors count] > 0)
return [objects sortedArrayUsingDescriptors:sortDescriptors];
return [objects copy];
}
/*!
Triggers the filtering of the objects in the controller.
*/
- (void)rearrangeObjects
{
[self willChangeValueForKey:@"arrangedObjects"];
@@ -270,24 +425,40 @@
[self __setSelectionIndexes:oldSelectionIndexes];
}
/*!
@ignore
*/
- (void)__setArrangedObjects:(id)value
{
if (_arrangedObjects === value)
return;
_arrangedObjects = [[_CPObservableArray alloc] initWithArray:value];
_arrangedObjects = [[_CPObservableArray alloc] initWithArray:value];
}
/*!
Returns an array of the controller's objects sorted and filtered.
@return - array of objects
*/
- (id)arrangedObjects
{
return _arrangedObjects;
}
/*!
Returns the receiver's array of sort descriptors.
@return CPArray an array of sort descriptors
*/
- (CPArray)sortDescriptors
{
return _sortDescriptors;
}
/*!
Sets the sort descriptors for the controller.
@param CPArray descriptors - the new sort descriptors.
*/
- (void)setSortDescriptors:(CPArray)value
{
if (_sortDescriptors === value)
@@ -299,14 +470,33 @@
[self _rearrangeObjects];
}
/*!
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
*/
- (CPPredicate)filterPredicate
{
return _filterPredicate;
}
/*!
Sets the predicate for the controller to filter the content.
Passing nil will remove an existing prediate.
@param CPPrediate aPredicate - the new predicate.
*/
- (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"];
}
/*
@@ -319,33 +509,56 @@
return;
_filterPredicate = value;
// Use the non-notification version since arrangedObjects already depends
// on filterPredicate.
// Use the non-notification version.
[self _rearrangeObjects];
}
/*!
Returns a BOOL indicating whether the receiver always returns the multiple values marker when multiple objects are selected.
@return BOOL YES is the controller always uses multiple value markers, otherwise NO.
*/
- (BOOL)alwaysUsesMultipleValuesMarker
{
return _alwaysUsesMultipleValuesMarker;
}
//Selection
/*!
Returns the index of the first object in the controller's selection.
@return unsigned - Index of the first selected object.
*/
- (unsigned)selectionIndex
{
return [_selectionIndexes firstIndex];
}
/*!
Sets the selected index
@param unsigned anIndex - the new index to select
@return BOOL - Returns YES if the selection was changed, otherwise NO.
*/
- (BOOL)setSelectionIndex:(unsigned)index
{
return [self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
}
/*!
Returns an index set of the selected indexes.
@return CPIndexSet - The selected indexes.
*/
- (CPIndexSet)selectionIndexes
{
return _selectionIndexes;
}
/*!
Sets the selection indexes of the controller.
@param CPIndexSet indexes - the indexes to select
@return BOOL - Returns YES if the selection changed, otherwise NO.
*/
- (BOOL)setSelectionIndexes:(CPIndexSet)indexes
{
[self _selectionWillChange]
@@ -393,11 +606,16 @@
// 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.
[[CPKeyValueBinding getBinding:@"selectionIndexes" forObject:self] reverseSetValueFor:@"selectionIndexes"];
var binderClass = [[self class] _binderClassForBinding:@"selectionIndexes"];
[[binderClass getBinding:@"selectionIndexes" forObject:self] reverseSetValueFor:@"selectionIndexes"];
return YES;
}
/*!
Returns an array of the selected objects.
@return CPArray - the selected objects.
*/
- (CPArray)selectedObjects
{
var objects = [[self arrangedObjects] objectsAtIndexes:[self selectionIndexes]];
@@ -405,6 +623,12 @@
return [_CPObservableArray arrayWithArray:(objects || [])];
}
/*!
Sets the selected objects of the controller.
@param CPArray anArray - the objects to select
@return BOOL - Returns YES if the selection was changed, otherwise NO.
*/
- (BOOL)setSelectedObjects:(CPArray)objects
{
[self willChangeValueForKey:@"selectionIndexes"];
@@ -439,12 +663,20 @@
}
//Moving selection
/*!
Returns YES if the previous object, relative to the current selection, in the controller's content array can be selected.
@return BOOL - YES if the object can be selected, otherwise NO.
*/
- (BOOL)canSelectPrevious
{
return [[self selectionIndexes] firstIndex] > 0
}
/*!
Selects the previous object, relative to the current selection, in the controllers arranged content.
@param id sender - the sender of the message.
*/
- (void)selectPrevious:(id)sender
{
var index = [[self selectionIndexes] firstIndex] - 1;
@@ -453,11 +685,20 @@
[self setSelectionIndexes:[CPIndexSet indexSetWithIndex:index]];
}
/*!
Returns YES if the next object, relative to the current selection, in the controller's content array can be selected.
@return BOOL - YES if the object can be selected, otherwise NO.
*/
- (BOOL)canSelectNext
{
return [[self selectionIndexes] firstIndex] < [[self arrangedObjects] count] - 1;
}
/*!
Selects the next object, relative to the current selection, in the controllers arranged content.
@param id sender - the sender of the message.
*/
- (void)selectNext:(id)sender
{
var index = [[self selectionIndexes] firstIndex] + 1;
@@ -468,22 +709,45 @@
//Add/Remove
/*!
Adds object to the receiver's content collection and the arranged objects array.
@param id anObject - the object to add the controller.
*/
- (void)addObject:(id)object
{
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];
_disableSetContent = NO;
if (_clearsFilterPredicateOnInsertion)
[self __setFilterPredicate:nil];
if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:object])
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
@@ -493,14 +757,25 @@
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 receiver's collection.
@param id anObject - The object to add to the collection.
@param int anIndex - The index to insert the object at.
*/
- (void)insertObject:(id)anObject atArrangedObjectIndex:(int)anIndex
{
if (![self canAdd])
@@ -510,7 +785,13 @@
[self willChangeValueForKey:@"filterPredicate"];
[self willChangeValueForKey:@"content"];
/*
See _disableSetContent explanation in addObject:.
*/
_disableSetContent = YES;
[_contentObject insertObject:anObject atIndex:anIndex];
_disableSetContent = NO;
if (_clearsFilterPredicateOnInsertion)
[self __setFilterPredicate:nil];
@@ -532,18 +813,26 @@
[self didChangeValueForKey:@"filterPredicate"];
}
/*!
Removes a given object from the receiver's collection.
@param id anObject - The object to remove from the collection.
*/
- (void)removeObject:(id)object
{
if (![self canRemove])
return;
[self willChangeValueForKey:@"content"];
/*
See _disableSetContent explanation in addObject:.
*/
_disableSetContent = YES;
[_contentObject removeObject:object];
_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.
// 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];
@@ -553,6 +842,11 @@
[self didChangeValueForKey:@"content"];
}
/*!
Creates and adds a new object to the receiver's content and arranged objects.
@param id sender - The sender of the message.
*/
- (void)add:(id)sender
{
if (![self canAdd])
@@ -561,6 +855,10 @@
[self insert:sender];
}
/*!
Creates a new object and inserts it into the receiver's content array.
@param id sender - The sender of the message.
*/
- (void)insert:(id)sender
{
if (![self canInsert])
@@ -571,17 +869,29 @@
[self addObject:newObject];
}
/*!
Removes the controller's selected objects from the controller's collection.
@param id sender - The sender of the message.
*/
- (void)remove:(id)sender
{
[self removeObjects:[[self arrangedObjects] objectsAtIndexes:[self 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
{
[self _removeObjects:[[self arrangedObjects] objectsAtIndexes:indexes]];
}
/*!
Adds an array of objects to the controller's collection.
@param CPArray anArray - The array of objects to add to the collection.
*/
- (void)addObjects:(CPArray)objects
{
if (![self canAdd])
@@ -596,18 +906,28 @@
[self setContent:contentArray];
}
/*!
Removes an array of objects from the collection.
@param CPArray anArray - The array of objects to remove
*/
- (void)removeObjects:(CPArray)objects
{
if (![self canRemove])
return;
[self _removeObjects:objects];
}
/*!
@ignore
*/
- (void)_removeObjects:(CPArray)objects
{
[self willChangeValueForKey:@"content"];
/*
See _disableSetContent explanation in addObject:.
*/
_disableSetContent = YES;
[_contentObject removeObjectsInArray:objects];
_disableSetContent = NO;
var arrangedObjects = [self arrangedObjects],
position = [arrangedObjects indexOfObject:[objects objectAtIndex:0]];
@@ -635,6 +955,10 @@
[self didChangeValueForKey:@"content"];
}
/*!
Returns a BOOL indicating whether an object can be inserted into the controller's collection.
@return BOOL - YES if an object can be inserted, otherwise NO.
*/
- (BOOL)canInsert
{
return [self isEditable];
@@ -642,30 +966,80 @@
@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],
newValue = [destination mutableArrayValueForKeyPath:keyPath];
newValue = [self transformValue:newValue withOptions:options];
[_source setValue:newValue forKey:aBinding];
}
@end
var CPArrayControllerAvoidsEmptySelection = @"CPArrayControllerAvoidsEmptySelection",
CPArrayControllerClearsFilterPredicateOnInsertion = @"CPArrayControllerClearsFilterPredicateOnInsertion",
CPArrayControllerFilterRestrictsInsertion = @"CPArrayControllerFilterRestrictsInsertion",
CPArrayControllerPreservesSelection = @"CPArrayControllerPreservesSelection",
CPArrayControllerSelectsInsertedObjects = @"CPArrayControllerSelectsInsertedObjects",
CPArrayControllerAlwaysUsesMultipleValuesMarker = @"CPArrayControllerAlwaysUsesMultipleValuesMarker",
CPArrayControllerAutomaticallyRearrangesObjects = @"CPArrayControllerAutomaticallyRearrangesObjects";
@implementation CPArrayController (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:coder];
self = [super initWithCoder:aCoder];
if (self)
{
_avoidsEmptySelection = [coder decodeBoolForKey:@"CPArrayControllerAvoidsEmptySelection"];
_clearsFilterPredicateOnInsertion = [coder decodeBoolForKey:@"CPClearsFilterPredicateOnInsertion"];
_filterRestrictsInsertion = [coder decodeBoolForKey:@"CPArrayControllerFilterRestrictsInsertion"];
_preservesSelection = [coder decodeBoolForKey:@"CPArrayControllerPreservesSelection"];
_selectsInsertedObjects = [coder decodeBoolForKey:@"CPArrayControllerSelectsInsertedObjects"];
_alwaysUsesMultipleValuesMarker = [coder decodeBoolForKey:@"CPArrayControllerAlwaysUsesMultipleValuesMarker"];
_avoidsEmptySelection = [aCoder decodeBoolForKey:CPArrayControllerAvoidsEmptySelection];
_clearsFilterPredicateOnInsertion = [aCoder decodeBoolForKey:CPArrayControllerClearsFilterPredicateOnInsertion];
_filterRestrictsInsertion = [aCoder decodeBoolForKey:CPArrayControllerFilterRestrictsInsertion];
_preservesSelection = [aCoder decodeBoolForKey:CPArrayControllerPreservesSelection];
_selectsInsertedObjects = [aCoder decodeBoolForKey:CPArrayControllerSelectsInsertedObjects];
_alwaysUsesMultipleValuesMarker = [aCoder decodeBoolForKey:CPArrayControllerAlwaysUsesMultipleValuesMarker];
_automaticallyRearrangesObjects = [aCoder decodeBoolForKey:CPArrayControllerAutomaticallyRearrangesObjects];
_sortDescriptors = [CPArray array];
if ([self automaticallyPreparesContent])
if (![self content] && [self automaticallyPreparesContent])
[self prepareContent];
else
else if (![self content])
[self _setContentArray:[]];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeBool:_avoidsEmptySelection forKey:CPArrayControllerAvoidsEmptySelection];
[aCoder encodeBool:_clearsFilterPredicateOnInsertion forKey:CPArrayControllerClearsFilterPredicateOnInsertion];
[aCoder encodeBool:_filterRestrictsInsertion forKey:CPArrayControllerFilterRestrictsInsertion];
[aCoder encodeBool:_preservesSelection forKey:CPArrayControllerPreservesSelection];
[aCoder encodeBool:_selectsInsertedObjects forKey:CPArrayControllerSelectsInsertedObjects];
[aCoder encodeBool:_alwaysUsesMultipleValuesMarker forKey:CPArrayControllerAlwaysUsesMultipleValuesMarker];
[aCoder encodeBool:_automaticallyRearrangesObjects forKey:CPArrayControllerAutomaticallyRearrangesObjects];
}
- (void)awakeFromCib
{
[self _selectionWillChange];
+2 -2
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
@@ -184,7 +184,6 @@ var DefaultLineWidth = 1.0;
CGContextBeginPath(ctx);
CGContextAddPath(ctx, _path);
CGContextSetLineWidth(ctx, [self lineWidth]);
CGContextClosePath(ctx);
CGContextStrokePath(ctx);
}
@@ -281,6 +280,7 @@ var DefaultLineWidth = 1.0;
{
CGPathAddPath(_path, nil, other._path);
}
/*!
Remove all path elements; clears path.
*/
+74 -8
View File
@@ -25,7 +25,7 @@
// CPBoxType
CPBoxPrimary = 0;
CPBoxSecondary = 1;
CPBoxSeperator = 2;
CPBoxSeparator = 2;
CPBoxOldStyle = 3;
CPBoxCustom = 4;
@@ -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;
@@ -89,16 +95,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 +144,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)
@@ -234,9 +300,9 @@ CPGrooveBorder = 3;
switch (_boxType)
{
case CPBoxSeperator:
// 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.
case CPBoxSeparator:
// NSBox does not include a horizontal flag for the separator type. We have to determine
// the type of separator to draw by the width and height of the frame.
if (CGRectGetWidth(bounds) === 5.0)
return [self _drawVerticalSeperatorInRect:bounds];
else if (CGRectGetHeight(bounds) === 5.0)
@@ -265,8 +331,8 @@ CPGrooveBorder = 3;
CGContextSetStrokeColor(context, [self borderColor]);
CGContextSetLineWidth(context, 1.0);
CGContextMoveToPoint(context, CGRectGetMinX(aRect), CGRectGetMinY(aRect));
CGContextAddLineToPoint(context, CGRectGetWidth(aRect), CGRectGetMinY(aRect));
CGContextMoveToPoint(context, CGRectGetMinX(aRect), CGRectGetMinY(aRect) + 0.5);
CGContextAddLineToPoint(context, CGRectGetWidth(aRect), CGRectGetMinY(aRect) + 0.5);
CGContextStrokePath(context);
}
@@ -277,8 +343,8 @@ CPGrooveBorder = 3;
CGContextSetStrokeColor(context, [self borderColor]);
CGContextSetLineWidth(context, 1.0);
CGContextMoveToPoint(context, CGRectGetMinX(aRect), CGRectGetMinY(aRect));
CGContextAddLineToPoint(context, CGRectGetMinX(aRect), CGRectGetHeight(aRect));
CGContextMoveToPoint(context, CGRectGetMinX(aRect) + 0.5, CGRectGetMinY(aRect));
CGContextAddLineToPoint(context, CGRectGetMinX(aRect) + 0.5, CGRectGetHeight(aRect));
CGContextStrokePath(context);
}
+88 -34
View File
@@ -83,42 +83,47 @@
{
if (self = [super initWithFrame:aFrame])
{
_rowHeight = 23.0;
_defaultColumnWidth = 140.0;
_minColumnWidth = 80.0;
_imageWidth = 23.0;
_leafWidth = 13.0;
_columnWidths = [];
_pathSeparator = "/";
_tableViews = [];
_tableDelegates = [];
_allowsMultipleSelection = YES;
_allowsEmptySelection = YES;
_tableViewClass = [_CPBrowserTableView class];
_prototypeView = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
[_prototypeView setVerticalAlignment:CPCenterVerticalTextAlignment];
[_prototypeView setValue:[CPColor whiteColor] forThemeAttribute:"text-color" inState:CPThemeStateSelectedDataView];
[_prototypeView setLineBreakMode:CPLineBreakByTruncatingTail];
_horizontalScrollView = [[CPScrollView alloc] initWithFrame:[self bounds]];
[_horizontalScrollView setHasVerticalScroller:NO];
[_horizontalScrollView setAutohidesScrollers:YES];
[_horizontalScrollView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
_contentView = [[CPView alloc] initWithFrame:CGRectMake(0, 0, 0, CGRectGetHeight([self bounds]))];
[_contentView setAutoresizingMask:CPViewHeightSizable];
[_horizontalScrollView setDocumentView:_contentView];
[self addSubview:_horizontalScrollView];
[self _init];
}
return self;
}
- (void)_init
{
_rowHeight = 23.0;
_defaultColumnWidth = 140.0;
_minColumnWidth = 80.0;
_imageWidth = 23.0;
_leafWidth = 13.0;
_columnWidths = [];
_pathSeparator = "/";
_tableViews = [];
_tableDelegates = [];
_allowsMultipleSelection = YES;
_allowsEmptySelection = YES;
_tableViewClass = [_CPBrowserTableView class];
_prototypeView = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
[_prototypeView setVerticalAlignment:CPCenterVerticalTextAlignment];
[_prototypeView setValue:[CPColor whiteColor] forThemeAttribute:"text-color" inState:CPThemeStateSelectedDataView];
[_prototypeView setLineBreakMode:CPLineBreakByTruncatingTail];
_horizontalScrollView = [[CPScrollView alloc] initWithFrame:[self bounds]];
[_horizontalScrollView setHasVerticalScroller:NO];
[_horizontalScrollView setAutohidesScrollers:YES];
[_horizontalScrollView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
_contentView = [[CPView alloc] initWithFrame:CGRectMake(0, 0, 0, CGRectGetHeight([self bounds]))];
[_contentView setAutoresizingMask:CPViewHeightSizable];
[_horizontalScrollView setDocumentView:_contentView];
[self addSubview:_horizontalScrollView];
}
- (void)setPrototypeView:(CPView)aPrototypeView
{
_prototypeView = [CPKeyedUnarchiver unarchiveObjectWithData:
@@ -299,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];
@@ -431,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
@@ -650,6 +657,53 @@
@end
@implementation CPBrowser (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
[self _init];
_allowsEmptySelection = [aCoder decodeBoolForKey:@"CPBrowserAllowsEmptySelectionKey"];
_allowsMultipleSelection = [aCoder decodeBoolForKey:@"CPBrowserAllowsMultipleSelectionKey"];
_prototypeView = [aCoder decodeObjectForKey:@"CPBrowserPrototypeViewKey"];
_rowHeight = [aCoder decodeFloatForKey:@"CPBrowserRowHeightKey"];
_imageWidth = [aCoder decodeFloatForKey:@"CPBrowserImageWidthKey"];
_minColumnWidth = [aCoder decodeFloatForKey:@"CPBrowserMinColumnWidthKey"];
_columnWidths = [aCoder decodeObjectForKey:@"CPBrowserColumnWidthsKey"];
[self setDelegate:[aCoder decodeObjectForKey:@"CPBrowserDelegateKey"]];
[self setAutohidesScroller:[aCoder decodeBoolForKey:@"CPBrowserAutohidesScrollerKey"]];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
// Don't encode the subviews, they're transient and will be recreated from data.
var actualSubviews = _subviews;
_subviews = [];
[super encodeWithCoder:aCoder];
_subviews = actualSubviews;
[aCoder encodeBool:[self autohidesScroller] forKey:@"CPBrowserAutohidesScrollerKey"];
[aCoder encodeBool:_allowsEmptySelection forKey:@"CPBrowserAllowsEmptySelectionKey"];
[aCoder encodeBool:_allowsMultipleSelection forKey:@"CPBrowserAllowsMultipleSelectionKey"];
[aCoder encodeObject:_delegate forKey:@"CPBrowserDelegateKey"];
[aCoder encodeObject:_prototypeView forKey:@"CPBrowserPrototypeViewKey"];
[aCoder encodeFloat:_rowHeight forKey:@"CPBrowserRowHeightKey"];
[aCoder encodeFloat:_imageWidth forKey:@"CPBrowserImageWidthKey"];
[aCoder encodeFloat:_minColumnWidth forKey:@"CPBrowserMinColumnWidthKey"];
[aCoder encodeObject:_columnWidths forKey:@"CPBrowserColumnWidthsKey"];
}
@end
var _CPBrowserResizeControlBackgroundImage = nil;
@implementation _CPBrowserResizeControl : CPView
+152 -19
View File
@@ -70,7 +70,13 @@ CPPushInCellMask = CPPushInButtonMask;
CPChangeGrayCellMask = CPGrayButtonMask;
CPChangeBackgroundCellMask = CPBackgroundButtonMask;
CPButtonStateMixed = CPThemeState("mixed");
CPButtonStateMixed = CPThemeState("mixed");
CPButtonStateBezelStyleRounded = CPThemeState("rounded");
// add all future correspondance between bezel styles and theme state here.
var CPButtonBezelStyleStateMap = [CPDictionary dictionaryWithObjects:[CPButtonStateBezelStyleRounded, nil]
forKeys:[CPRoundedBezelStyle, CPRoundRectBezelStyle]];
CPButtonDefaultHeight = 24.0;
CPButtonImageOffset = 3.0;
@@ -100,6 +106,11 @@ CPButtonImageOffset = 3.0;
CPString _keyEquivalent;
unsigned _keyEquivalentModifierMask;
CPTimer _continuousDelayTimer;
CPTimer _continuousTimer;
float _periodicDelay;
float _periodicInterval;
}
+ (id)buttonWithTitle:(CPString)aTitle
@@ -129,6 +140,11 @@ CPButtonImageOffset = 3.0;
forKeys:[@"image", @"image-offset", @"bezel-inset", @"content-inset", @"bezel-color"]];
}
/*!
Initializes and returns a newly allocated CPButton object with a specified frame rectangle.
@param aFrame The frame rectangle for the created button object.
@return An initialized CPView object or nil if the object couldn't be created.
*/
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
@@ -141,21 +157,31 @@ CPButtonImageOffset = 3.0;
[self setValue:CPImageLeft forThemeAttribute:@"image-position"];
[self setValue:CPScaleNone forThemeAttribute:@"image-scaling"];
_controlSize = CPRegularControlSize;
_keyEquivalent = @"";
_keyEquivalentModifierMask = 0;
// [self setBezelStyle:CPRoundRectBezelStyle];
[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 \c YES if the button has a 'mixed' state in addition to on and off.
Returns a Boolean value indicating whether the button allows a mixed state.
@return \c YES if the button has a 'mixed' state in addition to on and off.
*/
- (BOOL)allowsMixedState
{
@@ -179,6 +205,10 @@ CPButtonImageOffset = 3.0;
[self setState:CPOnState];
}
/*!
Sets the value of the button using an Objective-J object.
@param anObjectValue The value of the button interpreted as an Objective-J object.
*/
- (void)setObjectValue:(id)anObjectValue
{
if (!anObjectValue || anObjectValue === @"" || ([anObjectValue intValue] === 0))
@@ -187,7 +217,7 @@ CPButtonImageOffset = 3.0;
else if (![anObjectValue isKindOfClass:[CPNumber class]])
anObjectValue = CPOnState;
else if (anObjectValue > CPOnState)
else if (anObjectValue >= CPOnState)
anObjectValue = CPOnState
else if (anObjectValue < CPOffState)
@@ -213,6 +243,13 @@ CPButtonImageOffset = 3.0;
}
}
/*!
Returns the button's next state.
@return The button's state. A button can have two or three states.
If it has two, this value is either \c CPOffState (the normal or unpressed state)
or \c CPOnState (the alternate or pressed state).
If it has three, this value can be \c CPOnState (the feature is in effect everywhere), \c CPOffState (the feature is in effect nowhere), or \c CPMixedState (the feature is in effect somewhere).
*/
- (CPInteger)nextState
{
if ([self allowsMixedState])
@@ -225,8 +262,16 @@ CPButtonImageOffset = 3.0;
return 1 - [self state];
}
/*!
Sets the button's next state to \c aState.
@param aState Possible states are any of the CPButton globals:
\c CPOffState, \c CPOnState, \c CPMixedState
*/
- (void)setNextState
{
if ([self infoForBinding:CPValueBinding])
[self setAllowsMixedState:NO];
[self setState:[self nextState]];
}
@@ -248,6 +293,11 @@ CPButtonImageOffset = 3.0;
return [self intValue];
}
/*!
Sets the title displayed by the button when in its normal state.
@param aTitle The string to set as the button's title. This title is always shown on buttons
that dont use their alternate contents when highlighting or displaying their alternate state.
*/
- (void)setTitle:(CPString)aTitle
{
if (_title === aTitle)
@@ -259,6 +309,11 @@ CPButtonImageOffset = 3.0;
[self setNeedsDisplay:YES];
}
/*!
Returns the title displayed on the button when its in its normal state.
@return The title displayed on the receiver when its in its normal state
or the empty string if the button doesnt display a title.
*/
- (CPString)title
{
return _title;
@@ -409,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];
@@ -419,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];
@@ -426,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"];
@@ -461,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)
@@ -492,7 +586,20 @@ CPButtonImageOffset = 3.0;
if (maxSize.height >= 0.0)
size.height = MIN(size.height, maxSize.height);
[self setFrameSize:size];
return size;
}
/*!
Adjust the size of the button to fit the title and surrounding button image.
*/
- (void)sizeToFit
{
[self layoutSubviews];
[self setFrameSize:[self _minimumFrameSize]];
if ([self ephemeralSubviewNamed:@"content-view"])
[self layoutSubviews];
}
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aName
@@ -643,10 +750,24 @@ CPButtonImageOffset = 3.0;
- (void)setBezelStyle:(unsigned)aBezelStyle
{
if (aBezelStyle === _bezelStyle)
return;
var currentState = [CPButtonBezelStyleStateMap objectForKey:_bezelStyle],
newState = [CPButtonBezelStyleStateMap objectForKey:aBezelStyle];
if (currentState)
[self unsetThemeState:currentState];
if (newState)
[self setThemeState:newState];
_bezelStyle = aBezelStyle;
}
- (unsigned)bezelStyle
{
return _bezelStyle;
}
@end
@@ -661,7 +782,9 @@ var CPButtonImageKey = @"CPButtonImageKey",
CPButtonImageDimsWhenDisabledKey = @"CPButtonImageDimsWhenDisabledKey",
CPButtonImagePositionKey = @"CPButtonImagePositionKey",
CPButtonKeyEquivalentKey = @"CPButtonKeyEquivalentKey",
CPButtonKeyEquivalentMaskKey = @"CPButtonKeyEquivalentMaskKey";
CPButtonKeyEquivalentMaskKey = @"CPButtonKeyEquivalentMaskKey",
CPButtonPeriodicDelayKey = @"CPButtonPeriodicDelayKey",
CPButtonPeriodicIntervalKey = @"CPButtonPeriodicIntervalKey";
@implementation CPButton (CPCoding)
@@ -675,7 +798,7 @@ var CPButtonImageKey = @"CPButtonImageKey",
if (self)
{
_controlSize = CPRegularControlSize;
[self _init];
_title = [aCoder decodeObjectForKey:CPButtonTitleKey];
_alternateTitle = [aCoder decodeObjectForKey:CPButtonAlternateTitleKey];
@@ -691,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];
@@ -707,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];
@@ -720,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
+58
View File
@@ -44,6 +44,14 @@ CPCheckBoxImageOffset = 4.0;
return @"check-box";
}
+ (Class)_binderClassForBinding:(CPString)theBinding
{
if (theBinding === CPValueBinding)
return [_CPCheckBoxValueBinder class];
return [super _binderClassForBinding:theBinding];
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
@@ -87,3 +95,53 @@ CPCheckBoxImageOffset = 4.0;
}
@end
@implementation _CPCheckBoxValueBinder : CPBinder
{
}
- (void)setValueFor:(CPString)theBinding
{
var destination = [_info objectForKey:CPObservedObjectKey],
keyPath = [_info objectForKey:CPObservedKeyPathKey],
options = [_info objectForKey:CPOptionsKey],
newValue = [destination valueForKeyPath:keyPath],
isPlaceholder = CPIsControllerMarker(newValue);
if (isPlaceholder)
{
switch (newValue)
{
case CPMultipleValuesMarker:
newValue = CPMixedState;
break;
case CPNoSelectionMarker:
newValue = CPOffState;
break;
case CPNotApplicableMarker:
if ([options objectForKey:CPRaisesForNotApplicableKeysBindingOption])
[CPException raise:CPGenericException reason:@"can't transform non applicable key on: "+_source+" value: "+newValue];
newValue = CPOffState;
break;
}
if (newValue === CPMixedState)
{
[_source setAllowsMixedState:YES];
}
else
{
// Cocoa will always set allowsMixedState to NO
// This behavior will be fine for Cappuccino as well if we (like Cocoa)
// default the CPConditionallySetsEnabledBindingOption to YES
[_source setAllowsMixedState:NO];
}
}
[_source setState:newValue];
}
@end
+87 -8
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
@@ -203,8 +246,8 @@
*/
- (void)setContent:(CPArray)anArray
{
if (_content == anArray)
return;
// reset the _selectionIndexes
[self setSelectionIndexes:[CPIndexSet indexSet]];
_content = anArray;
@@ -312,7 +355,8 @@
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound)
[_items[index] setSelected:YES];
[[CPKeyValueBinding getBinding:@"selectionIndexes" forObject:self] reverseSetValueFor:@"selectionIndexes"];
var binderClass = [[self class] _binderClassForBinding:@"selectionIndexes"];
[[binderClass getBinding:@"selectionIndexes" forObject:self] reverseSetValueFor:@"selectionIndexes"];
if ([_delegate respondsToSelector:@selector(collectionViewDidChangeSelection:)])
[_delegate collectionViewDidChangeSelection:self];
@@ -342,7 +386,7 @@
_items = [];
if (!_itemPrototype || !_content)
if (!_itemPrototype)
return;
var index = 0;
@@ -368,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
@@ -588,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)
{
@@ -726,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];
@@ -897,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
@@ -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:)];
@@ -534,7 +535,7 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
{
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
if(point.x > [self bounds].size.width - 1 || point.x < 1)
if (point.x > [self bounds].size.width - 1 || point.x < 1)
return NO;
[[CPPasteboard pasteboardWithName:CPDragPboard] declareTypes:[CPArray arrayWithObject:CPColorDragType] owner:self];
+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)
+218 -69
View File
@@ -25,7 +25,6 @@
@import "CPView.j"
@import "CPKeyValueBinding.j"
CPLeftTextAlignment = 0;
CPRightTextAlignment = 1;
CPCenterTextAlignment = 2;
@@ -43,21 +42,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 +71,7 @@ CPControlTextDidBeginEditingNotification = "CPControlTextDidBeginEditingNotif
CPControlTextDidChangeNotification = "CPControlTextDidChangeNotification";
CPControlTextDidEndEditingNotification = "CPControlTextDidEndEditingNotification";
var CPControlBlackColor = [CPColor blackColor];
var CPControlBlackColor = [CPColor blackColor];
/*!
@ingroup appkit
@@ -95,8 +94,6 @@ var CPControlBlackColor = [CPColor blackColor];
BOOL _trackingWasWithinFrame;
unsigned _trackingMouseDownFlags;
CGPoint _previousTrackingLocation;
CPString _toolTip;
}
+ (CPDictionary)themeAttributes
@@ -141,18 +138,32 @@ var CPControlBlackColor = [CPColor blackColor];
}
}
- (void)_reverseSetBinding
+ (Class)_binderClassForBinding:(CPString)theBinding
{
var theBinding = [CPKeyValueBinding getBinding:CPValueBinding forObject:self];
[theBinding reverseSetValueFor:@"objectValue"];
if (theBinding === CPValueBinding)
return [_CPValueBinder class];
return [super _binderClassForBinding:theBinding];
}
- (void)_replacementKeyPathForBinding:(CPString)aBinding
/*!
Reverse set the binding iff the CPContinuouslyUpdatesValueBindingOption is set.
*/
- (void)_continuouslyReverseSetBinding
{
if (aBinding === @"value")
return @"objectValue";
var binderClass = [[self class] _binderClassForBinding:CPValueBinding],
theBinding = [binderClass getBinding:CPValueBinding forObject:self];
return [super _replacementKeyPathForBinding:aBinding];
if ([theBinding continuouslyUpdatesValue])
[theBinding reverseSetValueFor:@"objectValue"];
}
- (void)_reverseSetBinding
{
var binderClass = [[self class] _binderClassForBinding:CPValueBinding],
theBinding = [binderClass getBinding:CPValueBinding forObject:self];
[theBinding reverseSetValueFor:@"objectValue"];
}
- (id)initWithFrame:(CGRect)aFrame
@@ -169,7 +180,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
@@ -178,7 +190,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Returns the receiver's target action
Returns the receiver's target action.
*/
- (SEL)action
{
@@ -187,6 +199,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
@@ -204,6 +217,7 @@ 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
*/
@@ -222,33 +236,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.
*/
@@ -260,7 +247,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
@@ -270,6 +257,9 @@ var CPControlBlackColor = [CPColor blackColor];
_sendActionOn &= ~CPPeriodicMask;
}
/*!
Returns YES if the receiver tracks the mouse outside the frame, otherwise NO.
*/
- (BOOL)tracksMouseOutsideOfFrame
{
return NO;
@@ -286,9 +276,14 @@ var CPControlBlackColor = [CPColor blackColor];
[self stopTracking:_previousTrackingLocation at:currentLocation mouseIsUp:YES];
_trackingMouseDownFlags = 0;
if (isWithinFrame)
[self setThemeState:CPThemeStateHovered];
}
else
{
[self unsetThemeState:CPThemeStateHovered];
if (type === CPLeftMouseDown)
{
_trackingMouseDownFlags = [anEvent modifierFlags];
@@ -327,6 +322,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])
@@ -349,11 +349,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;
@@ -384,8 +391,27 @@ var CPControlBlackColor = [CPColor blackColor];
[self trackMouse:anEvent];
}
- (void)mouseEntered:(CPEvent)anEvent
{
if (![self isEnabled])
return;
[self setThemeState:CPThemeStateHovered];
}
- (void)mouseExited:(CPEvent)anEvent
{
var currentLocation = [self convertPoint:[anEvent locationInWindow] fromView:nil],
isWithinFrame = [self tracksMouseOutsideOfFrame] || CGRectContainsPoint([self bounds], currentLocation);
// Make sure we're not still in the frame because Cappuccino will sent mouseExited events
// for all of the (ephemeral) subviews of a view as well.
if (!isWithinFrame)
[self unsetThemeState:CPThemeStateHovered];
}
/*!
Returns the receiver's object value
Returns the receiver's object value.
*/
- (id)objectValue
{
@@ -393,7 +419,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Set's the receiver's object value
Sets the receiver's object value.
*/
- (void)setObjectValue:(id)anObject
{
@@ -404,7 +430,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Returns the receiver's float value
Returns the receiver's float value.
*/
- (float)floatValue
{
@@ -413,7 +439,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Sets the receiver's float value
Sets the receiver's float value.
*/
- (void)setFloatValue:(float)aValue
{
@@ -421,7 +447,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Returns the receiver's double value
Returns the receiver's double value.
*/
- (double)doubleValue
{
@@ -430,7 +456,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Set's the receiver's double value
Sets the receiver's double value.
*/
- (void)setDoubleValue:(double)anObject
{
@@ -438,7 +464,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Returns the receiver's int value
Returns the receiver's int value.
*/
- (int)intValue
{
@@ -447,7 +473,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Set's the receiver's int value
Sets the receiver's int value.
*/
- (void)setIntValue:(int)anObject
{
@@ -455,7 +481,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Returns the receiver's int value
Returns the receiver's int value.
*/
- (int)integerValue
{
@@ -464,7 +490,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Set's the receiver's int value
Sets the receiver's int value.
*/
- (void)setIntegerValue:(int)anObject
{
@@ -472,7 +498,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Returns the receiver's string value
Returns the receiver's string value.
*/
- (CPString)stringValue
{
@@ -480,7 +506,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Set's the receiver's string value
Sets the receiver's string value.
*/
- (void)setStringValue:(CPString)anObject
{
@@ -556,96 +582,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)
@@ -654,16 +783,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)
@@ -672,6 +814,9 @@ var CPControlBlackColor = [CPColor blackColor];
[self unsetThemeState:CPThemeStateHighlighted];
}
/*!
Returns YES if the control is highlighted, otherwise NO.
*/
- (BOOL)isHighlighted
{
return [self hasThemeState:CPThemeStateHighlighted];
@@ -695,6 +840,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
*/
@@ -718,6 +864,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
@@ -727,8 +874,10 @@ 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];
+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
+6 -5
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
{
@@ -390,13 +390,14 @@ var CPSharedDocumentController = nil;
- (void)noteNewRecentDocument:(CPDocument)aDocument
{
[self noteNewRecentDocumentURL:[[aDocument fileURL] absoluteString]];
[self noteNewRecentDocumentURL:[aDocument fileURL]];
}
- (void)noteNewRecentDocumentURL:(CPString)aURL
- (void)noteNewRecentDocumentURL:(CPURL)aURL
{
var urlAsString = [aURL isKindOfClass:CPString] ? aURL : [aURL absoluteString];
if (typeof window["cpNoteNewRecentDocumentPath"] === 'function')
window.cpNoteNewRecentDocumentPath(aURL);
window.cpNoteNewRecentDocumentPath(urlAsString);
[self _updateRecentDocumentsMenu];
}
+28 -24
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.
@@ -220,14 +220,14 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
[_draggingUpdateTimer invalidate];
_draggingUpdateTimer = nil;
var dragOperation = CPDragOperationCopy;
var dragOperation = CPDragOperationCopy,
// We have to convert base to bridge since the drag event comes from the source window, not the drag window.
var draggingDestination = [aPlatformWindow _dragHitTest:aLocation pasteboard:[CPDragServerDraggingInfo draggingPasteboard]];
draggingDestination = [aPlatformWindow _dragHitTest:aLocation pasteboard:[CPDragServerDraggingInfo draggingPasteboard]];
if (draggingDestination)
_draggingLocation = [DRAGGING_WINDOW(draggingDestination) convertPlatformWindowToBase:aLocation];
if(draggingDestination !== _draggingDestination)
if (draggingDestination !== _draggingDestination)
{
if ([_draggingDestination respondsToSelector:@selector(draggingExited:)])
[_draggingDestination draggingExited:CPDragServerDraggingInfo];
@@ -261,7 +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];
}
}
}
@@ -456,8 +460,8 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
}
else if (type === CPKeyDown)
{
var keyCode = [anEvent keyCode];
if (keyCode === CPEscapeKeyCode)
var characters = [anEvent characters];
if (characters === CPEscapeFunctionKey)
{
_dragOperation = CPDragOperationNone;
[self draggingEndedInPlatformWindow:platformWindow globalLocation:CGPointMakeZero() operation:_dragOperation];
+76 -59
View File
@@ -158,23 +158,24 @@ CPFindFunctionKey = "\uF745";
CPHelpFunctionKey = "\uF746";
CPModeSwitchFunctionKey = "\uF747";
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,
@@ -210,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
@@ -234,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
@@ -256,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
@@ -277,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;
@@ -305,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;
@@ -329,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;
@@ -348,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
@@ -371,7 +381,7 @@ var _CPEventPeriodicEventPeriod = 0,
}
/*!
Returns event information as a bit mask
Returns event information as a bit mask.
*/
- (unsigned)modifierFlags
{
@@ -379,7 +389,7 @@ var _CPEventPeriodicEventPeriod = 0,
}
/*!
Returns the time the event occurred
Returns the time the event occurred.
*/
- (CPTimeInterval)timestamp
{
@@ -395,7 +405,7 @@ var _CPEventPeriodicEventPeriod = 0,
}
/*!
Returns the event's associated window
Returns the event's associated window.
*/
- (CPWindow)window
{
@@ -426,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
{
@@ -434,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
@@ -444,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
@@ -453,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
@@ -462,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
@@ -494,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.
*/
@@ -527,7 +541,8 @@ var _CPEventPeriodicEventPeriod = 0,
if (_CPEventUpperCaseRegex.test(aKeyEquivalent))
aKeyEquivalentModifierMask |= CPShiftKeyMask;
if (CPBrowserIsOperatingSystem(CPWindowsOperatingSystem) && (aKeyEquivalentModifierMask & CPCommandKeyMask))
// Windows and Linux don't have command keys, so just switch it to ctrl.
if (!CPBrowserIsOperatingSystem(CPMacOperatingSystem) && (aKeyEquivalentModifierMask & CPCommandKeyMask))
{
aKeyEquivalentModifierMask |= CPControlKeyMask;
aKeyEquivalentModifierMask &= ~CPCommandKeyMask;
@@ -556,32 +571,35 @@ var _CPEventPeriodicEventPeriod = 0,
if (_modifierFlags & (CPCommandKeyMask | CPControlKeyMask))
return YES;
for(var i=0; i<characterCount; i++)
// Cocoa does not consider space, backspace, or escape a key equivalent
// if the first responder is a text field (presumably a subclass of NSText).
var firstResponderIsText = [[_window firstResponder] isKindOfClass:[CPTextField class]];
for (var i = 0; i < characterCount; i++)
{
switch(_characters.charAt(i))
var c = _characters.charAt(i);
if ((c >= CPUpArrowFunctionKey && c <= CPModeSwitchFunctionKey) ||
c === CPEnterCharacter ||
c === CPNewlineCharacter ||
c === CPCarriageReturnCharacter ||
c === CPEscapeFunctionKey ||
(!firstResponderIsText &&
(c === CPSpaceFunctionKey ||
c === CPDeleteCharacter ||
c === CPBackspaceCharacter)))
{
case CPBackspaceCharacter:
case CPDeleteCharacter:
case CPDeleteFunctionKey:
case CPTabCharacter:
case CPCarriageReturnCharacter:
case CPNewlineCharacter:
case CPEscapeFunctionKey:
case CPPageUpFunctionKey:
case CPPageDownFunctionKey:
case CPLeftArrowFunctionKey:
case CPUpArrowFunctionKey:
case CPRightArrowFunctionKey:
case CPDownArrowFunctionKey:
return YES;
return YES;
}
}
// FIXME: More cases? Space?
// FIXME: More cases?
return NO;
}
/*!
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
*/
@@ -594,7 +612,7 @@ var _CPEventPeriodicEventPeriod = 0,
}
/*!
Stops the periodic events from being generated
Stops the periodic events from being generated.
*/
+ (void)stopPeriodicEvents
{
@@ -632,4 +650,3 @@ function _CPEventFromNativeMouseEvent(aNativeEvent, anEventType, aPoint, modifie
return aNativeEvent;
}
+3 -3
View File
@@ -23,7 +23,7 @@
@import <Foundation/CPObject.j>
/*!
/*!
@ingroup appkit
@class CPFlashMovie
@@ -52,10 +52,10 @@
- (id)initWithFile:(CPString)aFilename
{
self = [super init];
if (self)
_filename = aFilename;
return self;
}
+26 -23
View File
@@ -32,10 +32,10 @@ var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
@implementation CPFlashView : CPView
{
CPFlashMovie _flashMovie;
CPDictionary _params;
CPDictionary _paramElements;
#if PLATFORM(DOM)
#if PLATFORM(DOM)
DOMElement _DOMParamElement;
DOMElement _DOMObjectElement;
DOMElement _DOMInnerObjectElement;
@@ -45,7 +45,7 @@ var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
#if PLATFORM(DOM)
@@ -58,24 +58,24 @@ var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
_DOMObjectElement.style.left = @"0px";
_DOMObjectElement.type = @"application/x-shockwave-flash";
_DOMObjectElement.setAttribute(@"classid", IEFlashCLSID);
_DOMParamElement = document.createElement(@"param");
_DOMParamElement.name = @"movie";
_DOMInnerObjectElement = document.createElement(@"object");
_DOMInnerObjectElement.width = @"100%";
_DOMInnerObjectElement.height = @"100%";
_DOMObjectElement.appendChild(_DOMParamElement);
_DOMObjectElement.appendChild(_DOMInnerObjectElement);
_DOMElement.appendChild(_DOMObjectElement);
}
else
[self _rebuildIEObjects];
#endif
}
return self;
}
@@ -83,7 +83,7 @@ var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
{
if (_flashMovie == aFlashMovie)
return;
_flashMovie = aFlashMovie;
#if PLATFORM(DOM)
if (!CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
@@ -105,14 +105,14 @@ var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
{
var varString = @"",
enumerator = [aDictionary keyEnumerator];
var key;
while (key = [enumerator nextObject])
varString = [varString stringByAppendingFormat:@"&%@=%@", key, [aDictionary objectForKey:key]];
if (!_params)
_params = [CPDictionary dictionary];
[_params setObject:varString forKey:@"flashvars"];
[self setParameters:_params];
}
@@ -129,28 +129,31 @@ var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
{
var elements = [_paramElements allValues],
count = [elements count];
for (var i = 0; i < count; i++)
_DOMObjectElement.removeChild([elements objectAtIndex:i]);
}
#endif
_params = aDictionary;
if (!_params)
_params = aDictionary;
else
[_params addEntriesFromDictionary:aDictionary];
#if PLATFORM(DOM)
if (!CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
{
_paramElements = [CPDictionary dictionary];
var enumerator = [_params keyEnumerator],
key;
while (key = [enumerator nextObject] && _DOMObjectElement)
while (_DOMObjectElement && (key = [enumerator nextObject]))
{
var param = document.createElement(@"param");
param.name = key;
param.value = [_params objectForKey:key];
_DOMObjectElement.appendChild(param);
[_paramElements setObject:param forKey:key];
}
}
@@ -170,17 +173,17 @@ var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
_DOMElement.innerHTML = @"";
if (![_flashMovie filename])
return;
var paramString = [CPString stringWithFormat:@"<param name='movie' value='%@' />", [_flashMovie filename]],
paramEnumerator = [_params keyEnumerator],
key;
while (key = [paramEnumerator nextObject])
paramString = [paramString stringByAppendingFormat:@"<param name='%@' value='%@' />", key, [_params objectForKey:key]];
_DOMObjectElement = document.createElement(@"object");
_DOMElement.appendChild(_DOMObjectElement);
_DOMObjectElement.outerHTML = [CPString stringWithFormat:@"<object classid=%@ width=%@ height=%@>%@</object>", IEFlashCLSID, CGRectGetWidth([self bounds]), CGRectGetHeight([self bounds]), paramString];
}
#endif
+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;
};
+38 -32
View File
@@ -45,7 +45,7 @@ var CPSharedFontManager = nil,
{
if (!CPSharedFontManager)
CPSharedFontManager = [[CPFontManagerFactory alloc] init];
return CPSharedFontManager;
}
@@ -65,7 +65,7 @@ var CPSharedFontManager = nil,
- (CPArray)availableFonts
{
if (!_availableFonts)
{
{
_CPFontDetectSpan = document.createElement("span");
_CPFontDetectSpan.fontSize = "24px";
_CPFontDetectSpan.appendChild(document.createTextNode("mmmmmmmmmml"));
@@ -74,13 +74,14 @@ var CPSharedFontManager = nil,
div.style.top = "-1000px";
div.appendChild(_CPFontDetectSpan);
document.getElementsByTagName("body")[0].appendChild(div);
_CPFontDetectReferenceFonts = _CPFontDetectPickTwoDifferentFonts(["monospace", "serif", "sans-serif", "cursive"]);
_CPFontDetectReferenceFonts = _CPFontDetectPickTwoDifferentFonts(["monospace", "serif", "sans-serif", "cursive"]);
_availableFonts = [];
for (var i = 0; i < _CPFontDetectAllFonts.length; i++) {
for (var i = 0; i < _CPFontDetectAllFonts.length; i++)
{
var available = _CPFontDetectFontAvailable(_CPFontDetectAllFonts[i]);
if (available)
if (available)
_availableFonts.push(_CPFontDetectAllFonts[i]);
}
}
@@ -101,8 +102,8 @@ var CPSharedFontManager = nil,
var _CPFontDetectSpan,
_CPFontDetectReferenceFonts,
_CPFontDetectAllFonts = [
/* "04b_21","A Charming Font","Abadi MT Condensed","Abadi MT Condensed Extra Bold","Abadi MT Condensed Light","Academy Engraved LET","Agency FB","Alba","Alba Matter","Alba Super","Algerian",*/
"American Typewriter",
/* "04b_21","A Charming Font","Abadi MT Condensed","Abadi MT Condensed Extra Bold","Abadi MT Condensed Light","Academy Engraved LET","Agency FB","Alba","Alba Matter","Alba Super","Algerian",*/
"American Typewriter",
/* "Andale Mono","Andale Mono IPA","Andy", */
"Apple Chancery","Arial","Arial Black","Arial Narrow","Arial Rounded MT Bold","Arial Unicode MS",
/* "Avant Garde","Avantgarde","Baby Kruffy","Base 02","Baskerville","Baskerville Old Face","Bauhaus 93","Beesknees ITC","Bell MT","Berlin Sans FB","Berlin Sans FB Demi","Bernard MT Condensed","Bickley Script",*/
@@ -122,8 +123,8 @@ var _CPFontDetectSpan,
/* "GlooGun","Gloucester MT Extra Condensed","Goudy Old Style","Goudy Stout","Haettenschweiler","Harlow Solid Italic","Harrington",*/
"Helvetica","Helvetica Narrow","Helvetica Neue","Herculanum","High Tower Text","Highlight LET","Hoefler Text","Impact","Imprint MT Shadow",
/* "Informal Roman","Jenkins v2.0","John Handy LET","Jokerman","Jokerman LET","Jokewood","Juice ITC","Kabel Ult BT","Kartika","Kino MT","Kristen ITC","Kunstler Script","La Bamba LET", */
"Lucida","Lucida Bright","Lucida Calligraphy","Lucida Console","Lucida Fax","Lucida Grande","Lucida Handwriting","Lucida Sans","Lucida Sans Typewriter","Lucida Sans Unicode",
/* "Luxi Mono","Luxi Sans","Luxi Serif","MARKETPRO","MS Reference Sans Serif","MS Reference Serif","Magneto","Maiandra GD", */
"Lucida","Lucida Bright","Lucida Calligraphy","Lucida Console","Lucida Fax","Lucida Grande","Lucida Handwriting","Lucida Sans","Lucida Sans Typewriter","Lucida Sans Unicode",
/* "Luxi Mono","Luxi Sans","Luxi Serif","MARKETPRO","MS Reference Sans Serif","MS Reference Serif","Magneto","Maiandra GD", */
"Marker Felt",
/* "Matisse ITC","Matura MT Script Capitals","Mead Bold","Mekanik LET","Mercurius Script MT Bold", */
"Microsoft Sans Serif","Milano LET","Minion Web","MisterEarl BT","Mistral","Monaco","Monotype Corsiva","Monotype.com","New Century Schoolbook","New York","News Gothic MT",
@@ -136,39 +137,44 @@ var _CPFontDetectSpan,
"Zapfino"];
// Compare against the reference fonts. Return true if it produces a different size than at least one of them.
var _CPFontDetectFontAvailable = function(font) {
for (var i = 0; i < _CPFontDetectReferenceFonts.length; i++)
if (_CPFontDetectCompareFonts(_CPFontDetectReferenceFonts[i], font))
return true;
return false;
var _CPFontDetectFontAvailable = function(font)
{
for (var i = 0; i < _CPFontDetectReferenceFonts.length; i++)
if (_CPFontDetectCompareFonts(_CPFontDetectReferenceFonts[i], font))
return true;
return false;
}
var _CPFontDetectCache = {};
// Compares two given fonts. Returns true if they produce different sizes (i.e. fontA didn't fallback to fontB)
var _CPFontDetectCompareFonts = function(fontA, fontB) {
var _CPFontDetectCompareFonts = function(fontA, fontB)
{
var a;
if (_CPFontDetectCache[fontA]) {
if (_CPFontDetectCache[fontA])
a = _CPFontDetectCache[fontA];
} else {
_CPFontDetectSpan.style.fontFamily = '"' + fontA + '"';
else
{
_CPFontDetectSpan.style.fontFamily = '"' + fontA + '"';
_CPFontDetectCache[fontA] = a = { w: _CPFontDetectSpan.offsetWidth, h: _CPFontDetectSpan.offsetHeight };
}
_CPFontDetectSpan.style.fontFamily= '"' + fontB + '", "' + fontA + '"';
var bWidth = _CPFontDetectSpan.offsetWidth;
var bHeight = _CPFontDetectSpan.offsetHeight;
return (a.w != bWidth || a.h != bHeight);
_CPFontDetectSpan.style.fontFamily = '"' + fontB + '", "' + fontA + '"';
var bWidth = _CPFontDetectSpan.offsetWidth,
bHeight = _CPFontDetectSpan.offsetHeight;
return (a.w != bWidth || a.h != bHeight);
}
// Test the candidate fonts pairwise until we find two that are different. Otherwise return the first.
var _CPFontDetectPickTwoDifferentFonts = function(candidates) {
for (var i = 0; i < candidates.length; i++)
for (var j = 0; j < i; j++)
if (_CPFontDetectCompareFonts(candidates[i], candidates[j]))
return [candidates[i], candidates[j]];
return [candidates[0]];
var _CPFontDetectPickTwoDifferentFonts = function(candidates)
{
for (var i = 0; i < candidates.length; i++)
for (var j = 0; j < i; j++)
if (_CPFontDetectCompareFonts(candidates[i], candidates[j]))
return [candidates[i], candidates[j]];
return [candidates[0]];
}
[CPFontManager setFontManagerFactory:[CPFontManager class]];
+1 -1
View File
@@ -71,7 +71,7 @@ function CPPointMake(x, y)
function CPRectInset(aRect, dX, dY)
{
return CPRectMake( aRect.origin.x + dX, aRect.origin.y + dY,
aRect.size.width - 2 * dX, aRect.size.height - 2*dY);
aRect.size.width - 2 * dX, aRect.size.height - 2 * dY);
}
/*!
+4 -4
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;
}
/*!
@@ -71,10 +71,10 @@ var CPGraphicsContextCurrent = nil;
- (id)initWithGraphicsPort:(CPContext)aGraphicsPort
{
self = [super init];
if (self)
_graphicsPort = aGraphicsPort;
return self;
}
+22 -3
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);
@@ -65,7 +66,7 @@ function CPAppKitImage(aFilename, aSize)
return CPImageInBundle(aFilename, aSize, [CPBundle bundleForClass:[CPView class]]);
}
/*!
/*!
@ingroup appkit
@class CPImage
@@ -73,7 +74,7 @@ function CPAppKitImage(aFilename, aSize)
all image types supported by the browser.
@par Delegate Methods
@delegate -(void)imageDidLoad:(CPImage)image;
Called when the specified image has finished loading.
@param image the image that loaded
@@ -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
{
+45 -44
View File
@@ -43,7 +43,7 @@ CPImageAlignRight = 8;
var CPImageViewShadowBackgroundColor = nil,
CPImageViewEmptyPlaceholderImage = nil;
var LEFT_SHADOW_INSET = 3.0,
RIGHT_SHADOW_INSET = 3.0,
TOP_SHADOW_INSET = 3.0,
@@ -51,7 +51,7 @@ var LEFT_SHADOW_INSET = 3.0,
VERTICAL_SHADOW_INSET = TOP_SHADOW_INSET + BOTTOM_SHADOW_INSET,
HORIZONTAL_SHADOW_INSET = LEFT_SHADOW_INSET + RIGHT_SHADOW_INSET;
/*!
/*!
@ingroup appkit
@class CPImageView
@@ -60,7 +60,7 @@ var LEFT_SHADOW_INSET = 3.0,
@implementation CPImageView : CPControl
{
DOMElement _DOMImageElement;
BOOL _hasShadow;
CPView _shadowView;
@@ -73,14 +73,14 @@ var LEFT_SHADOW_INSET = 3.0,
+ (void)initialize
{
var bundle = [CPBundle bundleForClass:[CPView class]];
CPImageViewEmptyPlaceholderImage = [[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"empty.png"]];
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
#if PLATFORM(DOM)
@@ -96,11 +96,11 @@ var LEFT_SHADOW_INSET = 3.0,
}
CPDOMDisplayServerAppendChild(_DOMElement, _DOMImageElement);
_DOMImageElement.style.visibility = "hidden";
#endif
}
return self;
}
@@ -121,29 +121,29 @@ var LEFT_SHADOW_INSET = 3.0,
- (void)setObjectValue:(CPImage)anImage
{
var oldImage = [self objectValue];
if (oldImage === anImage)
return;
[super setObjectValue:anImage];
var defaultCenter = [CPNotificationCenter defaultCenter];
if (oldImage)
[defaultCenter removeObserver:self name:CPImageDidLoadNotification object:oldImage];
var newImage = [self objectValue];
#if PLATFORM(DOM)
_DOMImageElement.src = newImage ? [newImage filename] : [CPImageViewEmptyPlaceholderImage filename];
#endif
var size = [newImage size];
if (size && size.width === -1 && size.height === -1)
{
[defaultCenter addObserver:self selector:@selector(imageDidLoad:) name:CPImageDidLoadNotification object:newImage];
#if PLATFORM(DOM)
_DOMImageElement.width = 0;
_DOMImageElement.height = 0;
@@ -162,7 +162,7 @@ var LEFT_SHADOW_INSET = 3.0,
- (void)imageDidLoad:(CPNotification)aNotification
{
[self hideOrDisplayContents];
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
@@ -184,25 +184,25 @@ var LEFT_SHADOW_INSET = 3.0,
{
if (_hasShadow == shouldHaveShadow)
return;
_hasShadow = shouldHaveShadow;
if (_hasShadow)
{
_shadowView = [[CPShadowView alloc] initWithFrame:[self bounds]];
[self addSubview:_shadowView];
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
else
{
[_shadowView removeFromSuperview];
_shadowView = nil;
}
[self hideOrDisplayContents];
}
@@ -215,12 +215,12 @@ var LEFT_SHADOW_INSET = 3.0,
{
if (_imageAlignment == anImageAlignment)
return;
_imageAlignment = anImageAlignment;
if (![self image])
return;
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
@@ -238,14 +238,14 @@ var LEFT_SHADOW_INSET = 3.0,
- (void)setImageScaling:(CPImageScaling)anImageScaling
{
[super setImageScaling:anImageScaling];
#if PLATFORM(DOM)
if ([self currentValueForThemeAttribute:@"image-scaling"] === CPScaleToFit)
{
CPDOMDisplayServerSetStyleLeftTop(_DOMImageElement, NULL, 0.0, 0.0);
}
#endif
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
@@ -314,7 +314,7 @@ var LEFT_SHADOW_INSET = 3.0,
else
{
var size = [image size];
if (size.width == -1 && size.height == -1)
return;
@@ -331,7 +331,7 @@ var LEFT_SHADOW_INSET = 3.0,
{
var imageRatio = size.width / size.height,
viewRatio = width / height;
if (viewRatio > imageRatio)
width = height * imageRatio;
else
@@ -348,7 +348,7 @@ var LEFT_SHADOW_INSET = 3.0,
width = size.width;
height = size.height;
}
if (imageScaling == CPScaleNone)
{
#if PLATFORM(DOM)
@@ -357,8 +357,9 @@ var LEFT_SHADOW_INSET = 3.0,
#endif
}
var x, y;
var x,
y;
switch (_imageAlignment)
{
case CPImageAlignLeft:
@@ -366,7 +367,7 @@ var LEFT_SHADOW_INSET = 3.0,
case CPImageAlignBottomLeft:
x = 0.0;
break;
case CPImageAlignRight:
case CPImageAlignTopRight:
case CPImageAlignBottomRight:
@@ -377,7 +378,7 @@ var LEFT_SHADOW_INSET = 3.0,
x = (boundsWidth - width) / 2.0;
break;
}
switch (_imageAlignment)
{
case CPImageAlignTop:
@@ -385,7 +386,7 @@ var LEFT_SHADOW_INSET = 3.0,
case CPImageAlignTopRight:
y = 0.0;
break;
case CPImageAlignBottom:
case CPImageAlignBottomLeft:
case CPImageAlignBottomRight:
@@ -395,7 +396,7 @@ var LEFT_SHADOW_INSET = 3.0,
default:
y = (boundsHeight - height) / 2.0;
break;
}
}
#if PLATFORM(DOM)
CPDOMDisplayServerSetStyleLeftTop(_DOMImageElement, NULL, x, y);
@@ -403,7 +404,7 @@ var LEFT_SHADOW_INSET = 3.0,
}
_imageRect = _CGRectMake(x, y, width, height);
if (_hasShadow)
[_shadowView setFrame:_CGRectMake(x - LEFT_SHADOW_INSET, y - TOP_SHADOW_INSET, width + insetWidth, height + insetHeight)];
}
@@ -450,7 +451,7 @@ var LEFT_SHADOW_INSET = 3.0,
[self setImage:images[0]];
[self sendAction:[self action] to:[self target]];
}
return YES;
}
@@ -485,7 +486,7 @@ var CPImageViewImageKey = @"CPImageViewImageKey",
#endif
self = [super initWithCoder:aCoder];
if (self)
{
#if PLATFORM(DOM)
@@ -494,14 +495,14 @@ var CPImageViewImageKey = @"CPImageViewImageKey",
[self setHasShadow:[aCoder decodeBoolForKey:CPImageViewHasShadowKey]];
[self setImageAlignment:[aCoder decodeIntForKey:CPImageViewImageAlignmentKey]];
if ([aCoder decodeBoolForKey:CPImageViewIsEditableKey] || NO)
[self setEditable:YES];
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
return self;
}
@@ -512,21 +513,21 @@ var CPImageViewImageKey = @"CPImageViewImageKey",
*/
- (void)encodeWithCoder:(CPCoder)aCoder
{
// We do this in order to avoid encoding the _shadowView, which
// We do this in order to avoid encoding the _shadowView, which
// should just automatically be created programmatically as needed.
if (_shadowView)
{
var actualSubviews = _subviews;
_subviews = [_subviews copy];
[_subviews removeObjectIdenticalTo:_shadowView];
}
[super encodeWithCoder:aCoder];
if (_shadowView)
_subviews = actualSubviews;
[aCoder encodeBool:_hasShadow forKey:CPImageViewHasShadowKey];
[aCoder encodeInt:_imageAlignment forKey:CPImageViewImageAlignmentKey];
+95 -90
View File
@@ -35,7 +35,7 @@ var exposedBindingsMap = [CPDictionary new],
var CPBindingOperationAnd = 0,
CPBindingOperationOr = 1;
@implementation CPKeyValueBinding : CPObject
@implementation CPBinder : CPObject
{
CPDictionary _info;
id _source;
@@ -43,12 +43,12 @@ var CPBindingOperationAnd = 0,
+ (void)exposeBinding:(CPString)aBinding forClass:(Class)aClass
{
var bindings = [exposedBindingsMap objectForKey:[aClass hash]];
var bindings = [exposedBindingsMap objectForKey:[aClass UID]];
if (!bindings)
{
bindings = [];
[exposedBindingsMap setObject:bindings forKey:[aClass hash]];
[exposedBindingsMap setObject:bindings forKey:[aClass UID]];
}
bindings.push(aBinding);
@@ -56,12 +56,12 @@ var CPBindingOperationAnd = 0,
+ (CPArray)exposedBindingsForClass:(Class)aClass
{
return [[exposedBindingsMap objectForKey:[aClass hash]] copy];
return [[exposedBindingsMap objectForKey:[aClass UID]] copy];
}
+ (CPKeyValueBinding)getBinding:(CPString)aBinding forObject:(id)anObject
+ (CPBinder)getBinding:(CPString)aBinding forObject:(id)anObject
{
return [[bindingsMap objectForKey:[anObject hash]] objectForKey:aBinding];
return [[bindingsMap objectForKey:[anObject UID]] objectForKey:aBinding];
}
+ (CPDictionary)infoForBinding:(CPString)aBinding forObject:(id)anObject
@@ -76,12 +76,12 @@ var CPBindingOperationAnd = 0,
+ (CPDictionary)allBindingsForObject:(id)anObject
{
return [bindingsMap objectForKey:[anObject hash]];
return [bindingsMap objectForKey:[anObject UID]];
}
+ (void)unbind:(CPString)aBinding forObject:(id)anObject
{
var bindings = [bindingsMap objectForKey:[anObject hash]];
var bindings = [bindingsMap objectForKey:[anObject UID]];
if (!bindings)
return;
@@ -101,7 +101,7 @@ var CPBindingOperationAnd = 0,
+ (void)unbindAllForObject:(id)anObject
{
var bindings = [bindingsMap objectForKey:[anObject hash]];
var bindings = [bindingsMap objectForKey:[anObject UID]];
if (!bindings)
return;
@@ -111,7 +111,7 @@ var CPBindingOperationAnd = 0,
while (count--)
[anObject unbind:[bindings objectForKey:allKeys[count]]];
[bindingsMap removeObjectForKey:[anObject hash]];
[bindingsMap removeObjectForKey:[anObject UID]];
}
- (id)initWithBinding:(CPString)aBinding name:(CPString)aName to:(id)aDestination keyPath:(CPString)aKeyPath options:(CPDictionary)options from:(id)aSource
@@ -128,11 +128,11 @@ var CPBindingOperationAnd = 0,
[aDestination addObserver:self forKeyPath:aKeyPath options:CPKeyValueObservingOptionNew context:aBinding];
var bindings = [bindingsMap objectForKey:[_source hash]];
var bindings = [bindingsMap objectForKey:[_source UID]];
if (!bindings)
{
bindings = [CPDictionary new];
[bindingsMap setObject:bindings forKey:[_source hash]];
[bindingsMap setObject:bindings forKey:[_source UID]];
}
[bindings setObject:self forKey:aName];
@@ -147,39 +147,10 @@ var CPBindingOperationAnd = 0,
var destination = [_info objectForKey:CPObservedObjectKey],
keyPath = [_info objectForKey:CPObservedKeyPathKey],
options = [_info objectForKey:CPOptionsKey],
newValue = [destination valueForKeyPath:keyPath],
isPlaceholder = CPIsControllerMarker(newValue);
if (isPlaceholder)
{
switch (newValue)
{
case CPMultipleValuesMarker:
newValue = [options objectForKey:CPMultipleValuesPlaceholderBindingOption] || @"Multiple Values";
break;
case CPNoSelectionMarker:
newValue = [options objectForKey:CPNoSelectionPlaceholderBindingOption] || @"No Selection";
break;
case CPNotApplicableMarker:
if ([options objectForKey:CPRaisesForNotApplicableKeysBindingOption])
[CPException raise:CPGenericException reason:@"can't transform non applicable key on: "+_source+" value: "+newValue];
newValue = [options objectForKey:CPNotApplicablePlaceholderBindingOption] || @"Not Applicable";
break;
}
}
else
{
// Only transform the value if the current value is not a placeholder
newValue = [self transformValue:newValue withOptions:options];
}
newValue = [destination valueForKeyPath:keyPath];
newValue = [self transformValue:newValue withOptions:options];
[_source setValue:newValue forKey:aBinding];
if ([_source respondsToSelector:@selector(_setCurrentValueIsPlaceholder:)])
[_source _setCurrentValueIsPlaceholder:isPlaceholder];
}
- (void)reverseSetValueFor:(CPString)aBinding
@@ -203,10 +174,6 @@ var CPBindingOperationAnd = 0,
- (id)transformValue:(id)aValue withOptions:(CPDictionary)options
{
var valueTransformerName,
valueTransformer,
placeholder;
var valueTransformerName = [options objectForKey:CPValueTransformerNameBindingOption],
valueTransformer;
@@ -231,7 +198,7 @@ var CPBindingOperationAnd = 0,
aValue = [valueTransformer transformedValue:aValue];
if (aValue === undefined || aValue === nil)
if (aValue === undefined || aValue === nil || aValue === [CPNull null])
aValue = [options objectForKey:CPNullPlaceholderBindingOption] || nil;
return aValue;
@@ -253,13 +220,25 @@ var CPBindingOperationAnd = 0,
return aValue;
}
- (BOOL)continuouslyUpdatesValue
{
var options = [_info objectForKey:CPOptionsKey];
return [[options objectForKey:CPContinuouslyUpdatesValueBindingOption] boolValue];
}
@end
@implementation CPObject (KeyValueBindingCreation)
+ (void)exposeBinding:(CPString)aBinding
{
[CPKeyValueBinding exposeBinding:aBinding forClass:[self class]];
[CPBinder exposeBinding:aBinding forClass:[self class]];
}
+ (Class)_binderClassForBinding:(CPString)theBinding
{
return [CPBinder class];
}
- (CPArray)exposedBindings
@@ -269,7 +248,7 @@ var CPBindingOperationAnd = 0,
while (theClass)
{
var temp = [CPKeyValueBinding exposedBindingsForClass:theClass];
var temp = [CPBinder exposedBindingsForClass:theClass];
if (temp)
[exposedBindings addObjectsFromArray:temp];
@@ -293,18 +272,21 @@ var CPBindingOperationAnd = 0,
//if (![[self exposedBindings] containsObject:aBinding])
// CPLog.warn("No binding exposed on "+self+" for "+aBinding);
var binderClass = [[self class] _binderClassForBinding:aBinding];
[self unbind:aBinding];
[[CPKeyValueBinding alloc] initWithBinding:[self _replacementKeyPathForBinding:aBinding] name:aBinding to:anObject keyPath:aKeyPath options:options from:self];
[[binderClass alloc] initWithBinding:[self _replacementKeyPathForBinding:aBinding] name:aBinding to:anObject keyPath:aKeyPath options:options from:self];
}
- (CPDictionary)infoForBinding:(CPString)aBinding
{
return [CPKeyValueBinding infoForBinding:aBinding forObject:self];
return [CPBinder infoForBinding:aBinding forObject:self];
}
- (void)unbind:(CPString)aBinding
{
[CPKeyValueBinding unbind:aBinding forObject:self];
var binderClass = [[self class] _binderClassForBinding:aBinding];
[binderClass unbind:aBinding forObject:self];
}
- (id)_replacementKeyPathForBinding:(CPString)binding
@@ -314,13 +296,35 @@ var CPBindingOperationAnd = 0,
@end
@implementation _CPKeyValueOrBinding : CPKeyValueBinding
/*!
@ignore
Provides stub implementations that simply call super for the "objectValue" binding
This class should not be necessary but assures backwards compliance with our old way of doing bindings
Every class with a value binding should implement a subclass to handle it's specific value binding logic
*/
@implementation _CPValueBinder : CPBinder
{
}
- (void)setValueFor:(CPString)theBinding
{
[super setValueFor:@"objectValue"];
}
- (void)reverseSetValueFor:(CPString)theBinding
{
[super reverseSetValueFor:@"objectValue"];
}
@end
@implementation _CPKeyValueOrBinding : CPBinder
{
}
- (void)setValueFor:(CPString)aBinding
{
var bindings = [bindingsMap valueForKey:[_source hash]];
var bindings = [bindingsMap valueForKey:[_source UID]];
if (!bindings)
return;
@@ -335,13 +339,13 @@ var CPBindingOperationAnd = 0,
@end
@implementation _CPKeyValueAndBinding : CPKeyValueBinding
@implementation _CPKeyValueAndBinding : CPBinder
{
}
- (void)setValueFor:(CPString)aBinding
{
var bindings = [bindingsMap objectForKey:[_source hash]];
var bindings = [bindingsMap objectForKey:[_source UID]];
if (!bindings)
return;
@@ -428,45 +432,46 @@ 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
CPAllowsEditingMultipleValuesSelectionBindingOption = @"CPAllowsEditingMultipleValuesSelectionBindingOption";
CPAllowsNullArgumentBindingOption = @"CPAllowsNullArgumentBindingOption";
CPConditionallySetsEditableBindingOption = @"CPConditionallySetsEditableBindingOption";
CPConditionallySetsEnabledBindingOption = @"CPConditionallySetsEnabledBindingOption";
CPConditionallySetsHiddenBindingOption = @"CPConditionallySetsHiddenBindingOption";
CPContinuouslyUpdatesValueBindingOption = @"CPContinuouslyUpdatesValueBindingOption";
CPCreatesSortDescriptorBindingOption = @"CPCreatesSortDescriptorBindingOption";
CPDeletesObjectsOnRemoveBindingsOption = @"CPDeletesObjectsOnRemoveBindingsOption";
CPDisplayNameBindingOption = @"CPDisplayNameBindingOption";
CPDisplayPatternBindingOption = @"CPDisplayPatternBindingOption";
CPHandlesContentAsCompoundValueBindingOption = @"CPHandlesContentAsCompoundValueBindingOption";
CPInsertsNullPlaceholderBindingOption = @"CPInsertsNullPlaceholderBindingOption";
CPInvokesSeparatelyWithArrayObjectsBindingOption = @"CPInvokesSeparatelyWithArrayObjectsBindingOption";
CPMultipleValuesPlaceholderBindingOption = @"CPMultipleValuesPlaceholderBindingOption";
CPNoSelectionPlaceholderBindingOption = @"CPNoSelectionPlaceholderBindingOption";
CPNotApplicablePlaceholderBindingOption = @"CPNotApplicablePlaceholderBindingOption";
CPNullPlaceholderBindingOption = @"CPNullPlaceholderBindingOption";
CPPredicateFormatBindingOption = @"CPPredicateFormatBindingOption";
CPRaisesForNotApplicableKeysBindingOption = @"CPRaisesForNotApplicableKeysBindingOption";
CPSelectorNameBindingOption = @"CPSelectorNameBindingOption";
CPSelectsAllWhenSettingContentBindingOption = @"CPSelectsAllWhenSettingContentBindingOption";
CPValidatesImmediatelyBindingOption = @"CPValidatesImmediatelyBindingOption";
CPValueTransformerNameBindingOption = @"CPValueTransformerNameBindingOption";
CPValueTransformerBindingOption = @"CPValueTransformerBindingOption";
CPAllowsEditingMultipleValuesSelectionBindingOption = @"CPAllowsEditingMultipleValuesSelection";
CPAllowsNullArgumentBindingOption = @"CPAllowsNullArgument";
CPConditionallySetsEditableBindingOption = @"CPConditionallySetsEditable";
CPConditionallySetsEnabledBindingOption = @"CPConditionallySetsEnabled";
CPConditionallySetsHiddenBindingOption = @"CPConditionallySetsHidden";
CPContinuouslyUpdatesValueBindingOption = @"CPContinuouslyUpdatesValue";
CPCreatesSortDescriptorBindingOption = @"CPCreatesSortDescriptor";
CPDeletesObjectsOnRemoveBindingsOption = @"CPDeletesObjectsOnRemove";
CPDisplayNameBindingOption = @"CPDisplayName";
CPDisplayPatternBindingOption = @"CPDisplayPattern";
CPHandlesContentAsCompoundValueBindingOption = @"CPHandlesContentAsCompoundValue";
CPInsertsNullPlaceholderBindingOption = @"CPInsertsNullPlaceholder";
CPInvokesSeparatelyWithArrayObjectsBindingOption = @"CPInvokesSeparatelyWithArrayObjects";
CPMultipleValuesPlaceholderBindingOption = @"CPMultipleValuesPlaceholder";
CPNoSelectionPlaceholderBindingOption = @"CPNoSelectionPlaceholder";
CPNotApplicablePlaceholderBindingOption = @"CPNotApplicablePlaceholder";
CPNullPlaceholderBindingOption = @"CPNullPlaceholder";
CPPredicateFormatBindingOption = @"CPPredicateFormat";
CPRaisesForNotApplicableKeysBindingOption = @"CPRaisesForNotApplicableKeys";
CPSelectorNameBindingOption = @"CPSelectorName";
CPSelectsAllWhenSettingContentBindingOption = @"CPSelectsAllWhenSettingContent";
CPValidatesImmediatelyBindingOption = @"CPValidatesImmediately";
CPValueTransformerNameBindingOption = @"CPValueTransformerName";
CPValueTransformerBindingOption = @"CPValueTransformer";
CPIsControllerMarker = function(/*id*/anObject)
{
return anObject === CPMultipleValuesMarker || anObject === CPNoSelectionMarker || anObject === CPNotApplicableMarker;
return anObject === CPMultipleValuesMarker || anObject === CPNoSelectionMarker || anObject === CPNotApplicableMarker || anObject === CPNullMarker;
}
+403
View File
@@ -0,0 +1,403 @@
/*
* CPLevelIndicator.j
* AppKit
*
* Created by Alexander Ljungberg.
* Copyright 2011, WireLoad Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPControl.j"
CPTickMarkBelow = 0;
CPTickMarkAbove = 1;
CPTickMarkLeft = CPTickMarkAbove;
CPTickMarkRight = CPTickMarkBelow;
CPRelevancyLevelIndicatorStyle = 0;
CPContinuousCapacityLevelIndicatorStyle = 1;
CPDiscreteCapacityLevelIndicatorStyle = 2;
CPRatingLevelIndicatorStyle = 3;
var _CPLevelIndicatorBezelColor = nil,
_CPLevelIndicatorSegmentEmptyColor = nil,
_CPLevelIndicatorSegmentNormalColor = nil,
_CPLevelIndicatorSegmentWarningColor = nil,
_CPLevelIndicatorSegmentCriticalColor = nil,
_CPLevelIndicatorSpacing = 1;
/*!
@ingroup appkit
@class CPLevelIndicator
CPLevelIndicator is a control which indicates a value visually on a scale.
*/
@implementation CPLevelIndicator : CPControl
{
CPLevelIndicator _levelIndicatorStyle @accessors(property=levelIndicatorStyle);
double _minValue @accessors(property=minValue);
double _maxValue @accessors(property=maxValue);
double _warningValue @accessors(property=warningValue);
double _criticalValue @accessors(property=criticalValue);
CPTickMarkPosition _tickMarkPosition @accessors(property=tickMarkPosition);
int _numberOfTickMarks @accessors(property=numberOfTickMarks);
int _numberOfMajorTickMarks @accessors(property=numberOfMajorTickMarks);
BOOL _isEditable;
BOOL _isTracking;
}
+ (void)initialize
{
var bundle = [CPBundle bundleForClass:CPLevelIndicator];
_CPLevelIndicatorBezelColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-bezel-left.png"] size:CGSizeMake(3.0, 18.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-bezel-center.png"] size:CGSizeMake(1.0, 18.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-bezel-right.png"] size:CGSizeMake(3.0, 18.0)]
]
isVertical:NO
]];
_CPLevelIndicatorSegmentEmptyColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-empty-left.png"] size:CGSizeMake(3.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-empty-center.png"] size:CGSizeMake(1.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-empty-right.png"] size:CGSizeMake(3.0, 17.0)]
]
isVertical:NO
]];
_CPLevelIndicatorSegmentNormalColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-normal-left.png"] size:CGSizeMake(3.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-normal-center.png"] size:CGSizeMake(1.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-normal-right.png"] size:CGSizeMake(3.0, 17.0)]
]
isVertical:NO
]];
_CPLevelIndicatorSegmentWarningColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-warning-left.png"] size:CGSizeMake(3.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-warning-center.png"] size:CGSizeMake(1.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-warning-right.png"] size:CGSizeMake(3.0, 17.0)]
]
isVertical:NO
]];
_CPLevelIndicatorSegmentCriticalColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-critical-left.png"] size:CGSizeMake(3.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-critical-center.png"] size:CGSizeMake(1.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-critical-right.png"] size:CGSizeMake(3.0, 17.0)]
]
isVertical:NO
]];
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
_levelIndicatorStyle = CPDiscreteCapacityLevelIndicatorStyle;
_maxValue = 2;
_warningValue = 2;
_criticalValue = 2;
[self _init];
}
return self;
}
- (void)_init
{
}
- (void)layoutSubviews
{
var bezelView = [self layoutEphemeralSubviewNamed:"bezel"
positioned:CPWindowBelow
relativeToEphemeralSubviewNamed:nil];
// TODO Make themable.
[bezelView setBackgroundColor:_CPLevelIndicatorBezelColor];
var segmentCount = _maxValue - _minValue;
if (segmentCount <= 0)
return;
var filledColor = _CPLevelIndicatorSegmentNormalColor,
value = [self doubleValue];
if (value < _criticalValue)
filledColor = _CPLevelIndicatorSegmentCriticalColor;
else if (value < _warningValue)
filledColor = _CPLevelIndicatorSegmentWarningColor;
for (var i = 0; i < segmentCount; i++)
{
var segmentView = [self layoutEphemeralSubviewNamed:"segment-bezel-" + i
positioned:CPWindowAbove
relativeToEphemeralSubviewNamed:bezelView];
[segmentView setBackgroundColor:(_minValue + i) < value ? filledColor : _CPLevelIndicatorSegmentEmptyColor];
}
}
- (CPView)createEphemeralSubviewNamed:(CPString)aName
{
return [[CPView alloc] initWithFrame:_CGRectMakeZero()];
}
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aViewName
{
// TODO Put into theme attributes.
var bezelHeight = 18,
segmentHeight = 17,
bounds = _CGRectCreateCopy([self bounds]);
if (aViewName == "bezel")
{
bounds.origin.y = (_CGRectGetHeight(bounds) - bezelHeight) / 2.0;
bounds.size.height = bezelHeight;
return bounds;
}
else if (aViewName.indexOf("segment-bezel") === 0)
{
var segment = parseInt(aViewName.substring("segment-bezel-".length), 10),
segmentCount = _maxValue - _minValue;
if (segment >= segmentCount)
return _CGRectMakeZero();
var basicSegmentWidth = bounds.size.width / segmentCount,
segmentFrame = CGRectCreateCopy([self bounds]);
segmentFrame.origin.y = (_CGRectGetHeight(bounds) - bezelHeight) / 2.0;
segmentFrame.origin.x = FLOOR(segment * basicSegmentWidth);
segmentFrame.size.width = (segment == segmentCount - 1) ? bounds.size.width - segmentFrame.origin.x : FLOOR(((segment + 1) * basicSegmentWidth)) - FLOOR((segment * basicSegmentWidth)) - _CPLevelIndicatorSpacing;
segmentFrame.size.height = segmentHeight;
return segmentFrame;
}
return _CGRectMakeZero();
}
/*!
Sets whether or not the receiver level indicator can be edited.
*/
- (void)setEditable:(BOOL)shouldBeEditable
{
if (_isEditable === shouldBeEditable)
return;
_isEditable = shouldBeEditable;
}
/*!
Returns \c YES if the textfield is currently editable by the user.
*/
- (BOOL)isEditable
{
return _isEditable;
}
- (void)mouseDown:(CPEvent)anEvent
{
if (![self isEditable] || ![self isEnabled])
return;
[self _trackMouse:anEvent];
}
- (void)_trackMouse:(CPEvent)anEvent
{
var type = [anEvent type];
if (type == CPLeftMouseDown || type == CPLeftMouseDragged)
{
var segmentCount = _maxValue - _minValue;
if (segmentCount <= 0)
return;
var location = [self convertPoint:[anEvent locationInWindow] fromView:nil],
bounds = [self bounds],
oldValue = [self doubleValue];
newValue = oldValue;
// Moving the mouse outside of the widget to the left sets it
// to its minimum, and moving outside on the right sets it to
// its maximum.
if (type == CPLeftMouseDragged && location.x < 0)
{
newValue = _minValue;
}
else if (type == CPLeftMouseDragged && location.x > bounds.size.width)
{
newValue = _maxValue;
}
else
{
for (var i = 0; i < segmentCount; i++)
{
var rect = [self rectForEphemeralSubviewNamed:"segment-bezel-" + i];
// Once we're tracking the mouse, we only care about horizontal mouse movement.
if (location.x >= CGRectGetMinX(rect) && location.x < CGRectGetMaxX(rect))
{
newValue = (_minValue + i + 1);
break;
}
}
}
if (newValue != oldValue)
[self setDoubleValue:newValue];
// Track the mouse to support click and slide value editing.
_isTracking = YES;
[CPApp setTarget:self selector:@selector(_trackMouse:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
if ([self isContinuous])
[self sendAction:[self action] to:[self target]];
}
else if (_isTracking)
{
_isTracking = NO;
[self sendAction:[self action] to:[self target]];
}
}
/*
- (CPLevelIndicatorStyle)style;
- (void)setLevelIndicatorStyle:(CPLevelIndicatorStyle)style;
*/
- (void)setMinValue:(double)minValue
{
if (_minValue === minValue)
return;
_minValue = minValue;
[self setNeedsLayout];
}
- (void)setMaxValue:(double)maxValue
{
if (_maxValue === maxValue)
return;
_maxValue = maxValue;
[self setNeedsLayout];
}
- (void)setWarningValue:(double)warningValue;
{
if (_warningValue === warningValue)
return;
_warningValue = warningValue;
[self setNeedsLayout];
}
- (void)setCriticalValue:(double)criticalValue;
{
if (_criticalValue === criticalValue)
return;
_criticalValue = criticalValue;
[self setNeedsLayout];
}
/*
- (CPTickMarkPosition)tickMarkPosition;
- (void)setTickMarkPosition:(CPTickMarkPosition)position;
- (int)numberOfTickMarks;
- (void)setNumberOfTickMarks:(int)count;
- (int)numberOfMajorTickMarks;
- (void)setNumberOfMajorTickMarks:(int)count;
- (double)tickMarkValueAtIndex:(int)index;
- (CGRect)rectOfTickMarkAtIndex:(int)index;
*/
@end
var CPLevelIndicatorStyleKey = "CPLevelIndicatorStyleKey",
CPLevelIndicatorMinValueKey = "CPLevelIndicatorMinValueKey",
CPLevelIndicatorMaxValueKey = "CPLevelIndicatorMaxValueKey",
CPLevelIndicatorWarningValueKey = "CPLevelIndicatorWarningValueKey",
CPLevelIndicatorCriticalValueKey = "CPLevelIndicatorCriticalValueKey",
CPLevelIndicatorTickMarkPositionKey = "CPLevelIndicatorTickMarkPositionKey",
CPLevelIndicatorNumberOfTickMarksKey = "CPLevelIndicatorNumberOfTickMarksKey",
CPLevelIndicatorNumberOfMajorTickMarksKey = "CPLevelIndicatorNumberOfMajorTickMarksKey",
CPLevelIndicatorIsEditableKey = "CPLevelIndicatorIsEditableKey";
@implementation CPLevelIndicator (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
_levelIndicatorStyle = [aCoder decodeIntForKey:CPLevelIndicatorStyleKey];
_minValue = [aCoder decodeDoubleForKey:CPLevelIndicatorMinValueKey];
_maxValue = [aCoder decodeDoubleForKey:CPLevelIndicatorMaxValueKey];
_warningValue = [aCoder decodeDoubleForKey:CPLevelIndicatorWarningValueKey];
_criticalValue = [aCoder decodeDoubleForKey:CPLevelIndicatorCriticalValueKey];
_tickMarkPosition = [aCoder decodeIntForKey:CPLevelIndicatorTickMarkPositionKey];
_numberOfTickMarks = [aCoder decodeIntForKey:CPLevelIndicatorNumberOfTickMarksKey];
_numberOfMajorTickMarks = [aCoder decodeIntForKey:CPLevelIndicatorNumberOfMajorTickMarksKey];
_isEditable = [aCoder decodeBoolForKey:CPLevelIndicatorIsEditableKey];
[self _init];
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeInt:_levelIndicatorStyle forKey:CPLevelIndicatorStyleKey];
[aCoder encodeDouble:_minValue forKey:CPLevelIndicatorMinValueKey];
[aCoder encodeDouble:_maxValue forKey:CPLevelIndicatorMaxValueKey];
[aCoder encodeDouble:_warningValue forKey:CPLevelIndicatorWarningValueKey];
[aCoder encodeDouble:_criticalValue forKey:CPLevelIndicatorCriticalValueKey];
[aCoder encodeInt:_tickMarkPosition forKey:CPLevelIndicatorTickMarkPositionKey];
[aCoder encodeInt:_numberOfTickMarks forKey:CPLevelIndicatorNumberOfTickMarksKey];
[aCoder encodeInt:_numberOfMajorTickMarks forKey:CPLevelIndicatorNumberOfMajorTickMarksKey];
[aCoder encodeBool:_isEditable forKey:CPLevelIndicatorIsEditableKey];
}
@end
+114 -40
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"];
@@ -274,22 +277,7 @@ var _CPMenuBarVisible = NO,
*/
- (void)insertItem:(CPMenuItem)aMenuItem atIndex:(unsigned)anIndex
{
var menu = [aMenuItem menu];
if (menu)
if (menu !== self)
[CPException raise:CPInternalInconsistencyException reason:@"Attempted to insert item into menu that was already in another menu."];
else
return;
[aMenuItem setMenu:self];
[_items insertObject:aMenuItem atIndex:anIndex];
[[CPNotificationCenter defaultCenter]
postNotificationName:CPMenuDidAddItemNotification
object:self
userInfo:[CPDictionary dictionaryWithObject:anIndex forKey:@"CPMenuItemIndex"]];
[self insertObject:aMenuItem inItemsAtIndex:anIndex];
}
/*!
@@ -346,16 +334,26 @@ var _CPMenuBarVisible = NO,
*/
- (void)removeItemAtIndex:(unsigned)anIndex
{
if (anIndex < 0 || anIndex >= _items.length)
return;
[self removeObjectFromItemsAtIndex:anIndex];
}
[_items[anIndex] setMenu:nil];
[_items removeObjectAtIndex:anIndex];
/*!
Removes all the menu items in the receiver.
This method is more efficient than removing menu items individually.
[[CPNotificationCenter defaultCenter]
postNotificationName:CPMenuDidRemoveItemNotification
object:self
userInfo:[CPDictionary dictionaryWithObject:anIndex forKey:@"CPMenuItemIndex"]];
Unlike the other remove methods, this method does not post CPMenuDidChangeItemNotification notifications.
*/
- (void)removeAllItems
{
var count = [_items count];
// Remove the connection to this menu in case
// someone else has a reference to the menu item.
while (count--)
[_items[count] setMenu:nil];
_items = [CPMutableArray array];
_highlightedIndex = CPNotFound;
}
/*!
@@ -364,9 +362,11 @@ var _CPMenuBarVisible = NO,
*/
- (void)itemChanged:(CPMenuItem)aMenuItem
{
if ([aMenuItem menu] != self)
if ([aMenuItem menu] !== self)
return;
[aMenuItem setValue:[aMenuItem valueForKey:@"changeCount"] + 1 forKey:@"changeCount"];
[[CPNotificationCenter defaultCenter]
postNotificationName:CPMenuDidChangeItemNotification
object:self
@@ -555,7 +555,6 @@ var _CPMenuBarVisible = NO,
*/
- (void)submenuAction:(id)aSender
{
}
/*!
@@ -603,11 +602,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
@@ -692,7 +714,7 @@ var _CPMenuBarVisible = NO,
var delegate = [self delegate];
if ([delegate respondsToSelector:@selector(menuWillOpen:)])
[delegate menuWillOpen:aMenu];
[delegate menuWillOpen:self];
// Convert location to global coordinates if not already in them.
if (aView)
@@ -870,7 +892,7 @@ var _CPMenuBarVisible = NO,
// Handling Tracking
/*!
Cancels tracking.
Cancels tracking.
*/
- (void)cancelTracking
{
@@ -930,7 +952,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];
@@ -967,14 +989,6 @@ var _CPMenuBarVisible = NO,
}
//
/*
@ignore
*/
- (BOOL)_itemIsHighlighted:(CPMenuItem)aMenuItem
{
return _items[_highlightedIndex] == aMenuItem;
}
/*
@ignore
*/
@@ -990,6 +1004,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
@@ -1035,6 +1052,61 @@ var _CPMenuBarVisible = NO,
@end
@implementation CPMenu (CPKeyValueCoding)
- (CPUInteger)countOfItems
{
return [_items count];
}
- (CPMenuItem)objectInItemsAtIndex:(CPUInteger)anIndex
{
return [_items objectAtIndex:anIndex];
}
- (CPArray)itemsAtIndexes:(CPIndexSet)indexes
{
return [_items objectsAtIndexes:indexes];
}
@end
@implementation CPMenu (CPKeyValueObserving)
- (void)insertObject:(CPMenuItem)aMenuItem inItemsAtIndex:(CPUInteger)anIndex
{
var menu = [aMenuItem menu];
if (menu)
if (menu !== self)
[CPException raise:CPInternalInconsistencyException reason:@"Attempted to insert item into menu that was already in another menu."];
else
return;
[aMenuItem setMenu:self];
[_items insertObject:aMenuItem atIndex:anIndex];
[[CPNotificationCenter defaultCenter]
postNotificationName:CPMenuDidAddItemNotification
object:self
userInfo:[CPDictionary dictionaryWithObject:anIndex forKey:@"CPMenuItemIndex"]];
}
- (void)removeObjectFromItemsAtIndex:(CPUInteger)anIndex
{
if (anIndex < 0 || anIndex >= [_items count])
return;
[[_items objectAtIndex:anIndex] setMenu:nil];
[_items removeObjectAtIndex:anIndex];
[[CPNotificationCenter defaultCenter]
postNotificationName:CPMenuDidRemoveItemNotification
object:self
userInfo:[CPDictionary dictionaryWithObject:anIndex forKey:@"CPMenuItemIndex"]];
}
@end
var CPMenuTitleKey = @"CPMenuTitleKey",
CPMenuNameKey = @"CPMenuNameKey",
@@ -1061,6 +1133,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)];
}
+333 -45
View File
@@ -5,9 +5,8 @@ _CPMenuManagerScrollingStateUp = -1,
_CPMenuManagerScrollingStateDown = 1,
_CPMenuManagerScrollingStateNone = 0;
var STICKY_TIME_INTERVAL = 500;
var SharedMenuManager = nil;
var STICKY_TIME_INTERVAL = 500,
SharedMenuManager = nil;
@implementation _CPMenuManager: CPObject
{
@@ -21,6 +20,11 @@ var SharedMenuManager = nil;
CPMutableArray _menuContainerStack;
Function _trackingCallback;
CPString _keyBuffer;
CPMenuItem _previousActiveItem;
int _showTimerID;
}
+ (_CPMenuManager)sharedMenuManager
@@ -36,7 +40,7 @@ var SharedMenuManager = nil;
if (SharedMenuManager)
return SharedMenuManager;
return [super init];
return [super init];
}
- (id)trackingMenuContainer
@@ -67,13 +71,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;
@@ -95,7 +99,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 | 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 +134,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 +155,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 +171,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 +187,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 +204,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 +217,59 @@ 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))
else if (type === CPLeftMouseUp && ([anEvent timestamp] - _startTime > (STICKY_TIME_INTERVAL + [activeMenu numberOfItems] * 5)))
[trackingMenu cancelTracking];
}
// Prevent previous selected menu items from opening by stopping the timer if a
// new item is selected before the timer runs out
if (_previousActiveItem !== activeItem)
{
clearTimeout(_showTimerID);
_showTimerID = undefined;
}
// If the item has a submenu, show it.
if ([activeItem hasSubmenu])// && [activeItem action] === @selector(submenuAction:))
{
var activeItemRect = [activeMenuContainer rectForItemAtIndex:activeItemIndex];
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 +279,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,9 +304,6 @@ 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];
@@ -256,9 +315,8 @@ var SharedMenuManager = nil;
if (_trackingCallback)
_trackingCallback([self trackingMenuContainer], trackingMenu);
[[CPNotificationCenter defaultCenter]
postNotificationName:CPMenuDidEndTrackingNotification
object:trackingMenu];
[[CPNotificationCenter defaultCenter] postNotificationName:CPMenuDidEndTrackingNotification
object:trackingMenu];
CPApp._activeMenu = nil;
}
@@ -358,10 +416,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];
+53 -14
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
@@ -77,6 +96,8 @@
id _representedObject;
CPView _view;
int _changeCount;
_CPMenuItemView _menuItemView;
}
@@ -98,12 +119,14 @@
if (self)
{
_changeCount = 0;
_isSeparator = NO;
_title = aTitle;
_action = anAction;
_isEnabled = YES;
_isHidden = NO;
_tag = 0;
_state = CPOffState;
@@ -129,10 +152,17 @@
if ([_menu autoenablesItems])
return;
_isEnabled = isEnabled;
[self _setEnabled:isEnabled];
}
- (void)_setEnabled:(BOOL)isEnabled
{
if (_isEnabled === isEnabled)
return;
_isEnabled = !!isEnabled;
[_menuItemView setDirty];
[_menu itemChanged:self];
}
@@ -445,7 +475,7 @@ CPOffState
return _mixedStateImage;
}
// Managing Subemenus
// Managing Submenus
/*!
Sets the submenu for this item
@param aMenu the submenu
@@ -459,7 +489,7 @@ CPOffState
if (supermenu)
[CPException raise:CPInvalidArgumentException
reason: @"Can't add submenu \"" + [aMenu title] + "\" to item \"" + [self title] + "\", because it is already submenu of \"" + [[aMenu supermenu] title] + "\""];
reason: @"Can't add submenu \"" + [aMenu title] + "\" to item \"" + [self title] + "\", because it is already submenu of \"" + [[aMenu supermenu] title] + "\""];
_submenu = aMenu;
@@ -592,22 +622,25 @@ CPControlKeyMask
return @"";
var string = _keyEquivalent.toUpperCase(),
needsShift = _keyEquivalentModifierMask & CPShiftKeyMask ||
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
{
@@ -644,7 +677,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
@@ -791,12 +824,12 @@ CPControlKeyMask
- (id)copy
{
var item = [[CPMenuItem alloc] init];
// No point in going through accessors and doing lots of unnecessary state checking/updating
item._isSeparator = _isSeparator;
[item setTitle:_title];
[item setFont:_font];
[item setFont:_font];
[item setTarget:_target];
[item setAction:_action];
[item setEnabled:_isEnabled];
@@ -815,7 +848,7 @@ CPControlKeyMask
[item setIndentationLevel:_indentationLevel];
[item setToolTip:_toolTip];
[item setRepresentedObject:_representedObject];
return item;
}
@@ -847,6 +880,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",
@@ -890,6 +928,7 @@ var CPMenuItemIsSeparatorKey = @"CPMenuItemIsSeparatorKey",
if (self)
{
_changeCount = 0;
_isSeparator = [aCoder containsValueForKey:CPMenuItemIsSeparatorKey] && [aCoder decodeBoolForKey:CPMenuItemIsSeparatorKey];
_title = [aCoder decodeObjectForKey:CPMenuItemTitleKey];
+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);
}
+227 -64
View File
@@ -1,16 +1,47 @@
/*
* CPObjectController.j
* AppKit
*
* Created by Ross Boucher.
* Copyright 2009, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPDictionary.j>
@import <Foundation/CPCountedSet.j>
@import "CPController.j"
/*!
@class
CPObjectController is a bindings-compatible controller class.
Properties of the content object of an object of this class can be bound to user interface elements to change and access their values.
The content of an CPObjectController instance is an CPMutableDictionary object by default.
This allows a single CPObjectController instance to be used to manage several properties accessed by key value paths.
The default content object class can be changed by calling setObjectClass:, which a subclass must override.
*/
@implementation CPObjectController : CPController
{
id _contentObject;
id _selection;
Class _objectClass;
CPString _objectClassName;
BOOL _isEditable;
BOOL _automaticallyPreparesContent;
@@ -52,11 +83,20 @@
return [CPSet setWithObjects:"editable", "selection"];
}
/*!
@ignore
*/
- (id)init
{
return [self initWithContent:nil];
}
/*!
Inits and returns a CPObjectController object with the given content.
@param id aContent - The object the controller will use.
@return id the CPObjectConroller instance.
*/
- (id)initWithContent:(id)aContent
{
if (self = [super init])
@@ -71,11 +111,19 @@
return self;
}
/*!
Returns the controller's content object.
@return id - The content object of the controller.
*/
- (id)content
{
return _contentObject;
}
/*!
Sets the content object for the controller.
@param id aContent - The new content object for the controller.
*/
- (void)setContent:(id)aContent
{
[self willChangeValueForKey:@"contentObject"];
@@ -87,109 +135,193 @@
[self _selectionDidChange];
}
/*!
@ignore
*/
- (void)_setContentObject:(id)aContent
{
[self setContent:aContent];
}
/*!
@ignore
*/
- (id)_contentObject
{
return [self content];
}
/*!
Sets whether the controller automatically creates and inserts new content objects automatically when loading from a cib file.
If you pass YES and the controller uses prepareContent to create the content object.
The default is NO.
@param BOOL shouldAutomaticallyPrepareContent - YES if the content should be prepared, otherwise NO.
*/
- (void)setAutomaticallyPreparesContent:(BOOL)shouldAutomaticallyPrepareContent
{
_automaticallyPreparesContent = shouldAutomaticallyPrepareContent;
}
/*!
Returns if the controller prepares the content automatically.
@return BOOL - YES if the content is prepared, otherwise NO.
*/
- (BOOL)automaticallyPreparesContent
{
return _automaticallyPreparesContent;
}
/*!
Overridden by a subclass that require control over the creation of new objects.
*/
- (void)prepareContent
{
[self setContent:[self newObject]];
}
/*!
Sets the object class when creating new objects.
@param Class - the class of new objects that will be created.
*/
- (void)setObjectClass:(Class)aClass
{
_objectClass = aClass;
}
/*!
Returns the class of what new objects will be when they are created.
@return Class - The class of new objects.
*/
- (Class)objectClass
{
return _objectClass;
}
- (id)newObject
/*!
@ignore
*/
- (id)_defaultNewObject
{
return [[[self objectClass] alloc] init];
}
/*!
Creates and returns a new object of the appropriate class.
@return id - The object created.
*/
- (id)newObject
{
return [self _defaultNewObject];
}
/*!
Sets the controller's content object.
@param id anObject - The object to set for the controller.
*/
- (void)addObject:(id)anObject
{
[self setContent:anObject];
[[CPKeyValueBinding getBinding:@"contentObject" forObject:self] reverseSetValueFor:@"contentObject"];
var binderClass = [[self class] _binderClassForBinding:@"contentObject"];
[[binderClass getBinding:@"contentObject" forObject:self] reverseSetValueFor:@"contentObject"];
}
/*!
Removes a given object from the controller.
@param id anObject - The object to remove from the receiver.
*/
- (void)removeObject:(id)anObject
{
if ([self content] === anObject)
[self setContent:nil];
[[CPKeyValueBinding getBinding:@"contentObject" forObject:self] reverseSetValueFor:@"contentObject"];
var binderClass = [[self class] _binderClassForBinding:@"contentObject"];
[[binderClass getBinding:@"contentObject" forObject:self] reverseSetValueFor:@"contentObject"];
}
/*!
Creates and adds a sets the object as the controller's content.
@param id aSender - The sender of the message.
*/
- (void)add:(id)aSender
{
// FIXME: This should happen on the next run loop?
[self addObject:[self newObject]];
}
/*!
@return BOOL - YES if you can added to the controller using add:
*/
- (BOOL)canAdd
{
return [self isEditable];
}
/*!
Removes the content object from the controller.
@param id aSender - The sender of the message.
*/
- (void)remove:(id)aSender
{
// FIXME: This should happen on the next run loop?
[self removeObject:[self content]];
}
/*!
@return BOOL - Returns YES if you can remove the controller's content using remove:
*/
- (BOOL)canRemove
{
return [self isEditable] && [[self selectedObjects] count];
}
/*!
Sets whether the controller allows for the editing of the content.
@param BOOL shouldBeEditable - YES if the content should be editable, otherwise NO.
*/
- (void)setEditable:(BOOL)shouldBeEditable
{
_isEditable = shouldBeEditable;
}
/*!
@return BOOL - Returns YES if the content of the controller is editable, otherwise NO.
*/
- (BOOL)isEditable
{
return _isEditable;
}
/*!
@return CPArray - Returns an array of all objects to be affected by editing.
*/
- (CPArray)selectedObjects
{
return [[_CPObservableArray alloc] initWithObjects:[_contentObject] count:1];
return [[_CPObservableArray alloc] initWithArray:[_contentObject]];
}
/*!
Returns a proxy object representing the controller's selection.
*/
- (id)selection
{
return _selection;
}
/*!
@ignore
*/
- (void)_selectionWillChange
{
[_selection controllerWillChange];
[self willChangeValueForKey:@"selection"];
}
/*!
@ignore
*/
- (void)_selectionDidChange
{
if (_selection === undefined || _selection === nil)
@@ -199,6 +331,9 @@
[self didChangeValueForKey:@"selection"];
}
/*!
@return id - Returns the keys which are being observed.
*/
- (id)observedKeys
{
return _observedKeys;
@@ -218,7 +353,8 @@
@end
var CPObjectControllerObjectClassNameKey = @"CPObjectControllerObjectClassNameKey",
var CPObjectControllerContentKey = @"CPObjectControllerContentKey",
CPObjectControllerObjectClassNameKey = @"CPObjectControllerObjectClassNameKey",
CPObjectControllerIsEditableKey = @"CPObjectControllerIsEditableKey",
CPObjectControllerAutomaticallyPreparesContentKey = @"CPObjectControllerAutomaticallyPreparesContentKey";
@@ -233,11 +369,10 @@ var CPObjectControllerObjectClassNameKey = @"CPObjectControllerOb
var objectClassName = [aCoder decodeObjectForKey:CPObjectControllerObjectClassNameKey],
objectClass = CPClassFromString(objectClassName);
// FIXME: Error if objectClass === nil
[self setObjectClass:objectClass];
[self setObjectClass:objectClass || [CPMutableDictionary class]];
[self setEditable:[aCoder decodeBoolForKey:CPObjectControllerIsEditableKey]];
[self setAutomaticallyPreparesContent:[aCoder decodeBoolForKey:CPObjectControllerAutomaticallyPreparesContentKey] || NO];
[self setContent:[aCoder decodeObjectForKey:CPObjectControllerContentKey]];
_observedKeys = [[CPCountedSet alloc] init];
}
@@ -247,11 +382,21 @@ var CPObjectControllerObjectClassNameKey = @"CPObjectControllerOb
- (void)encodeWithCoder:(CPCoder)aCoder
{
[aCoder encodeObject:CPStringFromClass(objectClass) forKey:CPObjectControllerObjectClassNameKey];
[aCoder encodeObject:[self isEditable] forKey:CPObjectControllerIsEditableKey];
[aCoder encodeObject:[self content] forKey:CPObjectControllerContentKey];
if (![self automaticallyPreparesContent])
[aCoder encodeBOOL:YES forKey:CPObjectControllerAutomaticallyPreparesContentKey];
if (_objectClass)
[aCoder encodeObject:CPStringFromClass(_objectClass) forKey:CPObjectControllerObjectClassNameKey];
else if (_objectClassName)
[aCoder encodeObject:_objectClassName forKey:CPObjectControllerObjectClassNameKey];
[aCoder encodeBool:[self isEditable] forKey:CPObjectControllerIsEditableKey];
[aCoder encodeBool:[self automaticallyPreparesContent] forKey:CPObjectControllerAutomaticallyPreparesContentKey];
}
- (void)awakeFromCib
{
if (![self content] && [self automaticallyPreparesContent])
[self prepareContent];
}
@end
@@ -270,7 +415,7 @@ var CPObjectControllerObjectClassNameKey = @"CPObjectControllerOb
- (id)initWithKeyPath:(id)aKeyPath observer:(id)anObserver object:(id)anObject
{
if (self=[super init])
if (self = [super init])
{
_keyPath = aKeyPath;
_observer = anObserver;
@@ -319,9 +464,9 @@ var CPObjectControllerObjectClassNameKey = @"CPObjectControllerOb
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)change context:(id)context
{
if (_notifyObject)
[_object observeValueForKeyPath:_keyPath ofObject:_object change:change context:context];
[_object observeValueForKeyPath:aKeyPath ofObject:_object change:change context:context];
[_observer observeValueForKeyPath:_keyPath ofObject:_object change:change context:context];
[_observer observeValueForKeyPath:aKeyPath ofObject:_object change:change context:context];
}
- (CPString)description
@@ -331,7 +476,8 @@ var CPObjectControllerObjectClassNameKey = @"CPObjectControllerOb
@end
@implementation _CPObservableArray : CPMutableArray
// FIXME: This should subclass CPMutableArray not _CPJavaScriptArray
@implementation _CPObservableArray : _CPJavaScriptArray
{
CPArray _observationProxies;
}
@@ -357,25 +503,15 @@ var CPObjectControllerObjectClassNameKey = @"CPObjectControllerOb
- (id)initWithArray:(CPArray)anArray
{
if (self = [super initWithArray:anArray])
{
_observationProxies = [];
}
self = [super initWithArray:anArray];
self.isa = [_CPObservableArray class];
self._observationProxies = [];
return self;
}
- (id)initWithObjects:(CPArray)objects count:(unsigned)count
{
if (self = [super initWithObjects:objects count:count])
{
_observationProxies = [];
}
return self;
}
-(void)addObserver:(id)anObserver forKeyPath:(CPString)aKeyPath options:(CPKeyValueObservingOptions)options context:(id)context
- (void)addObserver:(id)anObserver forKeyPath:(CPString)aKeyPath options:(CPKeyValueObservingOptions)options context:(id)context
{
if (aKeyPath.indexOf("@") === 0)
{
@@ -387,7 +523,7 @@ var CPObjectControllerObjectClassNameKey = @"CPObjectControllerOb
[_observationProxies addObject:proxy];
var dotIndex = aKeyPath.indexOf("."),
remaining = aKeyPath.substring(dotIndex+1),
remaining = aKeyPath.substring(dotIndex + 1),
indexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [self count])];
[self addObserver:proxy toObjectsAtIndexes:indexes forKeyPath:remaining options:options context:context];
@@ -409,7 +545,7 @@ var CPObjectControllerObjectClassNameKey = @"CPObjectControllerOb
proxy = [_observationProxies objectAtIndex:index];
var dotIndex = aKeyPath.indexOf("."),
remaining = aKeyPath.substring(dotIndex+1),
remaining = aKeyPath.substring(dotIndex + 1),
indexes = [CPIndexSet indexSetWithIndexesInRange:CPMakeRange(0, [self count])];
[self removeObserver:proxy fromObjectsAtIndexes:indexes forKeyPath:remaining];
@@ -423,7 +559,7 @@ var CPObjectControllerObjectClassNameKey = @"CPObjectControllerOb
- (void)insertObject:(id)anObject atIndex:(unsigned)anIndex
{
for (var i=0, count=[_observationProxies count]; i<count; i++)
for (var i = 0, count = [_observationProxies count]; i < count; i++)
{
var proxy = [_observationProxies objectAtIndex:i],
keyPath = [proxy keyPath],
@@ -443,7 +579,7 @@ var CPObjectControllerObjectClassNameKey = @"CPObjectControllerOb
- (void)removeObjectAtIndex:(unsigned)anIndex
{
for (var i=0, count=[_observationProxies count]; i<count; i++)
for (var i = 0, count = [_observationProxies count]; i < count; i++)
{
var proxy = [_observationProxies objectAtIndex:i],
keyPath = [proxy keyPath],
@@ -480,7 +616,7 @@ var CPObjectControllerObjectClassNameKey = @"CPObjectControllerOb
{
var currentObject = [self objectAtIndex:anIndex];
for (var i=0, count=[_observationProxies count]; i<count; i++)
for (var i = 0, count = [_observationProxies count]; i < count; i++)
{
var proxy = [_observationProxies objectAtIndex:i],
keyPath = [proxy keyPath],
@@ -503,11 +639,13 @@ var CPObjectControllerObjectClassNameKey = @"CPObjectControllerOb
@implementation CPControllerSelectionProxy : CPObject
{
id _controller;
id _keys;
id _controller;
id _keys;
CPDictionary _cachedValues;
CPArray _observationProxies;
CPDictionary _cachedValues;
CPArray _observationProxies;
Object _observedObjectsByKeyPath;
}
- (id)initWithController:(id)aController
@@ -517,46 +655,68 @@ var CPObjectControllerObjectClassNameKey = @"CPObjectControllerOb
_cachedValues = [CPDictionary dictionary];
_observationProxies = [CPArray array];
_controller = aController;
_observedObjectsByKeyPath = {};
}
return self;
}
- (id)valueForKey:(CPString)aKey
- (id)_controllerMarkerForValues:(CPArray)theValues
{
var value = [_cachedValues objectForKey:aKey];
if (value !== undefined && value !== nil)
return value;
var allValues = [[_controller selectedObjects] valueForKeyPath:aKey],
count = [allValues count];
var count = [theValues count];
if (!count)
value = CPNoSelectionMarker;
else if (count === 1)
value = [allValues objectAtIndex:0];
value = [theValues objectAtIndex:0];
else
{
if ([_controller alwaysUsesMultipleValuesMarker])
value = CPMultipleValuesMarker;
else
{
value = [allValues objectAtIndex:0];
value = [theValues objectAtIndex:0];
for (var i=0, count=[allValues count]; i<count && value!=CPMultipleValuesMarker; i++)
for (var i = 0, count= [theValues count]; i < count && value != CPMultipleValuesMarker; i++)
{
if (![value isEqual:[allValues objectAtIndex:i]])
if (![value isEqual:[theValues objectAtIndex:i]])
value = CPMultipleValuesMarker;
}
}
}
[_cachedValues setValue:value forKey:aKey];
if (value === nil || value.isa && [value isEqual:[CPNull null]])
value = CPNullMarker;
return value;
}
- (id)valueForKeyPath:(CPString)theKeyPath
{
var values = [[_controller selectedObjects] valueForKeyPath:theKeyPath];
value = [self _controllerMarkerForValues:values];
[_cachedValues setObject:value forKey:theKeyPath];
return value;
}
- (id)valueForKey:(CPString)theKeyPath
{
return [self valueForKeyPath:theKeyPath];
}
- (void)setValue:(id)theValue forKeyPath:(CPString)theKeyPath
{
[[_controller selectedObjects] setValue:theValue forKeyPath:theKeyPath];
[_cachedValues removeObjectForKey:theKeyPath];
}
- (void)setValue:(id)theValue forKey:(CPString)theKeyPath
{
[self setValue:theKeyPath forKeyPath:theKeyPath];
}
- (unsigned)count
{
return [_cachedValues count];
@@ -567,32 +727,27 @@ var CPObjectControllerObjectClassNameKey = @"CPObjectControllerOb
return [_cachedValues keyEnumerator];
}
- (void)setValue:(id)aValue forKey:(CPString)aKey
{
[[_controller selectedObjects] setValue:aValue forKey:aKey];
}
-(void)controllerWillChange
- (void)controllerWillChange
{
_keys = [_cachedValues allKeys];
if (!_keys)
return;
for (var i=0, count=_keys.length; i<count; i++)
for (var i = 0, count = _keys.length; i < count; i++)
[self willChangeValueForKey:_keys[i]];
[_cachedValues removeAllObjects];
}
-(void)controllerDidChange
- (void)controllerDidChange
{
[_cachedValues removeAllObjects];
if (!_keys)
return;
for (var i=0, count=_keys.length; i<count; i++)
for (var i = 0, count = _keys.length; i < count; i++)
[self didChangeValueForKey:_keys[i]];
_keys = nil;
@@ -610,7 +765,11 @@ var CPObjectControllerObjectClassNameKey = @"CPObjectControllerOb
[proxy setNotifyObject:YES];
[_observationProxies addObject:proxy];
[[_controller selectedObjects] addObserver:proxy forKeyPath:aKeyPath options:options context:context];
// We keep are reference to the observed objects
// because the removeObserver: will be called after the selection changes
var observedObjects = [_controller selectedObjects];
_observedObjectsByKeyPath[aKeyPath] = observedObjects;
[observedObjects addObserver:proxy forKeyPath:aKeyPath options:options context:context];
}
- (void)removeObserver:(id)anObject forKeyPath:(CPString)aKeyPath
@@ -618,8 +777,12 @@ var CPObjectControllerObjectClassNameKey = @"CPObjectControllerOb
var proxy = [[_CPObservationProxy alloc] initWithKeyPath:aKeyPath observer:anObject object:self],
index = [_observationProxies indexOfObject:proxy];
[[_controller selectedObjects] removeObserver:[_observationProxies objectAtIndex:index] forKeyPath:aKeyPath];
var observedObjects = _observedObjectsByKeyPath[aKeyPath];
[observedObjects removeObserver:[_observationProxies objectAtIndex:index] forKeyPath:aKeyPath];
[_observationProxies removeObjectAtIndex:index];
_observedObjects = nil;
}
@end
+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"
+672 -49
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -26,7 +26,7 @@
CPOKButton = 1;
CPCancelButton = 0;
/*!
/*!
@ingroup appkit
@class CPPanel
@@ -51,7 +51,7 @@ CPCancelButton = 0;
@global
@class CPWindow
*/
CPDocModalWindowMask = 1 << 6;
CPDocModalWindowMask = 1 << 6;
@implementation CPPanel : CPWindow
{
+24 -24
View File
@@ -50,18 +50,18 @@ CPImagePboardType = @"CPImagePboardType";
var CPPasteboards = nil,
supportsNativePasteboard = NO;
/*!
/*!
@ingroup appkit
@class CPPasteboard
CPPasteBoard is the object responsible for cut/copy/paste and drag&drop operations.
CPPasteBoard is the object responsible for cut/copy/paste and drag&drop operations.
*/
@implementation CPPasteboard : CPObject
{
CPArray _types;
CPDictionary _owners;
CPDictionary _provided;
unsigned _changeCount;
CPString _stateUID;
@@ -77,7 +77,7 @@ var CPPasteboards = nil,
return;
[self setVersion:1.0];
CPPasteboards = [CPDictionary dictionary];
if (typeof window.cpPasteboardWithName !== "undefined")
@@ -103,10 +103,10 @@ var CPPasteboards = nil,
if (pasteboard)
return pasteboard;
pasteboard = [[CPPasteboard alloc] _initWithName:aName];
[CPPasteboards setObject:pasteboard forKey:aName];
return pasteboard;
}
@@ -114,15 +114,15 @@ var CPPasteboards = nil,
- (id)_initWithName:(CPString)aName
{
self = [super init];
if (self)
{
_name = aName;
_types = [];
_owners = [CPDictionary dictionary];
_provided = [CPDictionary dictionary];
_changeCount = 0;
if (supportsNativePasteboard)
@@ -131,7 +131,7 @@ var CPPasteboards = nil,
[self _synchronizePasteboard];
}
}
return self;
}
@@ -145,17 +145,17 @@ var CPPasteboards = nil,
{
var i = 0,
count = types.length;
for (; i < count; ++i)
{
var type = types[i];
if(![_owners objectForKey:type])
if (![_owners objectForKey:type])
{
[_types addObject:type];
[_provided removeObjectForKey:type];
}
[_owners setObject:anOwner forKey:type];
}
@@ -191,7 +191,7 @@ var CPPasteboards = nil,
_provided = [CPDictionary dictionary];
var count = _types.length;
while (count--)
[_owners setObject:anOwner forKey:_types[count]];
@@ -283,18 +283,18 @@ var CPPasteboards = nil,
- (CPData)dataForType:(CPString)aType
{
var data = [_provided objectForKey:aType];
if (data)
return data;
var owner = [_owners objectForKey:aType];
if (owner)
{
[owner pasteboard:self provideDataForType:aType];
[owner pasteboard:self provideDataForType:aType];
return [_provided objectForKey:aType];
}
if (aType === CPStringPboardType)
return [self dataForType:UTF8PboardType];
@@ -339,10 +339,10 @@ var CPPasteboards = nil,
- (id)propertyListForType:(CPString)aType
{
var data = [self dataForType:aType];
if (data)
return [CPPropertyListSerialization propertyListFromData:data format:CPPropertyList280NorthFormat_v1_0];
return nil;
}
@@ -360,9 +360,9 @@ var CPPasteboards = nil,
- (CPString)_generateStateUID
{
var bits = 32;
_stateUID = @"";
while (bits--)
_stateUID += FLOOR(RAND() * 16.0).toString(16).toUpperCase();
+240 -193
View File
@@ -26,7 +26,7 @@
@import "CPMenuItem.j"
var VISIBLE_MARGIN = 7.0;
var VISIBLE_MARGIN = 7.0;
CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
@@ -38,10 +38,8 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
@implementation CPPopUpButton : CPButton
{
int _selectedIndex;
CPUInteger _selectedIndex;
CPRectEdge _preferredEdge;
CPMenu _menu;
}
+ (CPString)defaultThemeClass
@@ -49,6 +47,21 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
return "popup-button";
}
+ (CPSet)keyPathsForValuesAffectingSelectedIndex
{
return [CPSet setWithObject:@"objectValue"];
}
+ (CPSet)keyPathsForValuesAffectingSelectedTag
{
return [CPSet setWithObject:@"objectValue"];
}
+ (CPSet)keyPathsForValuesAffectingSelectedItem
{
return [CPSet setWithObject:@"objectValue"];
}
/*!
Initializes the pop-up button to the specified size.
@param aFrame the size for the button
@@ -61,7 +74,8 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
if (self)
{
_selectedIndex = CPNotFound;
[self selectItemAtIndex:CPNotFound];
_preferredEdge = CPMaxYEdge;
[self setValue:CPImageLeft forThemeAttribute:@"image-position"];
@@ -71,6 +85,11 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
[self setMenu:[[CPMenu alloc] initWithTitle:@""]];
[self setPullsDown:shouldPullDown];
var options = CPKeyValueObservingOptionNew |CPKeyValueObservingOptionOld;/* |CPKeyValueObservingOptionInitial;*/
[self addObserver:self forKeyPath:@"menu.items" options:options context:nil];
[self addObserver:self forKeyPath:@"_firstItem.changeCount" options:options context:nil];
[self addObserver:self forKeyPath:@"selectedItem.changeCount" options:options context:nil];
}
return self;
@@ -85,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.
*/
@@ -98,7 +120,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
if (!changed)
return;
var items = [_menu itemArray];
var items = [[self menu] itemArray];
if ([items count] <= 0)
return;
@@ -123,21 +145,21 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (void)addItem:(CPMenuItem)anItem
{
[_menu addItem:anItem];
[[self menu] addItem:anItem];
}
/*!
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
{
[_menu addItemWithTitle:aTitle action:NULL keyEquivalent:nil];
[[self menu] addItemWithTitle:aTitle action:NULL keyEquivalent:nil];
}
/*!
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
{
@@ -150,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
@@ -162,7 +184,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
if ([items[count] title] == aTitle)
[self removeItemAtIndex:count];
[_menu insertItemWithTitle:aTitle action:NULL keyEquivalent:nil atIndex:anIndex];
[[self menu] insertItemWithTitle:aTitle action:NULL keyEquivalent:nil atIndex:anIndex];
}
/*!
@@ -170,10 +192,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (void)removeAllItems
{
var count = [_menu numberOfItems];
while (count--)
[_menu removeItemAtIndex:0];
[[self menu] removeAllItems];
}
/*!
@@ -192,7 +211,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (void)removeItemAtIndex:(int)anIndex
{
[_menu removeItemAtIndex:anIndex];
[[self menu] removeItemAtIndex:anIndex];
[self synchronizeTitleAndSelectedItem];
}
@@ -202,10 +221,12 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (CPMenuItem)selectedItem
{
if (_selectedIndex < 0 || _selectedIndex > [self numberOfItems] - 1)
var indexOfSelectedItem = [self indexOfSelectedItem];
if (indexOfSelectedItem < 0 || indexOfSelectedItem > [self numberOfItems] - 1)
return nil;
return [_menu itemAtIndex:_selectedIndex];
return [[self menu] itemAtIndex:indexOfSelectedItem];
}
/*!
@@ -224,13 +245,20 @@ 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.
@ignore
*/
- (id)objectValue
- (int)selectedTag
{
return _selectedIndex;
return [[self selectedItem] tag];
}
/*!
@ignore
*/
- (void)_setSelectedTag:(int)aTag
{
[self selectItemWithTag:aTag];
}
// Setting the Current Selection
@@ -247,22 +275,50 @@ 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
{
if (_selectedIndex == anIndex)
[self setObjectValue:anIndex];
}
- (void)setSelectedIndex:(CPUInteger)anIndex
{
[self setObjectValue:anIndex];
}
- (CPUInteger)selectedIndex
{
return [self objectValue];
}
/*!
Selects the item at the specified index
@param anIndex the index of the item to select
*/
- (void)setObjectValue:(int)anIndex
{
var indexOfSelectedItem = [self objectValue];
anIndex = parseInt(+anIndex, 10);
if (indexOfSelectedItem === anIndex)
return;
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];
}
- (id)objectValue
{
return _selectedIndex;
}
/*!
Selects the menu item with the specified tag
@param the tag of the item to select
@@ -281,84 +337,14 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
[self selectItemAtIndex:[self indexOfItemWithTitle:aTitle]];
}
/*!
Sets the object for the selected item. If no item is selected, then this method has no effect.
@param the object set for the selected item
*/
- (void)setObjectValue:(id)aValue
{
[self selectItemAtIndex:[aValue intValue]];
}
// Getting Menu Items
/*!
Returns the button's menu of items.
*/
- (CPMenu)menu
{
return _menu;
}
/*!
Sets the menu for the button
*/
- (void)setMenu:(CPMenu)aMenu
{
if (_menu === aMenu)
return;
var defaultCenter = [CPNotificationCenter defaultCenter];
if (_menu)
{
[defaultCenter
removeObserver:self
name:CPMenuDidAddItemNotification
object:_menu];
[defaultCenter
removeObserver:self
name:CPMenuDidChangeItemNotification
object:_menu];
[defaultCenter
removeObserver:self
name:CPMenuDidRemoveItemNotification
object:_menu];
}
_menu = aMenu;
if (_menu)
{
[defaultCenter
addObserver:self
selector:@selector(menuDidAddItem:)
name:CPMenuDidAddItemNotification
object:_menu];
[defaultCenter
addObserver:self
selector:@selector(menuDidChangeItem:)
name:CPMenuDidChangeItemNotification
object:_menu];
[defaultCenter
addObserver:self
selector:@selector(menuDidRemoveItem:)
name:CPMenuDidRemoveItemNotification
object:_menu];
}
[self synchronizeTitleAndSelectedItem];
}
/*!
Returns a count of the number of items in the button's menu.
*/
- (int)numberOfItems
{
return [_menu numberOfItems];
return [[self menu] numberOfItems];
}
/*!
@@ -366,7 +352,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (CPArray)itemArray
{
return [_menu itemArray];
return [[self menu] itemArray];
}
/*!
@@ -375,7 +361,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (CPMenuItem)itemAtIndex:(unsigned)anIndex
{
return [_menu itemAtIndex:anIndex];
return [[self menu] itemAtIndex:anIndex];
}
/*!
@@ -384,7 +370,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (CPString)itemTitleAtIndex:(unsigned)anIndex
{
return [[_menu itemAtIndex:anIndex] title];
return [[[self menu] itemAtIndex:anIndex] title];
}
/*!
@@ -409,7 +395,13 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (CPMenuItem)itemWithTitle:(CPString)aTitle
{
return [_menu itemAtIndex:[_menu indexOfItemWithTitle:aTitle]];
var menu = [self menu],
itemIndex = [menu indexOfItemWithTitle:aTitle];
if (itemIndex === CPNotFound)
return nil;
return [menu itemAtIndex:itemIndex];
}
/*!
@@ -417,7 +409,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (CPMenuItem)lastItem
{
return [[_menu itemArray] lastObject];
return [[[self menu] itemArray] lastObject];
}
// Getting the Indices of Menu Items
@@ -427,7 +419,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (int)indexOfItem:(CPMenuItem)aMenuItem
{
return [_menu indexOfItem:aMenuItem];
return [[self menu] indexOfItem:aMenuItem];
}
/*!
@@ -436,16 +428,16 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (int)indexOfItemWithTag:(int)aTag
{
return [_menu indexOfItemWithTag:aTag];
return [[self menu] indexOfItemWithTag:aTag];
}
/*!
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
{
return [_menu indexOfItemWithTitle:aTitle];
return [[self menu] indexOfItemWithTitle:aTitle];
}
/*!
@@ -456,7 +448,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (int)indexOfItemWithRepresentedObject:(id)anObject
{
return [_menu indexOfItemWithRepresentedObject:anObject];
return [[self menu] indexOfItemWithRepresentedObject:anObject];
}
/*!
@@ -468,7 +460,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (int)indexOfItemWithTarget:(id)aTarget action:(SEL)anAction
{
return [_menu indexOfItemWithTarget:aTarget action:anAction];
return [[self menu] indexOfItemWithTarget:aTarget action:anAction];
}
// Setting the Cell Edge to Pop out in Restricted Situations
@@ -483,7 +475,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.
*/
@@ -504,7 +496,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
if ([self pullsDown])
{
var items = [_menu itemArray];
var items = [[self menu] itemArray];
if ([items count] <= 0)
[self addItemWithTitle:aTitle];
@@ -552,7 +544,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
if ([self pullsDown])
{
var items = [_menu itemArray];
var items = [[self menu] itemArray];
if ([items count] > 0)
item = items[0];
@@ -564,73 +556,117 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
[super setTitle:[item title]];
}
//
/*!
Called when the menu has a new item added to it.
@param aNotification information about the event
*/
- (void)menuDidAddItem:(CPNotification)aNotification
- (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)changes context:(id)aContext
{
var index = [[aNotification userInfo] objectForKey:@"CPMenuItemIndex"];
var pullsDown = [self pullsDown];
if (_selectedIndex < 0)
[self selectItemAtIndex:0];
else if (index == _selectedIndex)
if (!pullsDown && aKeyPath === @"selectedItem.changeCount" ||
pullsDown && (aKeyPath === @"_firstItem" || aKeyPath === @"_firstItem.changeCount"))
[self synchronizeTitleAndSelectedItem];
else if (index < _selectedIndex)
++_selectedIndex;
if (index == 0 && [self pullsDown])
// FIXME: This is due to a bug in KVO, we should never get it for "menu".
if (aKeyPath === @"menu")
{
var items = [_menu itemArray];
aKeyPath = @"menu.items";
[items[0] setHidden:YES];
if (items.length > 0)
[items[1] setHidden:NO];
[changes setObject:CPKeyValueChangeSetting forKey:CPKeyValueChangeKindKey];
[changes setObject:[[self menu] itemArray] forKey:CPKeyValueChangeNewKey];
}
var item = [_menu itemArray][index],
action = [item action];
if (!action || (action === @selector(_popUpItemAction:)))
if (aKeyPath === @"menu.items")
{
[item setTarget:self];
[item setAction:@selector(_popUpItemAction:)];
var changeKind = [changes objectForKey:CPKeyValueChangeKindKey],
indexOfSelectedItem = [self indexOfSelectedItem];
if (changeKind === CPKeyValueChangeRemoval)
{
var index = CPNotFound,
indexes = [changes objectForKey:CPKeyValueChangeIndexesKey];
if ([indexes containsIndex:0] && [self pullsDown])
[self _firstItemDidChange];
// See whether the index has changed, despite the actual item not changing.
while ((index = [indexes indexGreaterThanIndex:index]) !== CPNotFound &&
index <= indexOfSelectedItem)
--indexOfSelectedItem;
[self selectItemAtIndex:indexOfSelectedItem];
}
else if (changeKind === CPKeyValueChangeReplacement)
{
var indexes = [changes objectForKey:CPKeyValueChangeIndexesKey];
if (pullsDown && [indexes containsIndex:0] ||
!pullsDown && [indexes containsIndex:indexOfSelectedItem])
[self synchronizeTitleAndSelectedItem];
}
else
{
// No matter what, we want to prepare the new items.
var newItems = [changes objectForKey:CPKeyValueChangeNewKey];
[newItems enumerateObjectsUsingBlock:function(aMenuItem)
{
var action = [aMenuItem action];
if (!action)
[aMenuItem setAction:action = @selector(_popUpItemAction:)];
if (action === @selector(_popUpItemAction:))
[aMenuItem setTarget:self];
}];
if (changeKind === CPKeyValueChangeSetting)
{
[self _firstItemDidChange];
[self selectItemAtIndex:CPNotFound];
[self selectItemAtIndex:MIN([newItems count] - 1, indexOfSelectedItem)];
}
else //if (changeKind === CPKeyValueChangeInsertion)
{
var indexes = [changes objectForKey:CPKeyValueChangeIndexesKey];
if ([self pullsDown] && [indexes containsIndex:0])
{
[self _firstItemDidChange];
if ([self numberOfItems] > 1)
{
var index = CPNotFound,
originalIndex = 0;
while ((index = [indexes indexGreaterThanIndex:index]) !== CPNotFound &&
index <= originalIndex)
++originalIndex;
[[self itemAtIndex:originalIndex] setHidden:NO];
}
}
if (indexOfSelectedItem < 0)
[self selectItemAtIndex:0];
else
{
var index = CPNotFound;
// See whether the index has changed, despite the actual item not changing.
while ((index = [indexes indexGreaterThanIndex:index]) !== CPNotFound &&
index <= indexOfSelectedItem)
++indexOfSelectedItem;
[self selectItemAtIndex:indexOfSelectedItem];
}
}
}
}
}
/*!
Called when a menu item has changed.
@param aNotification information about the event
*/
- (void)menuDidChangeItem:(CPNotification)aNotification
{
var index = [[aNotification userInfo] objectForKey:@"CPMenuItemIndex"];
if ([self pullsDown] && index != 0)
return;
if (![self pullsDown] && index != _selectedIndex)
return;
[self synchronizeTitleAndSelectedItem];
}
/*!
Called when an item was removed from the menu.
@param aNotification information about the event
*/
- (void)menuDidRemoveItem:(CPNotification)aNotification
{
var numberOfItems = [self numberOfItems];
if (numberOfItems <= _selectedIndex && numberOfItems > 0)
[self selectItemAtIndex:numberOfItems - 1];
else
[self synchronizeTitleAndSelectedItem];
// [super observeValueForKeyPath:aKeyPath ofObject:anObject change:changes context:aContext];
}
- (void)mouseDown:(CPEvent)anEvent
@@ -702,7 +738,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
@@ -710,6 +746,22 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
[self sendAction:[self action] to:[self target]];
}
- (void)_firstItemDidChange
{
[self willChangeValueForKey:@"_firstItem"];
[self didChangeValueForKey:@"_firstItem"];
[[self _firstItem] setHidden:YES];
}
- (CPMenuItem)_firstItem
{
if ([self numberOfItems] <= 0)
return nil;
return [[self menu] itemAtIndex:0];
}
- (void)takeValueFromKeyPath:(CPString)aKeyPath ofObjects:(CPArray)objects
{
var count = objects.length,
@@ -719,19 +771,14 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
[self setEnabled:YES];
while (count-- > 1)
{
if (value !== [objects[count] valueForKeyPath:aKeyPath])
{
[[self selectedItem] setState:CPOffState];
}
}
}
@end
var CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey",
CPPopUpButtonSelectedIndexKey = @"CPPopUpButtonSelectedIndexKey",
CPPopUpButtonPullsDownKey = @"CPPopUpButtonPullsDownKey";
var DEPRECATED_CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey",
DEPRECATED_CPPopUpButtonSelectedIndexKey = @"CPPopUpButtonSelectedIndexKey";
@implementation CPPopUpButton (CPCoding)
/*!
@@ -747,27 +794,27 @@ var CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey",
if (self)
{
// Nothing is currently selected
_selectedIndex = -1;
// FIXME: (or not?) _title is nulled in - [CPButton initWithCoder:],
// so we need to do this again.
[self synchronizeTitleAndSelectedItem];
[self setMenu:[aCoder decodeObjectForKey:CPPopUpButtonMenuKey]];
[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 */
[self addObserver:self forKeyPath:@"menu.items" options:options context:nil];
[self addObserver:self forKeyPath:@"_firstItem.changeCount" options:options context:nil];
[self addObserver:self forKeyPath:@"selectedItem.changeCount" options:options context:nil];
}
return self;
}
/*!
Encodes the data of the pop-up button into a coder
@param aCoder the coder to which the data
will be written
*/
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:_menu forKey:CPPopUpButtonMenuKey];
[aCoder encodeInt:_selectedIndex forKey:CPPopUpButtonSelectedIndexKey];
}
@end
+80 -43
View File
@@ -47,7 +47,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
CPProgressIndicatorStyleIdentifiers = nil,
CPProgressIndicatorStyleSizes = nil;
/*!
/*!
@ingroup appkit
@class CPProgressIndicator
@@ -59,19 +59,19 @@ var CPProgressIndicatorSpinningStyleColors = nil,
{
double _minValue;
double _maxValue;
double _doubleValue;
CPControlSize _controlSize;
BOOL _isIndeterminate;
CPProgressIndicatorStyle _style;
BOOL _isAnimating;
BOOL _isDisplayedWhenStoppedSet;
BOOL _isDisplayedWhenStopped;
CPView _barView;
}
@@ -82,11 +82,11 @@ var CPProgressIndicatorSpinningStyleColors = nil,
{
if (self != [CPProgressIndicator class])
return;
var bundle = [CPBundle bundleForClass:self];
CPProgressIndicatorSpinningStyleColors = [];
CPProgressIndicatorSpinningStyleColors[CPMiniControlSize] = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:
[bundle pathForResource:@"CPProgressIndicator/CPProgressIndicatorSpinningStyleRegular.gif"] size:CGSizeMake(64.0, 64.0)]];
CPProgressIndicatorSpinningStyleColors[CPSmallControlSize] = [CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:
@@ -95,10 +95,10 @@ var CPProgressIndicatorSpinningStyleColors = nil,
[bundle pathForResource:@"CPProgressIndicator/CPProgressIndicatorSpinningStyleRegular.gif"] size:CGSizeMake(64.0, 64.0)]];
CPProgressIndicatorBezelBorderViewPool = [];
var start = CPProgressIndicatorBarStyle,
end = CPProgressIndicatorHUDBarStyle;
for (; start <= end; ++start)
{
CPProgressIndicatorBezelBorderViewPool[start] = [];
@@ -106,21 +106,21 @@ var CPProgressIndicatorSpinningStyleColors = nil,
CPProgressIndicatorBezelBorderViewPool[start][CPSmallControlSize] = [];
CPProgressIndicatorBezelBorderViewPool[start][CPRegularControlSize] = [];
}
CPProgressIndicatorClassName = [self className];
CPProgressIndicatorStyleIdentifiers = [];
CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle] = @"Bar";
CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorSpinningStyle] = @"Spinny";
CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorHUDBarStyle] = @"HUDBar";
var regularIdentifier = _CPControlIdentifierForControlSize(CPRegularControlSize),
smallIdentifier = _CPControlIdentifierForControlSize(CPSmallControlSize),
miniIdentifier = _CPControlIdentifierForControlSize(CPMiniControlSize);
CPProgressIndicatorStyleSizes = [];
// Bar Sttyle
// Bar Style
var prefixes = [
CPProgressIndicatorClassName + @"BezelBorder" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle],
CPProgressIndicatorClassName + @"Bar" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle],
@@ -128,7 +128,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
CPProgressIndicatorClassName + @"Bar" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorHUDBarStyle]
];
for (var i = 0, count = prefixes.length; i<count; i++)
for (var i = 0, count = prefixes.length; i < count; i++)
{
var prefix = prefixes[i];
CPProgressIndicatorStyleSizes[prefix + regularIdentifier] = [_CGSizeMake(3.0, 16.0), _CGSizeMake(1.0, 16.0), _CGSizeMake(3.0, 16.0)];
@@ -140,23 +140,23 @@ var CPProgressIndicatorSpinningStyleColors = nil,
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
_minValue = 0.0;
_maxValue = 100.0;
_doubleValue = 0.0;
_style = CPProgressIndicatorBarStyle;
_isDisplayedWhenStoppedSet = NO;
_controlSize = CPRegularControlSize;
[self updateBackgroundColor];
[self drawBar];
}
return self;
}
@@ -174,7 +174,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
- (void)startAnimation:(id)aSender
{
_isAnimating = YES;
[self _hideOrDisplay];
}
@@ -213,7 +213,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
- (void)setDoubleValue:(double)aValue
{
_doubleValue = MIN(MAX(aValue, _minValue), _maxValue);
[self drawBar];
}
@@ -268,7 +268,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
{
if (_controlSize == aControlSize)
return;
_controlSize = aControlSize;
[self updateBackgroundColor];
@@ -290,7 +290,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
}
/*
Not yet impemented.
Not yet implemented.
*/
- (CPControlTint)controlTint
{
@@ -320,7 +320,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
{
if (_isIndeterminate == isIndeterminate)
return;
_isIndeterminate = isIndeterminate;
[self updateBackgroundColor];
@@ -342,9 +342,9 @@ var CPProgressIndicatorSpinningStyleColors = nil,
{
if (_style == aStyle)
return;
_style = aStyle;
[self updateBackgroundColor];
}
@@ -357,8 +357,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
[self setFrameSize:[[CPProgressIndicatorSpinningStyleColors[_controlSize] patternImage] size]];
else
[self setFrameSize:CGSizeMake(CGRectGetWidth([self frame]), CPProgressIndicatorStyleSizes[
CPProgressIndicatorClassName + @"BezelBorder" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle] +
_CPControlIdentifierForControlSize(_controlSize)][0].height)];
CPProgressIndicatorClassName + @"BezelBorder" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle] + _CPControlIdentifierForControlSize(_controlSize)][0].height)];
}
/*!
@@ -370,11 +369,11 @@ var CPProgressIndicatorSpinningStyleColors = nil,
{
if (_isDisplayedWhenStoppedSet && _isDisplayedWhenStopped == isDisplayedWhenStopped)
return;
_isDisplayedWhenStoppedSet = YES;
_isDisplayedWhenStopped = isDisplayedWhenStopped;
[self _hideOrDisplay];
}
@@ -385,10 +384,10 @@ var CPProgressIndicatorSpinningStyleColors = nil,
{
if (_isDisplayedWhenStoppedSet)
return _isDisplayedWhenStopped;
if (_style == CPProgressIndicatorBarStyle || _style == CPProgressIndicatorHUDBarStyle)
return YES;
return NO;
}
@@ -401,7 +400,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
- (void)setFrameSize:(CGSize)aSize
{
[super setFrameSize:aSize];
[self drawBar];
}
@@ -410,13 +409,13 @@ var CPProgressIndicatorSpinningStyleColors = nil,
{
if (_style == CPProgressIndicatorSpinningStyle)
return;
if (!_barView)
{
_barView = [[CPView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 16.0)];
_barView = [[CPView alloc] initWithFrame:CGRectMake(0.0, 0.0, 0.0, 16.0)];
[self addSubview:_barView];
}
[_barView setBackgroundColor:_CPControlThreePartImagePattern(
NO,
CPProgressIndicatorStyleSizes,
@@ -442,9 +441,9 @@ var CPProgressIndicatorSpinningStyleColors = nil,
if (_style == CPProgressIndicatorSpinningStyle)
{
[_barView removeFromSuperview];
_barView = nil;
[self setBackgroundColor:CPProgressIndicatorSpinningStyleColors[_controlSize]];
}
else
@@ -456,7 +455,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
@"BezelBorder",
CPProgressIndicatorStyleIdentifiers[_style],
_CPControlIdentifierForControlSize(_controlSize))];
[self drawBar];
}
}
@@ -465,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
+14 -7
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
{
@@ -358,8 +365,8 @@ var CPResponderNextResponderKey = @"CPResponderNextResponderKey",
if (self)
{
_nextResponder = [aCoder decodeObjectForKey:CPResponderNextResponderKey];
_menu = [aCoder decodeObjectForKey:CPResponderMenuKey];
[self setNextResponder:[aCoder decodeObjectForKey:CPResponderNextResponderKey]];
[self setMenu:[aCoder decodeObjectForKey:CPResponderMenuKey]];
}
return self;
+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
+29 -6
View File
@@ -342,6 +342,7 @@
[_contentView setFrame:contentFrame];
[_headerClipView setFrame:headerClipViewFrame];
[[_headerClipView documentView] setNeedsDisplay:YES];
[_cornerView setFrame:[self _cornerViewFrame]];
[[self bottomCornerView] setFrame:[self _bottomCornerViewFrame]];
@@ -354,6 +355,12 @@
/*!
Sets the type of border to be drawn around the view.
Valid types are:
<pre>
CPNoBorder
CPLineBorder
CPBezelBorder
CPGrooveBorder</pre>
*/
- (void)setBorderType:(CPBorderType)borderType
{
@@ -501,7 +508,7 @@
}
/*!
Sets whether the scroll view hides its scoll bars when not needed.
Sets whether the scroll view hides its scroll bars when not needed.
@param autohidesScrollers \c YES causes the scroll bars
to be hidden when not needed.
*/
@@ -708,7 +715,7 @@
*/
- (void)setLineScroll:(float)aLineScroll
{
[self setHorizonalLineScroll:aLineScroll];
[self setHorizontalLineScroll:aLineScroll];
[self setVerticalLineScroll:aLineScroll];
}
@@ -791,7 +798,7 @@
/*!
Sets the vertical page scroll amount.
@param aPageScroll the new vertcal page scroll amount
@param aPageScroll the new vertical page scroll amount
*/
- (void)setVerticalPageScroll:(float)aPageScroll
{
@@ -974,6 +981,22 @@
[self moveByOffset:CGSizeMake(0.0, _CGRectGetHeight(contentBounds) - _verticalPageScroll)];
}
- (void)scrollToBeginningOfDocument:(id)sender
{
[_contentView scrollToPoint:_CGPointMakeZero()];
[_headerClipView scrollToPoint:_CGPointMakeZero()];
}
- (void)scrollToEndOfDocument:(id)sender
{
var contentBounds = [_contentView bounds],
documentFrame = [[self documentView] frame],
scrollPoint = _CGPointMake(0.0, _CGRectGetHeight(documentFrame) - _CGRectGetHeight(contentBounds));
[_contentView scrollToPoint:scrollPoint];
[_headerClipView scrollToPoint:_CGPointMakeZero()];
}
- (void)moveLeft:(id)sender
{
[self moveByOffset:CGSizeMake(-_horizontalLineScroll, 0.0)];
@@ -1003,7 +1026,7 @@
contentBounds.origin.y += aSize.height;
[_contentView scrollToPoint:contentBounds.origin];
[_headerClipView scrollToPoint:CGPointMake(contentBounds.origin, 0)];
[_headerClipView scrollToPoint:CGPointMake(contentBounds.origin.x, 0)];
}
@end
@@ -1056,8 +1079,8 @@ var CPScrollViewContentViewKey = @"CPScrollViewContentView",
_cornerView = [aCoder decodeObjectForKey:CPScrollViewCornerViewKey];
_bottomCornerView = [aCoder decodeObjectForKey:CPScrollViewBottomCornerViewKey];
// Do to the anything goes nature of decoding, our subviews may not exist yet, so layout at the end of the run loop when we're sure everything is in a correct state.
[[CPRunLoop currentRunLoop] performSelector:@selector(reflectScrolledClipView:) target:self argument:_contentView order:0 modes:[CPDefaultRunLoopMode]];
// Due to the anything goes nature of decoding, our subviews may not exist yet, so layout at the end of the run loop when we're sure everything is in a correct state.
[[CPRunLoop currentRunLoop] performSelector:@selector(_updateCornerAndHeaderView) target:self argument:_contentView order:0 modes:[CPDefaultRunLoopMode]];
}
return self;
+9 -9
View File
@@ -267,16 +267,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 +296,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 +316,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);
}
}
}
+129 -142
View File
@@ -23,12 +23,10 @@
@import "CPButton.j"
@import "CPTextField.j"
CPSearchFieldRecentsTitleMenuItemTag = 1000;
CPSearchFieldRecentsMenuItemTag = 1001;
CPSearchFieldClearRecentsMenuItemTag = 1002;
CPSearchFieldNoRecentsMenuItemTag = 1003;
CPSearchFieldSeparatorMenuItemTag = 1004;
var CPSearchFieldSearchImage = nil,
CPSearchFieldFindImage = nil,
@@ -39,15 +37,16 @@ var SEARCH_BUTTON_DEFAULT_WIDTH = 25.0,
CANCEL_BUTTON_DEFAULT_WIDTH = 22.0,
BUTTON_DEFAULT_HEIGHT = 22.0;
var CPAutosavedRecentsChangedNotification = @"CPAutosavedRecentsChangedNotification";
var RECENT_SEARCH_PREFIX = @" ";
/*!
/*!
@ingroup appkit
@class CPSearchField
The CPSearchField class defines the programmatic interface for text fields that are optimized for text-based searches. A CPSearchField object directly inherits from the CPTextField class. The search field implemented by these classes presents a standard user interface for searches, including a search button, a cancel button, and a pop-up icon menu for listing recent search strings and custom search categories.
When the user types and then pauses, the text field's action message is sent to its target. You can query the text field's string value for the current text to search for. Do not rely on the sender of the action to be an CPMenu object because the menu may change. If you need to change the menu, modify the search menu template and call the setSearchMenuTemplate: method to update.
When the user types and then pauses, the text field's action message is sent to its target. You can query the text field's string value for the current text to search for. Do not rely on the sender of the action to be an CPMenu object because the menu may change. If you need to change the menu, modify the search menu template and call the setSearchMenuTemplate: method to update.
*/
@implementation CPSearchField : CPTextField
{
@@ -58,7 +57,7 @@ var RECENT_SEARCH_PREFIX = @" ";
CPString _recentsAutosaveName;
CPArray _recentSearches;
int _maximumRecents;
BOOL _sendsWholeSearchString;
BOOL _sendsSearchStringImmediately;
@@ -96,9 +95,9 @@ var RECENT_SEARCH_PREFIX = @" ";
#if PLATFORM(DOM)
_cancelButton._DOMElement.style.cursor = "default";
_searchButton._DOMElement.style.cursor = "default";
#endif
#endif
}
return self;
}
@@ -110,34 +109,45 @@ var RECENT_SEARCH_PREFIX = @" ";
[self setBezelStyle:CPTextFieldRoundedBezel];
[self setBordered:YES];
[self setEditable:YES];
[self setDelegate:self];
[self setContinuous:YES];
var bounds = [self bounds],
cancelButton = [[CPButton alloc] initWithFrame:[self cancelButtonRectForBounds:bounds]],
searchButton = [[CPButton alloc] initWithFrame:[self searchButtonRectForBounds:bounds]];
[self setCancelButton:cancelButton];
[self resetCancelButton];
[self setSearchButton:searchButton];
[self resetSearchButton];
_canResignFirstResponder = YES;
}
- (void)viewWillMoveToSuperview:(CPView)aView
{
[super viewWillMoveToSuperview:aView];
// First we remove any observer that may have been in place to avoid memory leakage.
[[CPNotificationCenter defaultCenter] removeObserver:self name:CPControlTextDidChangeNotification object:self];
// Register the observe here if we need to.
if (aView)
[[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(_searchFieldTextDidChange:) name:CPControlTextDidChangeNotification object:self];
}
// Managing Buttons
/*!
Sets the button used to display the search-button image
@param button The search button.
*/
- (void)setSearchButton:(CPButton)button
{
{
if (button != _searchButton)
{
[_searchButton removeFromSuperview];
_searchButton = button;
[_searchButton setFrame:[self searchButtonRectForBounds:[self bounds]]];
[_searchButton setAutoresizingMask:CPViewMaxXMargin];
[self addSubview:_searchButton];
@@ -161,7 +171,7 @@ var RECENT_SEARCH_PREFIX = @" ";
{
var button = [self searchButton],
searchButtonImage = (_searchMenuTemplate === nil) ? CPSearchFieldSearchImage : CPSearchFieldFindImage;
[button setBordered:NO];
[button setImageScaling:CPScaleToFit];
[button setImage:searchButtonImage];
@@ -178,11 +188,11 @@ var RECENT_SEARCH_PREFIX = @" ";
{
[_cancelButton removeFromSuperview];
_cancelButton = button;
[_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];
}
@@ -199,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
{
@@ -210,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
@@ -222,22 +232,22 @@ var RECENT_SEARCH_PREFIX = @" ";
*/
- (CGRect)searchTextRectForBounds:(CGRect)rect
{
var leftOffset = 0,
var leftOffset = 0,
width = _CGRectGetWidth(rect),
bounds = [self bounds];
if (_searchButton)
{
var searchBounds = [self searchButtonRectForBounds:bounds];
leftOffset = _CGRectGetMaxX(searchBounds) + 2;
}
if (_cancelButton)
{
var cancelRect = [self cancelButtonRectForBounds:bounds];
width = _CGRectGetMinX(cancelRect) - leftOffset;
}
return _CGRectMake(leftOffset, _CGRectGetMinY(rect), width, _CGRectGetHeight(rect));
}
@@ -257,7 +267,7 @@ var RECENT_SEARCH_PREFIX = @" ";
Subclasses can override this method to return a new bounding rectangle for the cancel button. You might use this method to provide a custom layout for the search field control.
*/
- (CGRect)cancelButtonRectForBounds:(CGRect)rect
{
{
return _CGRectMake(_CGRectGetWidth(rect) - CANCEL_BUTTON_DEFAULT_WIDTH - 5, (_CGRectGetHeight(rect) - CANCEL_BUTTON_DEFAULT_WIDTH) / 2, BUTTON_DEFAULT_HEIGHT, BUTTON_DEFAULT_HEIGHT);
}
@@ -279,7 +289,7 @@ var RECENT_SEARCH_PREFIX = @" ";
- (void)setSearchMenuTemplate:(CPMenu)aMenu
{
_searchMenuTemplate = aMenu;
[self resetSearchButton];
[self _loadRecentSearchList];
[self _updateSearchMenu];
@@ -291,8 +301,8 @@ var RECENT_SEARCH_PREFIX = @" ";
@return \c YES if the action message is sent all at once when the user clicks the search button or presses return; otherwise, NO if the search string is sent after each keystroke. The default value is NO.
*/
- (BOOL)sendsWholeSearchString
{
return _sendsWholeSearchString;
{
return _sendsWholeSearchString;
}
/*!
@@ -309,8 +319,8 @@ var RECENT_SEARCH_PREFIX = @" ";
@return \c YES if the text field sends its action immediately upon notification of any changes to the search field; otherwise, NO.
*/
- (BOOL)sendsSearchStringImmediately
{
return _sendsSearchStringImmediately;
{
return _sendsSearchStringImmediately;
}
/*!
@@ -328,7 +338,7 @@ var RECENT_SEARCH_PREFIX = @" ";
@return The maximum number of search strings that can appear in the menu. This value is between 0 and 254.
*/
- (int)maximumRecents
{
{
return _maximumRecents;
}
@@ -342,13 +352,13 @@ var RECENT_SEARCH_PREFIX = @" ";
max = 254;
else if (max < 0)
max = 10;
_maximumRecents = max;
}
/*!
Returns the list of recent search strings for the control.
@return An array of \c CPString objects, each of which contains a search string either displayed in the search menu or from a recent autosave archive. If there have been no recent searches and no prior searches saved under an autosave name, this array may be empty.
@return An array of \c CPString objects, each of which contains a search string either displayed in the search menu or from a recent autosave archive. If there have been no recent searches and no prior searches saved under an autosave name, this array may be empty.
*/
- (CPArray)recentSearches
{
@@ -364,8 +374,8 @@ var RECENT_SEARCH_PREFIX = @" ";
{
var max = MIN([self maximumRecents], [searches count]),
searches = [searches subarrayWithRange:CPMakeRange(0, max)];
_recentSearches = searches;
_recentSearches = searches;
[self _autosaveRecentSearchList];
}
@@ -375,7 +385,7 @@ var RECENT_SEARCH_PREFIX = @" ";
*/
- (CPString)recentsAutosaveName
{
return _recentsAutosaveName;
return _recentsAutosaveName;
}
/*!
@@ -386,9 +396,9 @@ var RECENT_SEARCH_PREFIX = @" ";
{
if (_recentsAutosaveName != nil)
[self _deregisterForAutosaveNotification];
_recentsAutosaveName = name;
if (_recentsAutosaveName != nil)
[self _registerForAutosaveNotification];
}
@@ -397,13 +407,13 @@ var RECENT_SEARCH_PREFIX = @" ";
- (CGRect)contentRectForBounds:(CGRect)bounds
{
var superbounds = [super contentRectForBounds:bounds];
var superbounds = [super contentRectForBounds:bounds];
return [self searchTextRectForBounds:superbounds];
}
+ (double)_keyboardDelayForPartialSearchString:(CPString)string
{
return (6 - MIN([string length],4))/10;
return (6 - MIN([string length], 4)) / 10;
}
- (CPMenu)menu
@@ -421,7 +431,7 @@ var RECENT_SEARCH_PREFIX = @" ";
[_cancelButton setHidden:([[self stringValue] length] === 0)];
}
- (void)controlTextDidChange:(CPNotification)aNotification
- (void)_searchFieldTextDidChange:(CPNotification)aNotification
{
if (![self sendsWholeSearchString])
{
@@ -431,15 +441,15 @@ var RECENT_SEARCH_PREFIX = @" ";
{
[_partialStringTimer invalidate];
var timeInterval = [CPSearchField _keyboardDelayForPartialSearchString:[self stringValue]];
_partialStringTimer = [CPTimer scheduledTimerWithTimeInterval:timeInterval
target:self
selector:@selector(_sendPartialString)
userInfo:nil
repeats:NO];
_partialStringTimer = [CPTimer scheduledTimerWithTimeInterval:timeInterval
target:self
selector:@selector(_sendPartialString)
userInfo:nil
repeats:NO];
}
}
[self _updateCancelButtonVisibility];
}
@@ -462,7 +472,7 @@ var RECENT_SEARCH_PREFIX = @" ";
{
if (string === nil || string === @"" || [_recentSearches containsObject:string])
return;
var searches = [CPMutableArray arrayWithArray:_recentSearches];
[searches addObject:string];
[self setRecentSearches:searches];
@@ -471,7 +481,7 @@ var RECENT_SEARCH_PREFIX = @" ";
- (CPView)hitTest:(CGPoint)aPoint
{
// Make sure a hit anywhere within the search field returns the search field itself
// Make sure a hit anywhere within the search field returns the search field itself
if (_CGRectContainsPoint([self frame], aPoint))
return self;
else
@@ -493,8 +503,8 @@ var RECENT_SEARCH_PREFIX = @" ";
if (_searchMenuTemplate == nil)
[self _sendAction:self];
else
[self _showMenu];
}
[self _showMenu];
}
else if (_CGRectContainsPoint([self cancelButtonRectForBounds:[self bounds]], point))
[_cancelButton mouseDown:anEvent];
else
@@ -504,69 +514,69 @@ var RECENT_SEARCH_PREFIX = @" ";
/*!
Provides the common case items for a recent searches menu. If there are not recent searches,
displays a single disabled item:
No Recent Searches
If there are 1 more recent searches, it displays:
Recent Searches
recent search 1
recent search 2
etc.
---------------------
Clear Recent Searches
If you wish to add items before or after the template, you can. If you put items
before, a separator will automatically be placed before the default template item.
If you add items after the default template, it is your responsibility to add a separator.
To add a custom item:
item = [[CPMenuItem alloc] initWithTitle:@"google"
action:@selector(google:)
item = [[CPMenuItem alloc] initWithTitle:@"google"
action:@selector(google:)
keyEquivalent:@""];
[item setTag:700];
[item setTarget:self];
[template addItem:item];
Be sure that your custom items do not use tags in the range 1000-1004 inclusive.
Be sure that your custom items do not use tags in the range 1000-1003 inclusive.
If you wish to maintain state in custom menu items that you add, you will need to maintain
the item state yourself, then in the action method of the custom items, modify the items
in the search menu template and send [searchField setSearchMenuTemplate:template] to update the menu.
*/
- (CPMenu)defaultSearchMenuTemplate
{
var template = [[CPMenu alloc] init],
var template = [[CPMenu alloc] init],
item;
item = [[CPMenuItem alloc] initWithTitle:@"Recent Searches"
action:nil
item = [[CPMenuItem alloc] initWithTitle:@"Recent Searches"
action:nil
keyEquivalent:@""];
[item setTag:CPSearchFieldRecentsTitleMenuItemTag];
[item setEnabled:NO];
[template addItem:item];
item = [[CPMenuItem alloc] initWithTitle:@"Recent search item"
action:@selector(_searchFieldSearch:)
item = [[CPMenuItem alloc] initWithTitle:@"Recent search item"
action:@selector(_searchFieldSearch:)
keyEquivalent:@""];
[item setTag:CPSearchFieldRecentsMenuItemTag];
[item setTarget:self];
[template addItem:item];
item = [[CPMenuItem alloc] initWithTitle:@"Clear Recent Searches"
action:@selector(_searchFieldClearRecents:)
item = [[CPMenuItem alloc] initWithTitle:@"Clear Recent Searches"
action:@selector(_searchFieldClearRecents:)
keyEquivalent:@""];
[item setTag:CPSearchFieldClearRecentsMenuItemTag];
[item setTarget:self];
[template addItem:item];
item = [[CPMenuItem alloc] initWithTitle:@"No Recent Searches"
action:nil
item = [[CPMenuItem alloc] initWithTitle:@"No Recent Searches"
action:nil
keyEquivalent:@""];
[item setTag:CPSearchFieldNoRecentsMenuItemTag];
[item setEnabled:NO];
[template addItem:item];
return template;
}
@@ -574,72 +584,66 @@ var RECENT_SEARCH_PREFIX = @" ";
{
if (_searchMenuTemplate === nil)
return;
var menu = [[CPMenu alloc] init],
countOfRecents = [_recentSearches count],
numberOfItems = [_searchMenuTemplate numberOfItems];
for (var i = 0; i < numberOfItems; i++)
{
var item = [[_searchMenuTemplate itemAtIndex:i] copy];
switch ([item tag])
{
case CPSearchFieldRecentsTitleMenuItemTag:
if (countOfRecents === 0)
continue;
if ([menu numberOfItems] > 0)
[self _addSeparatorToMenu:menu];
break;
case CPSearchFieldRecentsMenuItemTag:
{
var itemAction = @selector(_searchFieldSearch:);
for (var recentIndex = 0; recentIndex < countOfRecents; ++recentIndex)
{
// RECENT_SEARCH_PREFIX is a hack until CPMenuItem -setIndentationLevel works
var recentItem = [[CPMenuItem alloc] initWithTitle:RECENT_SEARCH_PREFIX + [_recentSearches objectAtIndex:recentIndex]
action:itemAction
var recentItem = [[CPMenuItem alloc] initWithTitle:RECENT_SEARCH_PREFIX + [_recentSearches objectAtIndex:recentIndex]
action:itemAction
keyEquivalent:[item keyEquivalent]];
[item setTarget:self];
[menu addItem:recentItem];
}
continue;
}
case CPSearchFieldClearRecentsMenuItemTag:
if (countOfRecents === 0)
continue;
if ([menu numberOfItems] > 0)
[self _addSeparatorToMenu:menu];
[item setAction:@selector(_searchFieldClearRecents:)];
[item setTarget:self];
break;
case CPSearchFieldNoRecentsMenuItemTag:
if (countOfRecents !== 0)
continue;
if ([menu numberOfItems] > 0)
[self _addSeparatorToMenu:menu];
break;
case CPSearchFieldSeparatorMenuItemTag:
item = [CPMenuItem separatorItem];
[item setEnabled:NO];
[menu addItem:item];
continue;
}
}
[item setEnabled:([item isEnabled] && [item action] != nil && [item target] != nil)];
[menu addItem:item];
}
[menu setDelegate:self];
_searchMenu = menu;
@@ -660,7 +664,7 @@ var RECENT_SEARCH_PREFIX = @" ";
- (void)menuDidClose:(CPMenu)menu
{
_canResignFirstResponder = YES;
[self becomeFirstResponder];
}
@@ -668,12 +672,12 @@ var RECENT_SEARCH_PREFIX = @" ";
{
if (_searchMenu === nil || [_searchMenu numberOfItems] === 0 || ![self isEnabled])
return;
var aFrame = [[self superview] convertRect:[self frame] toView:nil],
location = CPMakePoint(aFrame.origin.x + 10, aFrame.origin.y + aFrame.size.height - 4);
var anEvent = [CPEvent mouseEventWithType:CPRightMouseDown location:location modifierFlags:0 timestamp:[[CPApp currentEvent] timestamp] windowNumber:[[self window] windowNumber] context:nil eventNumber:1 clickCount:1 pressure:0];
[self selectAll:nil];
[CPMenu popUpContextMenu:_searchMenu withEvent:anEvent forView:self];
}
@@ -684,24 +688,25 @@ 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];
}
- (void)_searchFieldSearch:(id)sender
{
var searchString = [[sender title] substringFromIndex:[RECENT_SEARCH_PREFIX length]];
if ([sender tag] != CPSearchFieldRecentsMenuItemTag)
[self _addStringToRecentSearches:searchString];
[self setObjectValue:searchString];
[self _sendPartialString];
[self selectAll:nil];
[self _updateCancelButtonVisibility];
}
@@ -715,54 +720,36 @@ var RECENT_SEARCH_PREFIX = @" ";
- (void)_registerForAutosaveNotification
{
[[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(_updateAutosavedRecents:) name:@"CPAutosavedRecentsChangedNotification" object:nil];
[[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(_updateAutosavedRecents:) name:CPAutosavedRecentsChangedNotification object:_recentsAutosaveName];
}
- (void)_deregisterForAutosaveNotification
{
[[CPNotificationCenter defaultCenter] removeObserver:self name:@"CPAutosavedRecentsChangedNotification" object:nil];
[[CPNotificationCenter defaultCenter] removeObserver:self name:CPAutosavedRecentsChangedNotification object:_recentsAutosaveName];
}
- (void)_autosaveRecentSearchList
{
if (_recentsAutosaveName != nil)
[[CPNotificationCenter defaultCenter] postNotificationName:@"CPAutosavedRecentsChangedNotification" object:_recentsAutosaveName];
{
if (_recentsAutosaveName != nil)
[[CPNotificationCenter defaultCenter] postNotificationName:CPAutosavedRecentsChangedNotification object:_recentsAutosaveName];
}
- (void)_updateAutosavedRecents:(id)notification
{
var list = [self recentSearches],
name = [notification object],
bundle_name = [[[CPBundle mainBundle] infoDictionary] objectForKey:"CPBundleName"],
cookie_name = [bundle_name lowercaseString] + "." + [notification object],
cookie = [[CPCookie alloc] initWithName:cookie_name],
cookie_value = [list componentsJoinedByString:@","];
[cookie setValue:cookie_value
expires:[[CPDate alloc] initWithTimeIntervalSinceNow:3600*24*365]
domain:(window.location.href.hostname)];
var name = [notification object];
[[CPUserDefaults standardUserDefaults] setObject:_recentSearches forKey:name];
}
- (void)_loadRecentSearchList
{
var list,
name = [self recentsAutosaveName];
var name = [self recentsAutosaveName];
if (name === nil)
return;
var bundle_name = [[[CPBundle mainBundle] infoDictionary] objectForKey:"CPBundleName"],
cookie_name = [bundle_name lowercaseString] + "." + name,
var list = [[CPUserDefaults standardUserDefaults] objectForKey:name];
cookie = [[CPCookie alloc] initWithName:cookie_name];
if (cookie != nil)
{
var cookie_value = [cookie value];
list = (cookie_value != @"") ? [cookie_value componentsSeparatedByString:@","] : [CPArray array];
if (list !== nil)
_recentSearches = list;
}
}
@end
@@ -780,7 +767,7 @@ var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
[_searchButton removeFromSuperview];
[_cancelButton removeFromSuperview];
[super encodeWithCoder:coder];
[super encodeWithCoder:coder];
if (_searchButton)
[self addSubview:_searchButton];
@@ -793,7 +780,7 @@ var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
if (_recentsAutosaveName)
[coder encodeObject:_recentsAutosaveName forKey:CPRecentsAutosaveNameKey];
if (_searchMenuTemplate)
[coder encodeObject:_searchMenuTemplate forKey:CPSearchMenuTemplateKey];
}
@@ -802,16 +789,16 @@ var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
{
if (self = [super initWithCoder:coder])
{
_recentsAutosaveName = [coder decodeObjectForKey:CPRecentsAutosaveNameKey];
[self setRecentsAutosaveName:[coder decodeObjectForKey:CPRecentsAutosaveNameKey]];
_sendsWholeSearchString = [coder decodeBoolForKey:CPSendsWholeSearchStringKey];
_sendsSearchStringImmediately = [coder decodeBoolForKey:CPSendsSearchStringImmediatelyKey];
_maximumRecents = [coder decodeIntForKey:CPMaximumRecentsKey];
var template = [coder decodeObjectForKey:CPSearchMenuTemplateKey];
if (template)
[self setSearchMenuTemplate:template];
[self _init];
}
+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"
+14 -4
View File
@@ -94,7 +94,9 @@ CPSegmentSwitchTrackingMomentary = 2;
if (_segments.length == aCount)
return;
var height = CGRectGetHeight([self bounds]);
var height = CGRectGetHeight([self bounds]),
dividersBefore = MAX(0, _segments.length - 1),
dividersAfter = MAX(0, aCount - 1);
if (_segments.length < aCount)
{
@@ -113,6 +115,14 @@ CPSegmentSwitchTrackingMomentary = 2;
if (_selectedSegment >= _segments.length)
_selectedSegment = -1;
// Make space for/remove space used by dividers.
var thickness = [self currentValueForThemeAttribute:@"divider-thickness"],
delta = thickness * (dividersAfter - dividersBefore),
frame = [self frame];
if (delta)
[self setFrameSize:CGSizeMake(frame.size.width + delta, frame.size.height)];
[self tileWithChangedSegment:0];
}
@@ -351,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
@@ -607,7 +617,7 @@ CPSegmentSwitchTrackingMomentary = 2;
segmentWidth = [segment width],
themeState = _themeStates[aSegment] | (_themeState & CPThemeStateDisabled),
contentInset = [self valueForThemeAttribute:@"content-inset" inState:themeState],
font = [self valueForThemeAttribute:@"font" inState:themeState];
font = [self font];
if (!segmentWidth)
{
+6 -6
View File
@@ -23,8 +23,8 @@
@import <Foundation/CPObject.j>
/*!
@deprecated
/*!
@deprecated
@class CPShadow
Instances of this class contain the attributes of a drop shadow used in Cappuccino.
@@ -34,7 +34,7 @@
CPSize _offset;
float _blurRadius;
CPColor _color;
CPString _cssString;
}
@@ -54,16 +54,16 @@
- (id)_initWithOffset:(CPSize)anOffset blurRadius:(float)aBlurRadius color:(CPColor)aColor
{
self = [super init];
if (self)
{
_offset = anOffset;
_blurRadius = aBlurRadius;
_color = aColor;
_cssString = [_color cssString] + " " + Math.round(anOffset.width) + @"px " + Math.round(anOffset.height) + @"px " + Math.round(_blurRadius) + @"px";
}
return self;
}
+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];
+62 -55
View File
@@ -28,16 +28,16 @@
@ignore
*/
@implementation CPSliderColorPicker : CPColorPicker
{
{
CPView _contentView;
CPSlider _redSlider;
CPSlider _greenSlider;
CPSlider _blueSlider;
CPSlider _hueSlider;
CPSlider _saturationSlider;
CPSlider _brightnessSlider;
CPTextField _rgbLabel;
CPTextField _hsbLabel;
CPTextField _redLabel;
@@ -58,27 +58,27 @@
CPTextField _brightnessValue;
}
- (id)initWithPickerMask:(int)mask colorPanel:(CPColorPanel)owningColorPanel
- (id)initWithPickerMask:(int)mask colorPanel:(CPColorPanel)owningColorPanel
{
return [super initWithPickerMask:mask colorPanel: owningColorPanel];
}
-(id)initView
- (id)initView
{
aFrame = CPRectMake(0, 0, CPColorPickerViewWidth, CPColorPickerViewHeight);
aFrame = CGRectMake(0, 0, CPColorPickerViewWidth, CPColorPickerViewHeight);
_contentView = [[CPView alloc] initWithFrame:aFrame];
[_contentView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
_rgbLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 10, 100, 20)];
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
_rgbLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 10, 100, 20)];
[_rgbLabel setStringValue: "Red, Green, Blue"];
[_rgbLabel setTextColor:[CPColor blackColor]];
_redLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 35, 15, 20)];
_redLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 37, 15, 20)];
[_redLabel setStringValue: "R"];
[_redLabel setTextColor:[CPColor blackColor]];
_redSlider = [[CPSlider alloc] initWithFrame: CPRectMake(15, 35, aFrame.size.width - 70, 20)];
_redSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 35, aFrame.size.width - 70, 20)];
[_redSlider setMaxValue: 1.0];
[_redSlider setMinValue: 0.0];
[_redSlider setTarget: self];
@@ -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: CPRectMake(0, 58, 15, 20)];
_greenLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 63, 15, 20)];
[_greenLabel setStringValue: "G"];
[_greenLabel setTextColor:[CPColor blackColor]];
_greenSlider = [[CPSlider alloc] initWithFrame: CPRectMake(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: CPRectMake(0, 81, 15, 20)];
_blueLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 90, 15, 20)];
[_blueLabel setStringValue: "B"];
[_blueLabel setTextColor:[CPColor blackColor]];
_blueSlider = [[CPSlider alloc] initWithFrame: CPRectMake(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,22 +124,22 @@
[_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];
[_blueValue setDelegate: self];
[_contentView addSubview: _blueValue];
_hsbLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 120, 190, 20)];
_hsbLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 120, 190, 20)];
[_hsbLabel setStringValue: "Hue, Saturation, Brightness"];
[_hsbLabel setTextColor:[CPColor blackColor]];
_hueLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 145, 15, 20)];
_hueLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 145, 15, 20)];
[_hueLabel setStringValue: "H"];
[_hueLabel setTextColor:[CPColor blackColor]];
_hueSlider = [[CPSlider alloc] initWithFrame: CPRectMake(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,18 +147,18 @@
[_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: CPRectMake(0, 168, 15, 20)];
_saturationLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 170, 15, 20)];
[_saturationLabel setStringValue: "S"];
[_saturationLabel setTextColor:[CPColor blackColor]];
_saturationSlider = [[CPSlider alloc] initWithFrame: CPRectMake(15, 168, aFrame.size.width - 70, 20)];
_saturationSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 168, aFrame.size.width - 70, 20)];
[_saturationSlider setMaxValue: 100.0];
[_saturationSlider setMinValue: 0.0];
[_saturationSlider setTarget: self];
@@ -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: CPRectMake(0, 191, 15, 20)];
_brightnessLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 196, 15, 20)];
[_brightnessLabel setStringValue: "B"];
[_brightnessLabel setTextColor:[CPColor blackColor]];
_brightnessSlider = [[CPSlider alloc] initWithFrame: CPRectMake(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,19 +185,19 @@
[_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];
[_brightnessValue setDelegate: self];
[_contentView addSubview: _brightnessValue];
_hexLabel = [[CPTextField alloc] initWithFrame: CPRectMake(0, 230, 30, 20)];
_hexLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 230, 30, 20)];
[_hexLabel setStringValue: "Hex"];
[_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];
@@ -210,7 +210,7 @@
[_contentView addSubview: _redSlider];
[_contentView addSubview: _greenSlider];
[_contentView addSubview: _blueSlider];
[_contentView addSubview: _hsbLabel];
[_contentView addSubview: _hueLabel];
[_contentView addSubview: _saturationLabel];
@@ -218,35 +218,35 @@
[_contentView addSubview: _hueSlider];
[_contentView addSubview: _saturationSlider];
[_contentView addSubview: _brightnessSlider];
[_contentView addSubview: _hexLabel];
}
- (CPView)provideNewView:(BOOL)initialRequest
- (CPView)provideNewView:(BOOL)initialRequest
{
if (initialRequest)
if (initialRequest)
[self initView];
return _contentView;
}
- (int)currentMode
- (int)currentMode
{
return CPSliderColorPickerMode;
}
- (BOOL)supportsMode:(int)mode
- (BOOL)supportsMode:(int)mode
{
return (mode == CPSliderColorPickerMode) ? YES : NO;
}
-(void)sliderChanged:(id)sender
- (void)sliderChanged:(id)sender
{
var newColor,
colorPanel = [self colorPanel],
alpha = [colorPanel opacity];
switch(sender)
switch (sender)
{
case _hueSlider:
case _saturationSlider:
@@ -254,27 +254,27 @@
saturation: [_saturationSlider floatValue]
brightness: [_brightnessSlider floatValue]
alpha: alpha];
[self updateRGBSliders: newColor];
break;
case _redSlider:
case _greenSlider:
case _blueSlider: newColor = [CPColor colorWithCalibratedRed: [_redSlider floatValue]
green: [_greenSlider floatValue]
blue: [_blueSlider floatValue]
alpha: alpha];
[self updateHSBSliders: newColor];
break;
}
[self updateLabels];
[self updateHex: newColor];
[colorPanel setColor: newColor];
}
-(void)setColor:(CPColor)aColor
- (void)setColor:(CPColor)aColor
{
[self updateRGBSliders: aColor];
[self updateHSBSliders: aColor];
@@ -282,10 +282,10 @@
[self updateLabels];
}
-(void)updateHSBSliders:(CPColor)aColor
- (void)updateHSBSliders:(CPColor)aColor
{
var hsb = [aColor hsbComponents];
[_hueSlider setFloatValue:hsb[0]];
[_saturationSlider setFloatValue:hsb[1]];
[_brightnessSlider setFloatValue:hsb[2]];
@@ -310,7 +310,7 @@
[_hueValue setStringValue: ROUND([_hueSlider floatValue])];
[_saturationValue setStringValue: ROUND([_saturationSlider floatValue])];
[_brightnessValue setStringValue: ROUND([_brightnessSlider floatValue])];
[_redValue setStringValue: ROUND([_redSlider floatValue] * 255)];
[_greenValue setStringValue: ROUND([_greenSlider floatValue] * 255)];
[_blueValue setStringValue: ROUND([_blueSlider floatValue] * 255)];
@@ -330,14 +330,21 @@
{
var field = [aNotification object],
value = [[field stringValue] stringByTrimmingWhitespace];
if (field === _hexValue) {
if (field === _hexValue)
{
var newColor = [CPColor colorWithHexString: value];
if (newColor) {
if (newColor)
{
[self setColor: newColor];
[[self colorPanel] setColor: newColor];
}
} else {
switch(field) {
}
else
{
switch (field)
{
case _redValue: [_redSlider setFloatValue:MAX(MIN(ROUND(value), 255) / 255.0, 0)];
[self sliderChanged: _redSlider];
break;
+303
View File
@@ -0,0 +1,303 @@
/*
* CPSound.j
* AppKit
*
* Created by Antoine Mercadal
* Copyright 2010, Antoine Mercadal
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPObject.j>
CPSoundLoadStateEmpty = 0;
CPSoundLoadStateLoading = 1;
CPSoundLoadStateCanBePlayed = 2;
CPSoundLoadStateError = 3;
CPSoundPlayBackStatePlay = 0;
CPSoundPlayBackStateStop = 1;
CPSoundPlayBackStatePause = 2;
/*!
CPSound provides a way to load and play sounds. In the browser it relies on the
HTML5 audio tag being available.
CPSound delegate:
- sound:didFinishPlaying: called when sound has finished to played
*/
@implementation CPSound : CPObject
{
CPString _name @accessors(property=name);
id _delegate @accessors(property=delegate);
HTMLAudioElement _audioTag;
int _loadStatus;
int _playBackStatus;
}
#pragma mark -
#pragma mark Initialization
- (id)init
{
if (self = [super init])
{
_loadStatus = CPSoundLoadStateEmpty;
_loops = NO;
_audioTag = document.createElement("audio");
_audioTag.preload = YES;
_audioTag.addEventListener("canplay", function()
{
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
[self _soundDidload];
}, true);
_audioTag.addEventListener("ended", function()
{
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
[self _soundDidEnd];
}, true);
_audioTag.addEventListener("error", function()
{
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
[self _soundError];
}, true);
}
return self;
}
/*!
Initialize with the sound contents of the URL represented by aFile.
@param aFile CPString the path of the sound
@param byRef ignored (Cocoa compatibility)
*/
- (id)initWithContentsOfFile:(CPString)aFile byReference:(BOOL)byRef
{
if (self = [self init])
{
_loadStatus = CPSoundLoadStateLoading;
_audioTag.src = aFile;
}
return self;
}
/*!
Initialize with the sound contents of the file located at aURL.
@param aURL CPURL containing the URL of the sound
@param byRef ignored (Cocoa compatibility)
*/
- (id)initWithContentsOfURL:(CPURL)aURL byReference:(BOOL)byRef
{
return [self initWithContentsOfFile:[aURL absoluteString] byReference:NO];
}
/*!
Initialize with the sound contents of someData.
@param someData CPData containing the sound
@param byRef ignored (Cocoa compatibility)
*/
- (id)initWithData:(CPData)someData
{
if (self = [self init])
{
_loadStatus = CPSoundLoadStateLoading;
_audioTag.src = [someData rawString];
}
return self;
}
#pragma mark -
#pragma mark Events listener
/*! @ignore
*/
- (void)_soundDidload
{
_loadStatus = CPSoundLoadStateCanBePlayed;
}
/*! @ignore
*/
- (void)_soundDidEnd
{
if (![self loops])
[self stop];
}
/*! @ignore
*/
- (void)_soundError
{
_loadStatus = CPSoundLoadStateError;
CPLog.error("Cannot load sound. Maybe the format of your sound is not compatible with your browser.");
}
#pragma mark -
#pragma mark Media controls
/*!
Play the sound.
@return YES when the receiver is playing its audio data, NO otherwise.
*/
- (BOOL)play
{
if ((_loadStatus !== CPSoundLoadStateCanBePlayed)
|| (_playBackStatus === CPSoundPlayBackStatePlay))
return NO;
_audioTag.play();
_playBackStatus = CPSoundPlayBackStatePlay;
return YES;
}
/*!
Stop the sound.
@return YES when the receiver is playing its audio data, NO otherwise.
*/
- (BOOL)stop
{
if ((_loadStatus !== CPSoundLoadStateCanBePlayed)
|| (_playBackStatus === CPSoundPlayBackStateStop))
return NO;
_audioTag.pause();
_audioTag.currentTime = 0.0;
_playBackStatus = CPSoundPlayBackStateStop;
if (_delegate && [_delegate respondsToSelector:@selector(sound:didFinishPlaying:)])
[_delegate sound:self didFinishPlaying:YES];
return YES;
}
/*!
Pause the sound.
@return YES when the receiver is playing its audio data, NO otherwise.
*/
- (BOOL)pause
{
if ((_loadStatus !== CPSoundLoadStateCanBePlayed)
|| (_playBackStatus === CPSoundPlayBackStatePause))
return NO;
_audioTag.pause();
_playBackStatus = CPSoundPlayBackStatePause;
return YES;
}
/*!
Resume playback of a paused sound.
@return YES when the receiver is playing its audio data, NO otherwise.
*/
- (BOOL)resume
{
if ((_loadStatus !== CPSoundLoadStateCanBePlayed)
|| (_playBackStatus !== CPSoundPlayBackStatePause))
return NO;
_audioTag.play();
_playBackStatus = CPSoundPlayBackStatePlay;
return YES;
}
/*!
Return YES if the sound is in loop mode.
@return BOOL YES if in loop mode, NO otherwise
*/
- (BOOL)loops
{
return _audioTag.loop;
}
/*!
Specifies whether the sound should repeat.
@param BOOL YES for loop mode, NO otherwise
*/
- (void)setLoops:(BOOL)shouldLoop
{
_audioTag.loop = shouldLoop;
}
/*!
Returns the volume of the receiver.
@return double from 0.0 to 1.0
*/
- (double)volume
{
return _audioTag.volume;
}
/*!
Set the volume the sound should be played at.
@param double a volume value between 0.0 and 1.0
*/
- (void)setVolume:(double)aVolume
{
if (aVolume > 1.0)
aVolume = 1.0;
else if (aVolume < 0.0)
aVolume = 0.0;
_audioTag.volume = aVolume;
}
#pragma mark -
#pragma mark Accessors
/*!
Returns the duration in seconds of the sound.
@return double the duration
*/
- (double)duration
{
return _audioTag.duration;
}
/*!
Returns if the sound is playing or not.
@return BOOL YES if the sound is playing, NO otherwise
*/
- (BOOL)isPlaying
{
return (_playBackStatus === CPSoundPlayBackStatePlay);
}
@end
+174 -17
View File
@@ -33,6 +33,14 @@ var CPSplitViewHorizontalImage = nil,
/*!
@ingroup appkit
@class CPSplitView
CPSplitView is a view that allows you to stack several subviews vertically or horizontally. The user is given divider to resize the subviews.
The divider indices are zero-based. So the divider on the top (or left for vertical dividers) will be index 0.
CPSplitView can be supplied a delegate to provide control over the resizing of the splitview and subviews. Those methods are documented in setDelegate:
CPSplitView will add dividers for each subview you add. So just like adding subviews to a CPView you should call addSubview: to add new resizable subviews in your splitview.
*/
@implementation CPSplitView : CPView
@@ -64,7 +72,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"]];
}
@@ -96,16 +104,28 @@ var CPSplitViewHorizontalImage = nil,
return self;
}
/*!
Returns the thickness of the divider.
@return float - the thickness of the divider.
*/
- (float)dividerThickness
{
return [self currentValueForThemeAttribute:[self isPaneSplitter] ? @"pane-divider-thickness" : @"divider-thickness"];
}
/*!
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 +167,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 +203,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 +232,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 +260,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 +312,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 = "";
}
}
@@ -485,6 +561,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 +576,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)
@@ -535,6 +621,11 @@ var CPSplitViewHorizontalImage = nil,
return realPosition;
}
/*!
Sets the position of a divider at a given index.
@param position - The float value of the position to place the divider.
@param dividerIndex - The index of the divider to position.
*/
- (void)setPosition:(float)position ofDividerAtIndex:(int)dividerIndex
{
[self _adjustSubviewsWithCalculatedSize];
@@ -621,17 +712,20 @@ var CPSplitViewHorizontalImage = nil,
viewFrame = CGRectMakeCopy(bounds),
isSizable = isVertical ? [view autoresizingMask] & CPViewWidthSizable : [view autoresizingMask] & CPViewHeightSizable;
if (index + 1 == count)
viewFrame.size[_sizeComponent] = bounds.size[_sizeComponent] - viewFrame.origin[_originComponent];
else if (totalSizableSpace && isSizable && lastSizableIndex === index)
viewFrame.size[_sizeComponent] = MAX(0, ROUND([view frame].size[_sizeComponent] + remainingFlexibleSpace))
else if (isSizable || !totalSizableSpace)
{
viewFrame.size[_sizeComponent] = MAX(0, ROUND(ratio * [view frame].size[_sizeComponent]));
remainingFlexibleSpace -= (viewFrame.size[_sizeComponent] - [view frame].size[_sizeComponent]);
}
else if (totalSizableSpace && !isSizable)
viewFrame.size[_sizeComponent] = [view frame].size[_sizeComponent];
if (index + 1 === count)
viewFrame.size[_sizeComponent] = bounds.size[_sizeComponent] - viewFrame.origin[_originComponent];
else if (totalSizableSpace && isSizable && lastSizableIndex === index)
viewFrame.size[_sizeComponent] = MAX(0, ROUND([view frame].size[_sizeComponent] + remainingFlexibleSpace))
else if (isSizable || !totalSizableSpace)
{
viewFrame.size[_sizeComponent] = MAX(0, ROUND(ratio * [view frame].size[_sizeComponent]));
remainingFlexibleSpace -= (viewFrame.size[_sizeComponent] - [view frame].size[_sizeComponent]);
}
else if (totalSizableSpace && !isSizable)
viewFrame.size[_sizeComponent] = [view frame].size[_sizeComponent];
bounds.origin[_originComponent] += viewFrame.size[_sizeComponent] + dividerThickness;
@@ -641,6 +735,66 @@ var CPSplitViewHorizontalImage = nil,
[self _postNotificationDidResize];
}
/*!
Sets the delegate of the receiver.
Possible delegate methods to implement are listed below.
Notifies the delegate when the subviews have resized.
@code
- (void)splitViewDidResizeSubviews:(CPNotification)aNotification;
@endcode
Notifies the delegate when the subviews will be resized.
@code
- (void)splitViewWillResizeSubviews:(CPNotification)aNotification;
@endcode
Lets the delegate specify a different rect for which the user can drag the splitView divider.
@code
- (CGRect)splitView:(CPSplitView)aSplitView effectiveRect:(CGRect)aRect forDrawnRect:(CGRect)aDrawnRect ofDividerAtIndex:(int)aDividerIndex;
@endcode
Lets the delegate specify an additional rect for which the user can drag the splitview divider.
@code
- (CGRect)splitView:(CPSplitView)aSplitView additionalEffectiveRectOfDividerAtIndex:(int)indexOfDivider;
@endcode
Notifies the delegate that the splitview is about to be collapsed. This usually happens when the user
Double clicks on the divider. Return YES if the subview can be collapsed, otherwise NO.
@code
- (BOOL)splitView:(CPSplitView)aSplitView canCollapseSubview:(CPView)aSubview;
@endcode
Notifies the delegate that the subview at indexOfDivider is about to be collapsed. This usually happens when the user
Double clicks on the divider. Return YES if the subview should be collapsed, otherwise NO.
@code
- (BOOL)splitView:(CPSplitView)aSplitView shouldCollapseSubview:(CPView)aSubview forDoubleClickOnDividerAtIndex:(int)indexOfDivider;
@endcode
Allows the delegate to constrain the subview beings resized. This method is called continuously as the user resizes the divider.
For example if the subview needs to have a width which is a multiple of a certain number you could return that multiple with this method.
@code
- (float)splitView:(CPSplitView)aSpiltView constrainSplitPosition:(float)proposedPosition ofSubviewAt:(int)subviewIndex;
@endcode
Allows the delegate to constrain the minimum position of a subview.
@code
- (float)splitView:(CPSplitView)aSplitView constrainMinCoordinate:(float)proposedMin ofSubviewAt:(int)subviewIndex;
@endcode
Allows the delegate to constrain the maximum position of a subview.
@code
- (float)splitView:(CPSplitView)aSplitView constrainMaxCoordinate:(float)proposedMax ofSubviewAt:(int)subviewIndex;
@endcode
Allows the splitview to specify a custom resizing behavior. This is called when the splitview is resized.
The sum of the views and the sum of the dividers should be equal to the size of the splitview.
@code
- (void)splitView:(CPSplitView)aSplitView resizeSubviewsWithOldSize:(CGSize)oldSize;
@endcode
@param delegate - The delegate of the splitview.
*/
- (void)setDelegate:(id)delegate
{
if ([_delegate respondsToSelector:@selector(splitViewDidResizeSubviews:)])
@@ -673,6 +827,9 @@ 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.
*/
- (void)setButtonBar:(CPButtonBar)aButtonBar forDividerAtIndex:(unsigned)dividerIndex
{
@@ -738,7 +895,7 @@ var CPSplitViewDelegateKey = "CPSplitViewDelegateKey",
_buttonBars = [aCoder decodeObjectForKey:CPSplitViewButtonBarsKey] || [];
_delegate = [aCoder decodeObjectForKey:CPSplitViewDelegateKey];
[self setDelegate:[aCoder decodeObjectForKey:CPSplitViewDelegateKey]];
_isPaneSplitter = [aCoder decodeBoolForKey:CPSplitViewIsPaneSplitterKey];
[self _setVertical:[aCoder decodeBoolForKey:CPSplitViewIsVerticalKey]];
+246
View File
@@ -0,0 +1,246 @@
/*
* CPStepper.j
* AppKit
*
* Created by Antoine Mercadal
* Copyright 2009, Antoine Mercadal
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <AppKit/CPControl.j>
@import <AppKit/CPButton.j>
@import <AppKit/CPTextField.j>
var CPStepperButtonsSize = CPSizeMake(19, 13);
/*! CPStepper is an implementation of Cocoa NSStepper.
This control display a two part button that can be used to increase or decrease a value with a given interval.
*/
@implementation CPStepper: CPControl
{
BOOL _valueWraps @accessors(property=valueWraps);
int _increment @accessors(property=increment);
int _maxValue @accessors(property=maxValue);
int _minValue @accessors(property=minValue);
CPButton _buttonDown;
CPButton _buttonUp;
}
#pragma mark -
#pragma mark Initialization
/*! Initializes a CPStepper with given values
@param aValue the initial value of the CPStepper
@param minValue the minimal acceptable value of the stepper
@param maxValue the maximal acceptable value of the stepper
@return Initialized CPStepper
*/
+ (CPStepper)stepperWithInitialValue:(float)aValue minValue:(float)aMinValue maxValue:(float)aMaxValue
{
var stepper = [[CPStepper alloc] initWithFrame:CPRectMake(0, 0, 19, 25)];
[stepper setDoubleValue:aValue];
[stepper setMinValue:aMinValue];
[stepper setMaxValue:aMaxValue];
return stepper;
}
/*! Initializes a CPStepper with default values:
- minValue = 0.0
- maxValue = 59.0
- value = 0.0
@return Initialized CPStepper
*/
+ (CPStepper)stepper
{
return [CPStepper stepperWithInitialValue:0.0 minValue:0.0 maxValue:59.0];
}
/*! Initializes the CPStepper
@param aFrame the frame of the control
@return initialized CPStepper
*/
- (id)initWithFrame:(CGRect)aFrame
{
if (self = [super initWithFrame:aFrame])
{
_maxValue = 59.0;
_minValue = 0.0;
_increment = 1.0;
_valueWraps = YES;
[self setDoubleValue:0.0];
_buttonUp = [[CPButton alloc] initWithFrame:CPRectMake(aFrame.size.width - CPStepperButtonsSize.width, 0, CPStepperButtonsSize.width, CPStepperButtonsSize.height)];
[_buttonUp setContinuous:YES];
[_buttonUp setTarget:self];
[_buttonUp setAction:@selector(_buttonDidClick:)];
[_buttonUp setAutoresizingMask:CPViewNotSizable];
[self addSubview:_buttonUp];
_buttonDown = [[CPButton alloc] initWithFrame:CPRectMake(aFrame.size.width - CPStepperButtonsSize.width, CPStepperButtonsSize.height, CPStepperButtonsSize.width, CPStepperButtonsSize.height - 1)];
[_buttonDown setContinuous:YES];
[_buttonDown setTarget:self];
[_buttonDown setAction:@selector(_buttonDidClick:)];
[_buttonDown setAutoresizingMask:CPViewNotSizable];
[self addSubview:_buttonDown];
[self setNeedsLayout];
}
return self;
}
#pragma mark -
#pragma mark Superclass overrides
/*! set if the CPStepper is enabled or not
@param shouldEnabled BOOL that define if stepper is enabled or not.
*/
- (void)setEnabled:(BOOL)shouldEnabled
{
[super setEnabled:shouldEnabled];
[_buttonUp setEnabled:shouldEnabled];
[_buttonDown setEnabled:shouldEnabled];
}
/*! set the frame of the CPStepper and check if width is not smaller than theme min-size
@param aFrame the frame
*/
- (void)setFrame:(CGRect)aFrame
{
if (aFrame.size.width >= CGRectGetWidth(aFrame))
[super setFrame:aFrame];
}
/*! @ignore
*/
- (void)layoutSubviews
{
[_buttonUp setValue:[self valueForThemeAttribute:@"bezel-color-up-button" inState:CPThemeStateBordered] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered];
[_buttonUp setValue:[self valueForThemeAttribute:@"bezel-color-up-button" inState:CPThemeStateBordered | CPThemeStateDisabled] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateDisabled];
[_buttonUp setValue:[self valueForThemeAttribute:@"bezel-color-up-button" inState:CPThemeStateBordered | CPThemeStateHighlighted] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateHighlighted];
[_buttonDown setValue:[self valueForThemeAttribute:@"bezel-color-down-button" inState:CPThemeStateBordered] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered];
[_buttonDown setValue:[self valueForThemeAttribute:@"bezel-color-down-button" inState:CPThemeStateBordered | CPThemeStateDisabled] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateDisabled];
[_buttonDown setValue:[self valueForThemeAttribute:@"bezel-color-down-button" inState:CPThemeStateBordered | CPThemeStateHighlighted] forThemeAttribute:@"bezel-color" inState:CPThemeStateBordered | CPThemeStateHighlighted];
}
/*! set if CPStepper should autorepeat
@param shouldAutoRepeat if YES, the first mouse down does one increment (decrement) and, after each delay of 0.5 seconds
*/
- (void)setAutorepeat:(BOOL)shouldAutoRepeat
{
[_buttonUp setContinuous:shouldAutoRepeat];
[_buttonDown setContinuous:shouldAutoRepeat];
}
/*! set the current value of the stepper
@param aValue a float containing the value
*/
- (void)setDoubleValue:(float)aValue
{
if (aValue > _maxValue)
[super setDoubleValue:_valueWraps ? _minValue : _maxValue];
else if (aValue < _minValue)
[super setDoubleValue:_valueWraps ? _maxValue : _minValue];
else
[super setDoubleValue:aValue];
}
#pragma mark -
#pragma mark Actions
/*! @ignore
*/
- (IBAction)_buttonDidClick:(id)aSender
{
if (![self isEnabled])
return;
if (aSender == _buttonUp)
[self setDoubleValue:([self doubleValue] + _increment)];
else
[self setDoubleValue:([self doubleValue] - _increment)];
if (_target && _action && [_target respondsToSelector:_action])
[self sendAction:_action to:_target];
}
/*! @perform a programatic click on up button
@param aSender sender of the action
*/
- (IBAction)performClickUp:(id)aSender
{
[_buttonUp performClick:aSender];
}
/*! @perform a programatic click on down button
@param aSender sender of the action
*/
- (IBAction)performClickDown:(id)aSender
{
[_buttonDown performClick:aSender];
}
#pragma mark -
#pragma mark Theming
+ (CPString)defaultThemeClass
{
return @"stepper";
}
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[[CPNull null], [CPNull null]]
forKeys:[@"bezel-color-up-button", @"bezel-color-down-button"]];
}
@end
@implementation CPStepper (CPCodingCompliance)
- (id)initWithCoder:(CPCoder)aCoder
{
if (self = [super initWithCoder:aCoder])
{
_maxValue = [aCoder decodeObjectForKey:@"_maxValue"];
_minValue = [aCoder decodeObjectForKey:@"_minValue"];
_increment = [aCoder decodeObjectForKey:@"_increment"];
_buttonUp = [aCoder decodeObjectForKey:@"_buttonUp"];
_buttonDown = [aCoder decodeObjectForKey:@"_buttonDown"];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:_maxValue forKey:@"_maxValue"];
[aCoder encodeObject:_minValue forKey:@"_minValue"];
[aCoder encodeObject:_increment forKey:@"_increment"];
[aCoder encodeObject:_buttonUp forKey:@"_buttonUp"];
[aCoder encodeObject:_buttonDown forKey:@"_buttonDown"];
}
@end
+183 -132
View File
@@ -3,83 +3,75 @@
@import "CPTabViewItem.j"
@import "CPView.j"
/*
Places tabs on top with a bezeled border.
@global
@group CPTabViewType
*/
CPTopTabsBezelBorder = 0;
//CPLeftTabsBezelBorder = 1;
//CPLeftTabsBezelBorder = 1;
CPBottomTabsBezelBorder = 2;
//CPRightTabsBezelBorder = 3;
/*
Displays no tabs and has a bezeled border.
@global
@group CPTabViewType
*/
CPNoTabsBezelBorder = 4;
/*
Has no tabs and displays a line border.
@global
@group CPTabViewType
*/
CPNoTabsLineBorder = 5;
/*
Displays no tabs and no border.
@global
@group CPTabViewType
*/
CPNoTabsNoBorder = 6;
//CPRightTabsBezelBorder = 3;
CPNoTabsBezelBorder = 4; //Displays no tabs and has a bezeled border.
CPNoTabsLineBorder = 5; //Has no tabs and displays a line border.
CPNoTabsNoBorder = 6; //Displays no tabs and no border.
var CPTabViewDidSelectTabViewItemSelector = 1,
CPTabViewShouldSelectTabViewItemSelector = 2,
CPTabViewWillSelectTabViewItemSelector = 4,
CPTabViewDidChangeNumberOfTabViewItemsSelector = 8;
var HEIGHT_OF_SEGMENTED_CONTROL = 24;
/*!
@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;
CPArray _items;
CPSegmentedControl tabs;
CPBox box;
CPSegmentedControl _tabs;
CPBox _box;
CPNumber selectedIndex;
CPNumber _selectedIndex;
CPTabViewType type;
CPTabViewType _type;
CPFont _font;
id delegate;
unsigned delegateSelectors;
id _delegate;
unsigned _delegateSelectors;
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
if (self = [super initWithFrame:aFrame])
{
items = [CPArray array];
tabs = [[CPSegmentedControl alloc] initWithFrame:CGRectMake(0, 0, 0, HEIGHT_OF_SEGMENTED_CONTROL)];
[tabs setHitTests:NO];
box = [[CPBox alloc] initWithFrame:CGRectMake(0, HEIGHT_OF_SEGMENTED_CONTROL / 2, CGRectGetWidth(aFrame),
CGRectGetHeight(aFrame) - HEIGHT_OF_SEGMENTED_CONTROL)];
selectedIndex = CPNotFound;
_items = [CPArray array];
_selectedIndex = CPNotFound;
[self _init];
[self setTabViewType:CPTopTabsBezelBorder];
[self setBackgroundColor:[CPColor colorWithCalibratedWhite:0.95 alpha:1.0]];
[self addSubview:box];
[self addSubview:tabs];
[box setAutoresizingMask:CPViewWidthSizable];
[tabs setAutoresizingMask:CPViewMinXMargin | CPViewMaxXMargin];
}
return self;
}
- (void)_init
{
_tabs = [[CPSegmentedControl alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
[_tabs setHitTests:NO];
var height = [_tabs valueForThemeAttribute:@"default-height"];
[_tabs setFrameSize:CGSizeMake(0, height)];
_box = [[CPBox alloc] initWithFrame:[self bounds]];
[self setBackgroundColor:[CPColor colorWithCalibratedWhite:0.95 alpha:1.0]];
[_box setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
[_tabs setAutoresizingMask:CPViewMinXMargin | CPViewMaxXMargin];
[self addSubview:_box];
[self addSubview:_tabs];
}
// Adding and Removing Tabs
/*!
Adds a CPTabViewItem to the tab view.
@@ -87,24 +79,25 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
*/
- (void)addTabViewItem:(CPTabViewItem)aTabViewItem
{
[self insertTabViewItem:aTabViewItem atIndex:[items count]];
[self insertTabViewItem:aTabViewItem atIndex:[_items count]];
}
/*!
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
*/
- (void)insertTabViewItem:(CPTabViewItem)aTabViewItem atIndex:(unsigned)anIndex
{
[items insertObject:aTabViewItem atIndex:anIndex];
[_items insertObject:aTabViewItem atIndex:anIndex];
[self _updateItems];
[self _repositionTabs];
if (delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
[delegate tabViewDidChangeNumberOfTabViewItems:self];
[aTabViewItem _setTabView:self];
if (_delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
[_delegate tabViewDidChangeNumberOfTabViewItems:self];
}
/*!
@@ -113,39 +106,45 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
*/
- (void)removeTabViewItem:(CPTabViewItem)aTabViewItem
{
for (var i = 0; i < [items count]; i++)
var count = [_items count];
for (var i = 0; i < count; i++)
{
if ([items objectAtIndex:i] === aTabViewItem)
if ([_items objectAtIndex:i] === aTabViewItem)
{
[items removeObjectAtIndex:i];
[_items removeObjectAtIndex:i];
break;
}
}
[self _updateItems];
[self _repositionTabs];
if (delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
[delegate tabViewDidChangeNumberOfTabViewItems:self];
[aTabViewItem _setTabView:nil];
if (_delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
[_delegate tabViewDidChangeNumberOfTabViewItems:self];
}
// Accessing Tabs
/*!
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
{
return [items indexOfObjectIdenticalTo:aTabViewItem];
return [_items indexOfObjectIdenticalTo:aTabViewItem];
}
/*!
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
{
for (var index = [items count]; index >= 0; index--)
if ([[items[index] identifier] isEqual:anIdentifier])
for (var index = [_items count]; index >= 0; index--)
if ([[_items[index] identifier] isEqual:anIdentifier])
return index;
return CPNotFound;
@@ -153,26 +152,29 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
/*!
Returns the number of items in the tab view.
@return the number of tab view items in the receiver
*/
- (unsigned)numberOfTabViewItems
{
return [items count];
return [_items count];
}
/*!
Returns the CPTabViewItem at the specified index.
@return a tab view item, or nil
*/
- (CPTabViewItem)tabViewItemAtIndex:(unsigned)anIndex
{
return [items objectAtIndex:anIndex];
return [_items objectAtIndex:anIndex];
}
/*!
Returns the array of items that backs this tab view.
@return a copy of the array of items in the receiver
*/
- (CPArray)tabViewItems
{
return [items copy]; // Copy?
return [_items copy]; // Copy?
}
// Selecting a Tab
@@ -182,7 +184,7 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
*/
- (void)selectFirstTabViewItem:(id)aSender
{
if ([items count] === 0)
if ([_items count] === 0)
return; // throw?
[self selectTabViewItemAtIndex:0];
@@ -194,10 +196,10 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
*/
- (void)selectLastTabViewItem:(id)aSender
{
if ([items count] === 0)
if ([_items count] === 0)
return; // throw?
[self selectTabViewItemAtIndex:[items count] - 1];
[self selectTabViewItemAtIndex:[_items count] - 1];
}
/*!
@@ -206,12 +208,12 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
*/
- (void)selectNextTabViewItem:(id)aSender
{
if (selectedIndex === CPNotFound)
if (_selectedIndex === CPNotFound)
return;
var nextIndex = selectedIndex + 1;
var nextIndex = _selectedIndex + 1;
if (nextIndex === [items count])
if (nextIndex === [_items count])
// does nothing. According to spec at (http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Reference/ApplicationKit/Classes/NSTabView_Class/Reference/Reference.html#//apple_ref/occ/instm/NSTabView/selectNextTabViewItem:)
return;
@@ -224,10 +226,10 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
*/
- (void)selectPreviousTabViewItem:(id)aSender
{
if (selectedIndex === CPNotFound)
if (_selectedIndex === CPNotFound)
return;
var previousIndex = selectedIndex - 1;
var previousIndex = _selectedIndex - 1;
if (previousIndex < 0)
return; // does nothing. See above.
@@ -250,32 +252,56 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
*/
- (void)selectTabViewItemAtIndex:(unsigned)anIndex
{
var aTabViewItem = [items objectAtIndex:anIndex];
var aTabViewItem = [_items objectAtIndex:anIndex];
if (anIndex === selectedIndex)
if (anIndex === _selectedIndex)
return;
var aTabViewItem = [self tabViewItemAtIndex:anIndex];
if ((delegateSelectors & CPTabViewShouldSelectTabViewItemSelector) && ![delegate tabView:self shouldSelectTabViewItem:aTabViewItem])
if ((_delegateSelectors & CPTabViewShouldSelectTabViewItemSelector) && ![_delegate tabView:self shouldSelectTabViewItem:aTabViewItem])
return;
if (delegateSelectors & CPTabViewWillSelectTabViewItemSelector)
[delegate tabView:self willSelectTabViewItem:aTabViewItem];
if (_delegateSelectors & CPTabViewWillSelectTabViewItemSelector)
[_delegate tabView:self willSelectTabViewItem:aTabViewItem];
[tabs selectSegmentWithTag:anIndex];
[_tabs selectSegmentWithTag:anIndex];
[self _setSelectedIndex:anIndex];
if (delegateSelectors & CPTabViewDidSelectTabViewItemSelector)
[delegate tabView:self didSelectTabViewItem:aTabViewItem];
if (_delegateSelectors & CPTabViewDidSelectTabViewItemSelector)
[_delegate tabView:self didSelectTabViewItem:aTabViewItem];
}
/*!
Returns the current item being displayed.
@return the tab view item currenly being displayed by the receiver
*/
- (CPTabViewItem)selectedTabViewItem
{
return [items objectAtIndex:selectedIndex];
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];
}
//
@@ -285,49 +311,60 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
*/
- (void)setTabViewType:(CPTabViewType)aTabViewType
{
if (type === aTabViewType)
if (_type === aTabViewType)
return;
if ((type === CPTopTabsBezelBorder || type === CPBottomTabsBezelBorder)
&& (aTabViewType !== CPTopTabsBezelBorder && aTabViewType !== CPBottomTabsBezelBorder))
[tabs removeFromSuperview];
_type = aTabViewType;
if ((type === CPNoTabsBezelBorder || type === CPNoTabsLineBorder || type === CPNoTabsNoBorder)
&& (aTabViewType !== CPNoTabsBezelBorder && aTabViewType !== CPNoTabsBezelBorder && aTabViewType !== CPNoTabsNoBorder))
[self addSubview:tabs];
if (_type !== CPTopTabsBezelBorder && _type !== CPBottomTabsBezelBorder)
{
[_box setFrame:[self bounds]];
[_tabs removeFromSuperview];
}
else
{
var aFrame = [self frame],
segmentedHeight = CGRectGetHeight([_tabs frame]),
origin = _type === CPTopTabsBezelBorder ? segmentedHeight / 2 : 0;
type = aTabViewType;
[_box setFrame:CGRectMake(0, origin, CGRectGetWidth(aFrame),
CGRectGetHeight(aFrame) - segmentedHeight / 2)];
switch (type)
[self addSubview:_tabs];
}
switch (_type)
{
case CPTopTabsBezelBorder:
case CPBottomTabsBezelBorder:
case CPNoTabsBezelBorder:
[box setBorderType:CPBezelBorder];
[_box setBorderType:CPBezelBorder];
break;
case CPNoTabsLineBorder:
[box setBorderType:CPLineBorder];
[_box setBorderType:CPLineBorder];
break;
case CPNoTabsNoBorder:
[box setBorderType:CPNoBorder];
[_box setBorderType:CPNoBorder];
break;
}
}
/*!
Returns the tab view type.
@return the tab view type of the receiver
*/
- (CPTabViewType)tabViewType
{
return type;
return _type;
}
/*!
Returns the receiver's delegate.
@return the receiver's delegate
*/
- (id)delegate
{
return delegate;
return _delegate;
}
/*!
@@ -336,71 +373,77 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
*/
- (void)setDelegate:(id)aDelegate
{
if (delegate == aDelegate)
if (_delegate == aDelegate)
return;
delegate = aDelegate;
_delegate = aDelegate;
delegateSelectors = 0;
_delegateSelectors = 0;
if ([delegate respondsToSelector:@selector(tabView:shouldSelectTabViewItem:)])
delegateSelectors |= CPTabViewShouldSelectTabViewItemSelector;
if ([_delegate respondsToSelector:@selector(tabView:shouldSelectTabViewItem:)])
_delegateSelectors |= CPTabViewShouldSelectTabViewItemSelector;
if ([delegate respondsToSelector:@selector(tabView:willSelectTabViewItem:)])
delegateSelectors |= CPTabViewWillSelectTabViewItemSelector;
if ([_delegate respondsToSelector:@selector(tabView:willSelectTabViewItem:)])
_delegateSelectors |= CPTabViewWillSelectTabViewItemSelector;
if ([delegate respondsToSelector:@selector(tabView:didSelectTabViewItem:)])
delegateSelectors |= CPTabViewDidSelectTabViewItemSelector;
if ([_delegate respondsToSelector:@selector(tabView:didSelectTabViewItem:)])
_delegateSelectors |= CPTabViewDidSelectTabViewItemSelector;
if ([delegate respondsToSelector:@selector(tabViewDidChangeNumberOfTabViewItems:)])
delegateSelectors |= CPTabViewDidChangeNumberOfTabViewItemsSelector;
if ([_delegate respondsToSelector:@selector(tabViewDidChangeNumberOfTabViewItems:)])
_delegateSelectors |= CPTabViewDidChangeNumberOfTabViewItemsSelector;
}
- (void)setBackgroundColor:(CPColor)aColor
{
[box setBackgroundColor:aColor];
[_box setBackgroundColor:aColor];
}
- (CPColor)backgroundColor
{
return [_box backgroundColor];
}
- (void)mouseDown:(CPEvent)anEvent
{
var segmentIndex = [tabs testSegment:[tabs convertPoint:[anEvent locationInWindow] fromView:nil]];
var segmentIndex = [_tabs testSegment:[_tabs convertPoint:[anEvent locationInWindow] fromView:nil]];
if (segmentIndex != CPNotFound)
{
[self selectTabViewItemAtIndex:segmentIndex];
[tabs trackSegment:anEvent];
[_tabs trackSegment:anEvent];
}
}
- (void)_repositionTabs
{
var horizontalCenterOfSelf = CGRectGetWidth([self bounds]) / 2,
verticalCenterOfTabs = CGRectGetHeight([tabs bounds]) / 2;
verticalCenterOfTabs = CGRectGetHeight([_tabs bounds]) / 2;
if (type === CPBottomTabsBezelBorder)
[tabs setCenter:CGPointMake(horizontalCenterOfSelf, CGRectGetHeight([self bounds]) - verticalCenterOfTabs)];
if (_type === CPBottomTabsBezelBorder)
[_tabs setCenter:CGPointMake(horizontalCenterOfSelf, CGRectGetHeight([self bounds]) - verticalCenterOfTabs)];
else
[tabs setCenter:CGPointMake(horizontalCenterOfSelf, verticalCenterOfTabs)];
[_tabs setCenter:CGPointMake(horizontalCenterOfSelf, verticalCenterOfTabs)];
}
- (void)_setSelectedIndex:(CPNumber)index
{
selectedIndex = index;
_selectedIndex = index;
[box setContentView:[[items objectAtIndex:selectedIndex] view]];
[_box setContentView:[[_items objectAtIndex:_selectedIndex] view]];
}
- (void)_updateItems
{
[tabs setSegmentCount:[items count]];
var count = [_items count];
[_tabs setSegmentCount:count];
for (var i = 0; i < [items count]; i++)
for (var i = 0; i < count; i++)
{
[tabs setLabel:[[items objectAtIndex:i] label] forSegment:i];
[tabs setTag:i forSegment:i];
[_tabs setLabel:[[_items objectAtIndex:i] label] forSegment:i];
[_tabs setTag:i forSegment:i];
}
if (selectedIndex === CPNotFound)
if (_selectedIndex === CPNotFound)
{
[self selectFirstTabViewItem:self];
}
@@ -411,6 +454,7 @@ var HEIGHT_OF_SEGMENTED_CONTROL = 24;
var CPTabViewItemsKey = "CPTabViewItemsKey",
CPTabViewSelectedItemKey = "CPTabViewSelectedItemKey",
CPTabViewTypeKey = "CPTabViewTypeKey",
CPTabViewFontKey = "CPTabViewFontKey",
CPTabViewDelegateKey = "CPTabViewDelegateKey";
@implementation CPTabView (CPCoding)
@@ -419,18 +463,24 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
{
if (self = [super initWithCoder:aCoder])
{
type = [aCoder decodeIntForKey:CPTabViewTypeKey];
items = [];
[self _init];
var encodedItems = [aCoder decodeObjectForKey:CPTabViewItemsKey];
for (var i = 0; encodedItems && i < encodedItems.length; i++)
[self insertTabViewItem:encodedItems[i] atIndex:i];
_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];
[self setDelegate:[aCoder decodeObjectForKey:CPTabViewDelegateKey]];
[self setTabViewType:[aCoder decodeIntForKey:CPTabViewTypeKey]];
}
return self;
@@ -440,12 +490,13 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:items forKey:CPTabViewItemsKey];;
[aCoder encodeObject:_items forKey:CPTabViewItemsKey];
[aCoder encodeObject:[self selectedTabViewItem] forKey:CPTabViewSelectedItemKey];
[aCoder encodeInt:type forKey:CPTabViewTypeKey];
[aCoder encodeInt:_type forKey:CPTabViewTypeKey];
[aCoder encodeObject:_font forKey:CPTabViewFontKey];
[aCoder encodeConditionalObject:delegate forKey:CPTabViewDelegateKey];
[aCoder encodeConditionalObject:_delegate forKey:CPTabViewDelegateKey];
}
@end
+12 -12
View File
@@ -44,7 +44,7 @@ CPBackgroundTab = 1;
*/
CPPressedTab = 2;
/*!
/*!
@ingroup appkit
@class CPTabViewItem
@@ -55,10 +55,10 @@ CPPressedTab = 2;
{
id _identifier;
CPString _label;
CPView _view;
CPView _auxiliaryView;
CPTabView _tabView;
}
@@ -74,10 +74,10 @@ CPPressedTab = 2;
- (id)initWithIdentifier:(id)anIdentifier
{
self = [super init];
if (self)
_identifier = anIdentifier;
return self;
}
@@ -145,8 +145,8 @@ CPPressedTab = 2;
// Assigning an Auxiliary View
/*!
Sets the tab's 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
{
@@ -191,16 +191,16 @@ var CPTabViewItemIdentifierKey = "CPTabViewItemIdentifierKey",
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
if (self)
{
_identifier = [aCoder decodeObjectForKey:CPTabViewItemIdentifierKey];
_label = [aCoder decodeObjectForKey:CPTabViewItemLabelKey];
_view = [aCoder decodeObjectForKey:CPTabViewItemViewKey];
_auxiliaryView = [aCoder decodeObjectForKey:CPTabViewItemAuxViewKey];
}
return self;
}
@@ -208,7 +208,7 @@ var CPTabViewItemIdentifierKey = "CPTabViewItemIdentifierKey",
{
[aCoder encodeObject:_identifier forKey:CPTabViewItemIdentifierKey];
[aCoder encodeObject:_label forKey:CPTabViewItemLabelKey];
[aCoder encodeObject:_view forKey:CPTabViewItemViewKey];
[aCoder encodeObject:_auxiliaryView forKey:CPTabViewItemAuxViewKey];
}
+289 -36
View File
@@ -33,6 +33,17 @@ CPTableColumnNoResizing = 0;
CPTableColumnAutoresizingMask = 1 << 0;
CPTableColumnUserResizingMask = 1 << 1;
/*!
@class CPTableColumn
A CPTableColumn contains a dataview to display for its column of the CPTableView.
A CPTableColumn determines its own size constrains and resizing behavior.
The default dataview is a CPTextField but you can set it to any view you'd like. See -setDataView: for documentation including theme states.
To customize the text of the column header you can simply call setStringValue: on the headerview of a table column.
For example: [[myTableColumn headerView] setStringValue:"My Title"];
*/
@implementation CPTableColumn : CPObject
{
CPTableView _tableView;
@@ -54,11 +65,18 @@ CPTableColumnUserResizingMask = 1 << 1;
BOOL _disableResizingPosting @accessors(property=disableResizingPosting);
}
/*!
@ignore
*/
- (id)init
{
return [self initWithIdentifier:@""];
}
/*!
Initializes a newly created CPTableColumn with a given identifier.
*/
- (id)initWithIdentifier:(id)anIdentifier
{
self = [super init];
@@ -84,17 +102,50 @@ CPTableColumnUserResizingMask = 1 << 1;
return self;
}
/*!
Set the columns's parent tableview
*/
- (void)setTableView:(CPTableView)aTableView
{
_tableView = aTableView;
}
/*!
Return the column's parent tableview
*/
- (CPTableView)tableView
{
return _tableView;
}
/*!
@ignore
this method tries to resize a column called via the tableview via autoresizing
it returns the delta from the actual resize and the proposed resize
for example if the column should have been resized 50px but the maxWidth was hit only
after 25px then the return value would be 25px;
if no edge has been hit zero will be returned
*/
- (int)_tryToResizeToWidth:(int)width
{
var min = [self minWidth],
max = [self maxWidth],
newWidth = MIN(MAX(width, min), max);
[self setWidth:newWidth];
return newWidth - width;
}
/*!
Set the width of the column
Default value is: 100
If the value is greater than the maxWidth the maxWidth will be reset with the supplied width here
If the value is less than the minWidth the minWidth will be reset with the supplied width.
*/
- (void)setWidth:(float)aWidth
{
aWidth = +aWidth;
@@ -135,11 +186,18 @@ CPTableColumnUserResizingMask = 1 << 1;
}
}
/*!
Returns the column's width
*/
- (float)width
{
return _width;
}
/*!
Sets the minimum width of the column.
Default value is 10.
*/
- (void)setMinWidth:(float)aMinWidth
{
aMinWidth = +aMinWidth;
@@ -156,11 +214,18 @@ CPTableColumnUserResizingMask = 1 << 1;
[self setWidth:newWidth];
}
/*!
Returns the minimum width of the column.
*/
- (float)minWidth
{
return _minWidth;
}
/*!
Sets the maximum width of the table column.
Default value is: 1000000
*/
- (void)setMaxWidth:(float)aMaxWidth
{
aMaxWidth = +aMaxWidth;
@@ -177,21 +242,42 @@ CPTableColumnUserResizingMask = 1 << 1;
[self setWidth:newWidth];
}
/*!
Returns the maximum width of the column
*/
- (float)maxWidth
{
return _maxWidth;
}
/*!
<pre>
Set the resizing mask of the column.
By default the column can be resized automatically with the tableview and manually by the user
Possible masking values are:
CPTableColumnNoResizing
CPTableColumnAutoresizingMask
CPTableColumnUserResizingMask
</pre>
*/
- (void)setResizingMask:(unsigned)aResizingMask
{
_resizingMask = aResizingMask;
}
/*!
Returns the resizing mask of the column
*/
- (unsigned)resizingMask
{
return _resizingMask;
}
/*!
Sizes the column to fix the column header text.
*/
- (void)sizeToFit
{
var width = _CGRectGetWidth([_headerView frame]);
@@ -205,7 +291,16 @@ CPTableColumnUserResizingMask = 1 << 1;
[self setWidth:width];
}
//Setting Component Cells
/*!
Sets the header view for the column.
The headerview handles the display of sort indicators, text, etc.
If you do not want a headerview for you table you should call setHeaderView: on your CPTableView instance.
Passing nil here will throw an exception.
In order to customize the text of the column header see - (CPView)headerView;
*/
- (void)setHeaderView:(CPView)aView
{
if (!aView)
@@ -219,26 +314,80 @@ CPTableColumnUserResizingMask = 1 << 1;
[tableHeaderView setNeedsDisplay:YES];
}
/*!
Returns the headerview for the column.
In order to change the text of the headerview for a column you should call setStringValue: on the headerview.
For example: [[myTableColumn headerView] setStringValue:"My Column"];
*/
- (CPView)headerView
{
return _headerView;
}
/*!
This method set's the "prototype" view which will be used to create all table cells in this column.
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.
Example:
[tableColumn setDataView:someView]; // snapshot taken
[[tableColumn dataView] setSomething:x]; //won't work
@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
[someView setSomething:x];
[tableColumn setDataView:someView];
@note You should implement CPKeyedArchiving otherwise you might see unexpected results.
This is done by adding the following methods to your class:
@endnote
@code
- (id)initWithCoder(CPCoder)aCoder;
- (void)encodeWithCoder:(CPCoder)aCoder;
@endcode
Example:
Say you have two instance variables in your object that need to be set up each time an object is create.
We will call these instance variables "image" and "text".
Your CPCoding methods will look like the following:
@code
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
image = [aCoder decodeObjectForKey:"MyDataViewImage"];
text = [aCoder decodeObjectForKey:"MyDataViewText"];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:image forKey:"MyDataViewImage"];
[aCoder encodeObject:text forKey:"MyDataViewText"];
}
@endcode
@section Theming
When you set a dataview and it is added to the tableview the theme state will be set to \c CPThemeStateTableDataView
When the dataview becomes selected the theme state will be set to \c CPThemeStateSelectedDataView.
If the dataview shows up in a group row of the tableview the theme state will be set to \c CPThemeStateGroupRow.
You should overide \c setThemeState: and \c unsetThemeState: to handle these theme state changes in your dataview.
*/
- (void)setDataView:(CPView)aView
{
@@ -260,7 +409,7 @@ CPTableColumnUserResizingMask = 1 << 1;
Returns the CPView object used by the CPTableView to draw values for the receiver.
By default, this method just calls dataView. Subclassers can override if they need to
potentially use different cells for different rows. Subclasses should expect this method
potentially use different "cells" or dataViews for different rows. Subclasses should expect this method
to be invoked with row equal to -1 in cases where no actual row is involved but the table
view needs to get some generic cell info.
*/
@@ -269,6 +418,9 @@ CPTableColumnUserResizingMask = 1 << 1;
return [self dataView];
}
/*!
@ignore
*/
- (id)_newDataViewForRow:(int)aRowIndex
{
var dataView = [self dataViewForRow:aRowIndex],
@@ -276,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])
@@ -294,7 +446,7 @@ CPTableColumnUserResizingMask = 1 << 1;
//Setting the Identifier
/*
/*!
Sets the receiver identifier to anIdentifier.
*/
- (void)setIdentifier:(id)anIdentifier
@@ -302,7 +454,7 @@ CPTableColumnUserResizingMask = 1 << 1;
_identifier = anIdentifier;
}
/*
/*!
Returns the object used by the data source to identify the attribute corresponding to the receiver.
*/
- (id)identifier
@@ -312,7 +464,7 @@ CPTableColumnUserResizingMask = 1 << 1;
//Controlling Editability
/*
/*!
Controls whether the user can edit cells in the receiver by double-clicking them.
*/
- (void)setEditable:(BOOL)shouldBeEditable
@@ -320,28 +472,35 @@ CPTableColumnUserResizingMask = 1 << 1;
_isEditable = shouldBeEditable;
}
/*
/*!
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
{
return _isEditable;
}
//Sorting
/*!
Sets the sort descriptor prototype for the column.
*/
- (void)setSortDescriptorPrototype:(CPSortDescriptor)aSortDescriptor
{
_sortDescriptorPrototype = aSortDescriptor;
}
/*!
Returns the sort descriptor prototype for the column.
*/
- (CPSortDescriptor)sortDescriptorPrototype
{
return _sortDescriptorPrototype;
}
//Setting Column Visibility
/*!
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
{
shouldBeHidden = !!shouldBeHidden
@@ -354,6 +513,9 @@ CPTableColumnUserResizingMask = 1 << 1;
[[self tableView] _tableColumnVisibilityDidChange:self];
}
/*!
Returns the visibility status of the column.
*/
- (BOOL)isHidden
{
return _isHidden;
@@ -361,7 +523,7 @@ CPTableColumnUserResizingMask = 1 << 1;
//Setting Tool Tips
/*
/*!
Sets the tooltip string that is displayed when the cursor pauses over the
header cell of the receiver.
*/
@@ -370,13 +532,21 @@ CPTableColumnUserResizingMask = 1 << 1;
_headerToolTip = aToolTip;
}
/*!
Returns the tooltip for the column header
*/
- (CPString)headerToolTip
{
return _headerToolTip;
}
/*!
@ignore
*/
- (void)_postDidResizeNotificationWithOldWidth:(float)oldWidth
{
[[self tableView] _didResizeTableColumn:self];
[[CPNotificationCenter defaultCenter]
postNotificationName:CPTableViewColumnDidResizeNotification
object:[self tableView]
@@ -385,8 +555,40 @@ 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];
@@ -395,9 +597,12 @@ CPTableColumnUserResizingMask = 1 << 1;
[[self tableView] _establishBindingsIfUnbound:anObject];
}
- (void)prepareDataView:(CPView)aDataView forRow:(unsigned)aRow
/*!
@ignore
*/
- (void)_prepareDataView:(CPView)aDataView forRow:(unsigned)aRow
{
var bindingsDictionary = [CPKeyValueBinding allBindingsForObject:self],
var bindingsDictionary = [CPBinder allBindingsForObject:self],
keys = [bindingsDictionary allKeys];
for (var i = 0, count = [keys count]; i < count; i++)
@@ -437,9 +642,42 @@ CPTableColumnUserResizingMask = 1 << 1;
}
value = [binding transformValue:value withOptions:[bindingInfo objectForKey:CPOptionsKey]];
[aDataView setValue:value forKey:@"objectValue"];
}
}
// console.log(bindingName+" : "+keyPath+" : "+aRow+" : "+[[destination valueForKeyPath:keyPath] objectAtIndex:aRow]);
[aDataView setValue:value forKey:bindingPath];
/*!
@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];
}
}
}
@@ -448,11 +686,6 @@ CPTableColumnUserResizingMask = 1 << 1;
// return nil;
//}
- (void)setValue:(CPArray)content
{
[[self tableView] reloadData];
}
@end
var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
@@ -468,6 +701,9 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
@implementation CPTableColumn (CPCoding)
/*!
@ignore
*/
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
@@ -495,13 +731,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];
@@ -516,31 +755,45 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
@end
@implementation CPTableColumn (NSInCompatibility)
/*!
@ignore
*/
- (void)setHeaderCell:(CPView)aView
{
[CPException raise:CPUnsupportedMethodException
reason:@"setHeaderCell: is not supported. -setHeaderCell:aView instead."];
reason:@"setHeaderCell: is not supported. Use -setHeaderView:aView instead."];
}
/*!
@ignore
*/
- (CPView)headerCell
{
[CPException raise:CPUnsupportedMethodException
reason:@"headCell is not supported. -headerView instead."];
reason:@"headCell is not supported. Use -headerView instead."];
}
/*!
@ignore
*/
- (void)setDataCell:(CPView)aView
{
[CPException raise:CPUnsupportedMethodException
reason:@"setDataCell: is not supported. Use -setHeaderCell:aView instead."];
reason:@"setDataCell: is not supported. Use -setDataView:aView instead."];
}
/*!
@ignore
*/
- (CPView)dataCell
{
[CPException raise:CPUnsupportedMethodException
reason:@"dataCell is not supported. Use -dataCell instead."];
reason:@"dataCell is not supported. Use -dataView instead."];
}
/*!
@ignore
*/
- (id)dataCellForRow:(int)row
{
[CPException raise:CPUnsupportedMethodException
+32 -25
View File
@@ -56,7 +56,7 @@
{
_textField = [[_CPImageAndTextView alloc] initWithFrame:_CGRectMakeZero()];
[_textField setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
[_textField setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
[_textField setLineBreakMode:CPLineBreakByTruncatingTail];
[_textField setAlignment:CPLeftTextAlignment];
@@ -102,20 +102,20 @@
- (void)setFont:(CPFont)aFont
{
[_textField setFont:aFont];
[self setValue:aFont forThemeAttribute:"text-font"];
}
- (void)_setIndicatorImage:(CPImage)anImage
{
if (anImage)
{
[_textField setImage:anImage];
[_textField setImagePosition:CPImageRight];
}
else
{
[_textField setImagePosition:CPNoImage];
}
if (anImage)
{
[_textField setImage:anImage];
[_textField setImagePosition:CPImageRight];
}
else
{
[_textField setImagePosition:CPNoImage];
}
}
@end
@@ -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,19 +592,19 @@ 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];
if([headerView superview] != self)
if ([headerView superview] != self)
[self addSubview:headerView];
}
@@ -634,7 +634,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
columnMaxX;
CGContextBeginPath(context);
for(; columnArrayIndex < columnArrayCount; columnArrayIndex++)
for (; columnArrayIndex < columnArrayCount; columnArrayIndex++)
{
// grab each column rect and add vertical lines
var columnIndex = columnsArray[columnArrayIndex],
@@ -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);
@@ -669,7 +668,15 @@ var CPTableHeaderViewTableViewKey = @"CPTableHeaderViewTableViewKey",
{
[self _init];
_tableView = [aCoder decodeObjectForKey:CPTableHeaderViewTableViewKey];
_drawsColumnLines = [aCoder decodeBoolForKey:CPTableHeaderViewDrawsColumnLines];
// FIX ME: Take this out before 1.0
if ([aCoder containsValueForKey:CPTableHeaderViewDrawsColumnLines])
_drawsColumnLines = [aCoder decodeBoolForKey:CPTableHeaderViewDrawsColumnLines];
else
{
_drawsColumnLines = YES;
CPLog.warn("The tableview header being decoded is using an old cib. Please run Nib2Cib.");
}
}
return self;
+1621 -528
View File
File diff suppressed because it is too large Load Diff
+199 -72
View File
@@ -84,8 +84,6 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
CPColor _textFieldBackgroundColor;
id _placeholderString;
id _originalPlaceholderString;
BOOL _currentValueIsPlaceholder;
id _delegate;
@@ -160,6 +158,14 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
return "textfield";
}
+ (Class)_binderClassForBinding:(CPString)theBinding
{
if (theBinding === CPValueBinding)
return [_CPTextFieldValueBinder class];
return [super _binderClassForBinding:theBinding];
}
+ (id)themeAttributes
{
return [CPDictionary dictionaryWithObjects:[_CGInsetMakeZero(), _CGInsetMake(2.0, 2.0, 2.0, 2.0), [CPNull null]]
@@ -479,11 +485,15 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
#if PLATFORM(DOM)
var string = [self stringValue],
element = [self _inputElement];
element = [self _inputElement],
font = [self currentValueForThemeAttribute:@"font"];
// generate the font metric
[font _getMetrics];
element.value = string;
element.style.color = [[self currentValueForThemeAttribute:@"text-color"] cssString];
element.style.font = [[self currentValueForThemeAttribute:@"font"] cssString];
element.style.font = [font cssString];
element.style.zIndex = 1000;
switch ([self alignment])
@@ -495,12 +505,32 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
default: element.style.textAlign = "left";
}
var contentRect = [self contentRectForBounds:[self bounds]];
var contentRect = [self contentRectForBounds:[self bounds]],
verticalAlign = [self currentValueForThemeAttribute:"vertical-alignment"];
element.style.top = _CGRectGetMinY(contentRect) + "px";
switch (verticalAlign)
{
case CPTopVerticalTextAlignment:
var topPoint = (_CGRectGetMinY(contentRect) + 1) + "px"; // for the same reason we have a -1 for the left, we also have a + 1 here
break;
case CPCenterVerticalTextAlignment:
var topPoint = (_CGRectGetMidY(contentRect) - (font._lineHeight / 2) + 1) + "px";
break;
case CPBottomVerticalTextAlignment:
var topPoint = (_CGRectGetMaxY(contentRect) - font._lineHeight) + "px";
break;
default:
var topPoint = (_CGRectGetMinY(contentRect) + 1) + "px";
break;
}
element.style.top = topPoint;
element.style.left = (_CGRectGetMinX(contentRect) - 1) + "px"; // why -1?
element.style.width = _CGRectGetWidth(contentRect) + "px";
element.style.height = _CGRectGetHeight(contentRect) + "px";
element.style.height = font._lineHeight + "px"; // private ivar for the line height of the DOM text at this particular size
_DOMElement.appendChild(element);
@@ -554,7 +584,9 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
[self _setStringValue:element.value];
CPTextFieldInputResigning = YES;
element.blur();
if (CPTextFieldInputIsActive)
element.blur();
if (!CPTextFieldInputDidBlur)
CPTextFieldBlurFunction();
@@ -672,25 +704,84 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
- (void)keyDown:(CPEvent)anEvent
{
if ([anEvent keyCode] === CPReturnKeyCode)
{
if (_isEditing)
{
_isEditing = NO;
[self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:nil]];
}
// 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 sendAction:[self action] to:[self target]];
[self selectText:nil];
[[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
}
else
[[[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
{
if (_isEditing)
{
_isEditing = NO;
[self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:nil]];
}
[self sendAction:[self action] to:[self target]];
[self selectText:nil];
[[[self window] platformWindow] _propagateCurrentDOMEvent:NO];
}
- (void)insertNewlineIgnoringFieldEditor:(id)sender
{
var oldValue = [self stringValue];
[self _inputElement].value += CPNewlineCharacter;
[self _setStringValue:[self _inputElement].value];
if (oldValue !== [self stringValue])
{
if (!_isEditing)
{
_isEditing = YES;
[self textDidBeginEditing:[CPNotification notificationWithName:CPControlTextDidBeginEditingNotification object:self userInfo:nil]];
}
[self textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:self userInfo:nil]];
}
}
- (void)insertTabIgnoringFieldEditor:(id)sender
{
var oldValue = [self stringValue];
[self _inputElement].value += CPTabCharacter;
[self _setStringValue:[self _inputElement].value];
if (oldValue !== [self stringValue])
{
if (!_isEditing)
{
_isEditing = YES;
[self textDidBeginEditing:[CPNotification notificationWithName:CPControlTextDidBeginEditingNotification object:self userInfo:nil]];
}
[self textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:self userInfo:nil]];
}
}
- (void)textDidBlur:(CPNotification)note
{
// this looks to prevent false propagation of notifications for other objects
@@ -709,11 +800,19 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
[[CPNotificationCenter defaultCenter] postNotification:note];
}
- (void)textDidChange:(CPNotification)note
{
if ([note object] !== self)
return;
[self _continuouslyReverseSetBinding];
[super textDidChange:note];
}
- (void)sendAction:(SEL)anAction to:(id)anObject
{
// Don't reverse set our empty value
if (!_currentValueIsPlaceholder)
[self _reverseSetBinding];
[self _reverseSetBinding];
[CPApp sendAction:anAction to:anObject from:self];
}
@@ -728,6 +827,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
/*
@ignore
Sets the internal string value without updating the value in the input element
*/
- (void)_setStringValue:(id)aValue
{
@@ -787,34 +887,6 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
return _placeholderString;
}
- (void)_setCurrentValueIsPlaceholder:(BOOL)isPlaceholder
{
// The initial _currentValueIsPlaceholder is null so convert it to NO for comparison purposes.
if (!!_currentValueIsPlaceholder === isPlaceholder)
return;
if (isPlaceholder)
{
// Save the original placeholder value so we can restore it later
// Only do this if the placeholder is not already overridden because the bindings logic might call this method
// several times and we don't want the bindings placeholder to ever become the original placeholder
if (!_currentValueIsPlaceholder)
_originalPlaceholderString = [self placeholderString];
// Set the current string value as the current placeholder and clear the string value
[self setPlaceholderString:[self stringValue]];
[self setStringValue:@""];
}
else
{
// Restore the original placeholder, the actual textfield value is already correct
// because it was set using setValue:forKey:
[self setPlaceholderString:_originalPlaceholderString];
}
_currentValueIsPlaceholder = isPlaceholder;
}
/*!
For non-bezeled text fields (typically a label), sizeToFit has two behaviors, depending
on the line break mode of the receiver.
@@ -885,21 +957,28 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
}
/*!
Select all the text in the CPTextField.
Make the receiver the first responder and select all the text in the field.
*/
- (void)selectText:(id)sender
{
#if PLATFORM(DOM)
var element = [self _inputElement];
// FIXME Should this really make the text field the first responder?
if (([self isEditable] || [self isSelectable]))
{
#if PLATFORM(DOM)
var element = [self _inputElement];
if ([[self window] firstResponder] === self)
window.setTimeout(function() { element.select(); }, 0);
else if ([self window] !== nil && [[self window] makeFirstResponder:self])
window.setTimeout(function() {[self selectText:sender];}, 0);
}
#else
// Even if we can't actually select the text we need to preserve the first
// responder side effect.
if ([self window] !== nil && [[self window] firstResponder] !== self)
[[self window] makeFirstResponder:self];
#endif
}
}
- (void)copy:(id)sender
@@ -927,6 +1006,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
@@ -948,6 +1029,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
[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
@@ -981,7 +1064,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
// fall through to the return
}
return CGMakeRange(0, 0);
return CPMakeRange(0, 0);
}
- (void)setSelectedRange:(CPRange)aRange
@@ -1026,8 +1109,15 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
- (void)deleteBackward:(id)sender
{
var selectedRange = [self selectedRange],
stringValue = [self stringValue],
var selectedRange = [self selectedRange];
if (selectedRange.length < 2)
return;
selectedRange.location += 1;
selectedRange.length -= 1;
var stringValue = [self stringValue],
newValue = [stringValue stringByReplacingCharactersInRange:selectedRange withString:""];
[self setStringValue:newValue];
@@ -1262,18 +1352,6 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
[self setAlignment:[aCoder decodeIntForKey:CPTextFieldAlignmentKey]];
[self setPlaceholderString:[aCoder decodeObjectForKey:CPTextFieldPlaceholderStringKey]];
// Make sure the frame is big enough
var minSize = [self _minimumFrameSize];
minSize.width = MAX(CGRectGetWidth([self frame]), minSize.width);
minSize.height = MAX(CGRectGetHeight([self frame]), minSize.height);
// Only size multiline bezeled textfields if it's to small to fit the content
if ([self isBezeled])
if ([self lineBreakMode] === CPLineBreakByCharWrapping || [self lineBreakMode] == CPLineBreakByWordWrapping)
minSize.height = MAX(CGRectGetHeight([self frame]), minSize.height);
[self setFrameSize:minSize];
}
return self;
@@ -1302,3 +1380,52 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
@end
@implementation _CPTextFieldValueBinder : CPBinder
{
}
- (void)setValueFor:(CPString)theBinding
{
var destination = [_info objectForKey:CPObservedObjectKey],
keyPath = [_info objectForKey:CPObservedKeyPathKey],
options = [_info objectForKey:CPOptionsKey],
newValue = [destination valueForKeyPath:keyPath],
isPlaceholder = CPIsControllerMarker(newValue);
if (isPlaceholder)
{
switch (newValue)
{
case CPMultipleValuesMarker:
newValue = [options objectForKey:CPMultipleValuesPlaceholderBindingOption] || @"Multiple Values";
break;
case CPNoSelectionMarker:
newValue = [options objectForKey:CPNoSelectionPlaceholderBindingOption] || @"No Selection";
break;
case CPNotApplicableMarker:
if ([options objectForKey:CPRaisesForNotApplicableKeysBindingOption])
[CPException raise:CPGenericException
reason:@"can't transform non applicable key on: "+_source+" value: "+newValue];
newValue = [options objectForKey:CPNotApplicablePlaceholderBindingOption] || @"Not Applicable";
break;
case CPNullMarker:
newValue = [options objectForKey:CPNullPlaceholderBindingOption] || @"";
break;
}
[_source setPlaceholderString:newValue];
[_source setObjectValue:nil];
}
else
{
newValue = [self transformValue:newValue withOptions:options];
[_source setObjectValue:newValue];
}
}
@end
+58 -9
View File
@@ -25,9 +25,10 @@
@import <Foundation/CPKeyedUnarchiver.j>
var CPThemesByName = { },
CPThemeDefaultTheme = nil,
CPThemeDefaultHudTheme = nil;
var CPThemesByName = { },
CPThemeNamesByInheritance = [],
CPThemeDefaultTheme = nil,
CPThemeDefaultHudTheme = nil;
/*!
@@ -76,6 +77,52 @@ var CPThemesByName = { },
return CPThemesByName[aName];
}
/*!
Returns an array of names of all loaded themes, in the order they were loaded.
*/
+ (CPArray)allThemeNames
{
return [CPThemeNamesByInheritance copy];
}
/*!
Returns the closest matching theme for a given view or view class.
The matching proceeds as follows:
- The default theme class name for the class is retrieved.
- Starting with the last loaded theme and proceeding towards the default theme,
each theme is checked to see if it defines that theme class.
- If the theme defines the class name, that theme is returned.
- If no themes match, the default theme is returned.
@param aViewOrClass The view or view class to match with a theme
@return The first matching theme
*/
+ (CPTheme)themeForView:(id)aViewOrClass
{
var themeClass = nil;
if (class_isMetaClass(aViewOrClass.isa))
themeClass = [aViewOrClass defaultThemeClass];
else
themeClass = [aViewOrClass themeClass];
if (themeClass)
{
var count = CPThemeNamesByInheritance.length;
while (count--)
{
var theme = CPThemesByName[CPThemeNamesByInheritance[count]];
if ([theme._attributes containsKey:themeClass])
return theme;
}
}
return CPThemeDefaultTheme;
}
- (id)initWithName:(CPString)aName
{
self = [super init];
@@ -86,6 +133,9 @@ var CPThemesByName = { },
_attributes = [CPDictionary dictionary];
CPThemesByName[_name] = self;
if (![CPThemeNamesByInheritance containsObject:_name])
CPThemeNamesByInheritance.push(_name);
}
return self;
@@ -299,6 +349,9 @@ var CPThemeNameKey = @"CPThemeNameKey",
_attributes = [aCoder decodeObjectForKey:CPThemeAttributesKey];
CPThemesByName[_name] = self;
if (![CPThemeNamesByInheritance containsObject:_name])
CPThemeNamesByInheritance.push(_name);
}
return self;
@@ -405,6 +458,7 @@ function CPThemeStateName(aState)
CPThemeStateNames[0] = "normal";
CPThemeStateNormal = CPThemeStates["normal"] = 0;
CPThemeStateDisabled = CPThemeState("disabled");
CPThemeStateHovered = CPThemeState("hovered");
CPThemeStateHighlighted = CPThemeState("highlighted");
CPThemeStateSelected = CPThemeState("selected");
CPThemeStateTableDataView = CPThemeState("tableDataView");
@@ -465,12 +519,7 @@ CPThemeStateCircular = CPThemeState("circular");
- (void)setValue:(id)aValue
{
_cache = {};
if (aValue === undefined || aValue === nil)
_values = [CPDictionary dictionary];
else
_values = [CPDictionary dictionaryWithObject:aValue forKey:String(CPThemeStateNormal)];
[self setValue:aValue forState:CPThemeStateNormal];
}
- (void)setValue:(id)aValue forState:(CPThemeState)aState
+60 -16
View File
@@ -27,6 +27,7 @@
@import "CPButton.j"
@import "CPScrollView.j"
@import "CPTextField.j"
@import "CPTableView.j"
@import "CPWindow.j"
@import "_CPMenuWindow.j"
@@ -79,6 +80,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
CPEvent _mouseDownEvent;
BOOL _preventResign;
BOOL _shouldNotifyTarget;
}
+ (CPCharacterSet)defaultTokenizingCharacterSet
@@ -177,7 +179,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
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 fallback to the normal behavior, resigning first responder or select the next or previous key view
if (!token || token === @"")
{
if (DOMEvent && DOMEvent.keyCode === CPTabKeyCode)
@@ -196,7 +198,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
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];
@@ -208,10 +210,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
[self _inputElement].value = @"";
[self setNeedsLayout];
var theBinding = [CPKeyValueBinding getBinding:CPValueBinding forObject:self];
if (theBinding)
[theBinding reverseSetValueFor:@"objectValue"];
[self _controlTextDidChange];
}
- (void)_autocomplete
@@ -265,12 +264,15 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
- (void)_controlTextDidChange
{
var theBinding = [CPKeyValueBinding getBinding:CPValueBinding forObject:self];
var binderClass = [[self class] _binderClassForBinding:CPValueBinding],
theBinding = [binderClass getBinding:CPValueBinding forObject:self];
if (theBinding)
[theBinding reverseSetValueFor:@"objectValue"];
[self textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:self userInfo:nil]];
_shouldNotifyTarget = YES;
}
- (void)_removeSelectedTokens:(id)sender
@@ -401,7 +403,14 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
[self setNeedsLayout];
[self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidBeginEditingNotification object:self userInfo:nil]];
if (_shouldNotifyTarget)
{
_shouldNotifyTarget = NO;
[self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:nil]];
if ([self sendsActionOnEndEditing])
[self sendAction:[self action] to:[self target]];
}
return YES;
}
@@ -446,7 +455,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];
}
@@ -465,7 +474,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
if ([token isKindOfClass:[CPString class]])
continue;
[objectValue addObject:[token stringValue]];
[objectValue addObject:[token representedObject]];
}
#if PLATFORM(DOM)
@@ -501,13 +510,14 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
for (var i = 0, count = [aValue count]; i < count; i++)
{
// Do we have this token among the old ones?
var tokenValue = aValue[i],
var tokenObject = aValue[i],
tokenValue = [self tokenField:self displayStringForRepresentedObject:tokenObject],
newToken = nil;
for (var j = 0, oldCount = [oldTokens count]; j < oldCount; j++)
{
var oldToken = oldTokens[j];
if ([oldToken stringValue] == tokenValue)
if ([oldToken representedObject] == tokenObject)
{
// Yep. Reuse it.
[oldTokens removeObjectAtIndex:j];
@@ -520,6 +530,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
{
newToken = [[_CPTokenFieldToken alloc] init];
[newToken setTokenField:self];
[newToken setRepresentedObject:tokenObject];
[newToken setStringValue:tokenValue];
[contentView addSubview:newToken];
}
@@ -552,6 +563,12 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
[self setNeedsDisplay:YES];
}
- (void)sendAction:(SEL)anAction to:(id)anObject
{
_shouldNotifyTarget = NO;
[super sendAction:anAction to:anObject];
}
// Incredible hack to disable supers implementation
// so it cannot change our object value and break the tokenfield
- (void)_setStringValue:(id)aValue
@@ -616,7 +633,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)
@@ -648,7 +665,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)
@@ -1074,7 +1091,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
- (void)tableView:(CPTableView)tableView objectValueForTableColumn:(CPTableColumn)tableColumn row:(int)row
{
return [_cachedCompletions objectAtIndex:row];
return [self tokenField:self displayStringForRepresentedObject:[_cachedCompletions objectAtIndex:row]];
}
- (void)tableViewSelectionDidChange:(CPNotification)notification
@@ -1111,6 +1128,23 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
return [];
}
// // 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
{
if ([[self delegate] respondsToSelector:@selector(tokenField:displayStringForRepresentedObject:)])
{
var stringForRepresentedObject = [[self delegate] tokenField:tokenField displayStringForRepresentedObject:representedObject];
if (stringForRepresentedObject !== nil)
{
return stringForRepresentedObject;
}
}
return representedObject;
}
//
// // return an array of represented objects you want to add.
// // If you want to reject the add, return an empty array.
@@ -1119,7 +1153,6 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
//
// // If you return nil or don't implement these delegate methods, we will assume
// // editing string = display string = represented object
// - (NSString *)tokenField:(NSTokenField *)tokenField displayStringForRepresentedObject:(id)representedObject;
// - (NSString *)tokenField:(NSTokenField *)tokenField editingStringForRepresentedObject:(id)representedObject;
// - (id)tokenField:(NSTokenField *)tokenField representedObjectForEditingString: (NSString *)editingString;
//
@@ -1143,6 +1176,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
{
_CPTokenFieldTokenCloseButton _deleteButton;
CPTokenField _tokenField;
id _representedObject;
}
+ (CPString)defaultThemeClass
@@ -1175,6 +1209,16 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
_tokenField = tokenField;
}
- (id)representedObject
{
return _representedObject;
}
- (void)setRepresentedObject:(id)representedObject
{
_representedObject = representedObject;
}
- (CGSize)_minimumFrameSize
{
var size = CGSizeMakeZero(),
+23 -6
View File
@@ -50,8 +50,8 @@ CPToolbarDisplayModeIconOnly = 2;
*/
CPToolbarDisplayModeLabelOnly = 3;
var CPToolbarsByIdentifier = nil;
var CPToolbarConfigurationsByIdentifier = nil;
var CPToolbarsByIdentifier = nil,
CPToolbarConfigurationsByIdentifier = nil;
/*!
@ingroup appkit
@@ -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?
@@ -667,7 +667,7 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
// Determine all the items that have flexible width.
// Also determine the height of the toolbar.
var count = _visibleItems.length
var count = _visibleItems.length,
flexibleItemIndexes = [CPIndexSet indexSet];
while (count--)
@@ -799,10 +799,11 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
hasNonSeparatorItem = YES;
var menuItem = [[CPMenuItem alloc] initWithTitle:[item label] action:[item action] keyEquivalent:nil];
var menuItem = [[CPMenuItem alloc] initWithTitle:[item label] action:@selector(didSelectMenuItem:) keyEquivalent:nil];
[menuItem setRepresentedObject:item];
[menuItem setImage:[item image]];
[menuItem setTarget:[item target]];
[menuItem setTarget:self];
[menuItem setEnabled:[item isEnabled]];
[_additionalItemsButton addItem:menuItem];
@@ -812,6 +813,18 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
[_additionalItemsButton removeFromSuperview];
}
/*
Used privately.
@ignore
*/
- (void)didSelectMenuItem:(id)aSender
{
var toolbarItem = [aSender representedObject];
[CPApp sendAction:[toolbarItem action] to:[toolbarItem target] from:toolbarItem];
}
- (void)reloadToolbarItems
{
// Get rid of all our current subviews.
@@ -836,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;
+36 -36
View File
@@ -40,7 +40,7 @@ CPToolbarShowFontsItemIdentifier = @"CPToolbarShowFontsItem";
CPToolbarCustomizeToolbarItemIdentifier = @"CPToolbarCustomizeToolbarItem";
CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
/*!
/*!
@ingroup appkit
@class CPToolbarItem
@@ -49,9 +49,9 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
@implementation CPToolbarItem : CPObject
{
CPString _itemIdentifier;
CPToolbar _toolbar;
CPString _label;
CPString _paletteLabel;
CPString _toolTip;
@@ -61,12 +61,12 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
BOOL _isEnabled;
CPImage _image;
CPImage _alternateImage;
CPView _view;
CGSize _minSize;
CGSize _maxSize;
CGSize _maxSize;
int _visibilityPriority;
BOOL _autovalidates;
@@ -86,21 +86,21 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
- (id)initWithItemIdentifier:(CPString)anItemIdentifier
{
self = [super init];
if (self)
{
_itemIdentifier = anItemIdentifier;
_tag = 0;
_isEnabled = YES;
_minSize = CGSizeMakeZero();
_maxSize = CGSizeMakeZero();
_visibilityPriority = CPToolbarItemVisibilityPriorityStandard;
_autovalidates = YES;
}
return self;
}
@@ -170,7 +170,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
{
if ([_view respondsToSelector:@selector(toolTip)])
return [_view toolTip];
return _toolTip;
}
@@ -182,7 +182,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
{
if ([_view respondsToSelector:@selector(setToolTip:)])
[_view setToolTip:aToolTip];
_toolTip = aToolTip;
}
@@ -193,7 +193,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
{
if ([_view respondsToSelector:@selector(tag)])
return [_view tag];
return _tag;
}
@@ -205,7 +205,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
{
if ([_view respondsToSelector:@selector(setTag:)])
[_view setTag:aTag];
_tag = aTag;
}
@@ -216,12 +216,12 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
{
if (_view)
return [_view respondsToSelector:@selector(target)] ? [_view target] : nil;
return _target;
}
/*!
Sets the target of the action that is triggered when the user clicks this item. \c nil will cause
Sets the target of the action that is triggered when the user clicks this item. \c nil will cause
the action to be passed on to the first responder.
@param aTarget the new target
*/
@@ -229,7 +229,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
{
if (!_view)
_target = aTarget;
else if ([_view respondsToSelector:@selector(setTarget:)])
[_view setTarget:aTarget];
}
@@ -241,7 +241,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
{
if (_view)
return [_view respondsToSelector:@selector(action)] ? [_view action] : nil;
return _action;
}
@@ -265,7 +265,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
{
if ([_view respondsToSelector:@selector(isEnabled)])
return [_view isEnabled];
return _isEnabled;
}
@@ -277,7 +277,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
{
if ([_view respondsToSelector:@selector(setEnabled:)])
[_view setEnabled:shouldBeEnabled];
_isEnabled = shouldBeEnabled;
}
@@ -288,7 +288,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
{
if ([_view respondsToSelector:@selector(image)])
return [_view image];
return _image;
}
@@ -302,11 +302,11 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
[_view setImage:anImage];
_image = anImage;
if (!_image)
return;
if (_minSize.width === 0 && _minSize.height === 0 &&
if (_minSize.width === 0 && _minSize.height === 0 &&
_maxSize.width === 0 && _maxSize.height === 0)
{
var imageSize = [_image size];
@@ -327,7 +327,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
{
if ([_view respondsToSelector:@selector(setAlternateImage:)])
[_view setAlternateImage:anImage];
_alternateImage = anImage;
}
@@ -338,7 +338,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
{
if ([_view respondsToSelector:@selector(alternateIamge)])
return [_view alternateImage];
return _alternateImage;
}
@@ -358,7 +358,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
{
if (_view == aView)
return;
_view = aView;
if (_view)
@@ -366,7 +366,7 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
// Tags get forwarded.
if (_tag !== 0 && [_view respondsToSelector:@selector(setTag:)])
[_view setTag:_tag];
_target = nil;
_action = nil;
}
@@ -386,11 +386,11 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
*/
- (void)setMinSize:(CGSize)aMinSize
{
if(!aMinSize.height || !aMinSize.width)
if (!aMinSize.height || !aMinSize.width)
return;
_minSize = CGSizeMakeCopy(aMinSize);
// Try to provide some sanity: Make maxSize >= minSize
_maxSize = CGSizeMake(MAX(_minSize.width, _maxSize.width), MAX(_minSize.height, _maxSize.height));
}
@@ -409,11 +409,11 @@ CPToolbarPrintItemIdentifier = @"CPToolbarPrintItem";
*/
- (void)setMaxSize:(CGSize)aMaxSize
{
if(!aMaxSize.height || !aMaxSize.width)
if (!aMaxSize.height || !aMaxSize.width)
return;
_maxSize = CGSizeMakeCopy(aMaxSize);
// Try to provide some sanity: Make minSize <= maxSize
_minSize = CGSizeMake(MIN(_minSize.width, _maxSize.width), MIN(_minSize.height, _maxSize.height));
}
@@ -623,7 +623,7 @@ var CPToolbarItemItemIdentifierKey = @"CPToolbarItemItemIdentifierKey",
case CPToolbarCustomizeToolbarItemIdentifier: return nil;
case CPToolbarPrintItemIdentifier: return nil;
}
return nil;
}
+9 -193
View File
@@ -1,11 +1,12 @@
@import <Foundation/CPObject.j>
@import <Foundation/CPIndexPath.j>
@implementation CPTreeNode : CPObject
{
id _representedObject @accessors(readonly, property=representedObject);
CPTreeNode _parentNode @accessors(readonly, property=parentNode);
CPMutableArray _childNodes;
}
@@ -87,38 +88,16 @@
[_childNodes[count] sortWithSortDescriptors:sortDescriptors recursively:YES];
}
- (CPEnumerator)preOrder
- (CPTreeNode)descendantNodeAtIndexPath:(CPIndexPath)indexPath
{
return [_CPTreeNodeEnumerator enumeratorWithTreeNode:self order:_CPTreeNodeEnumeratorPreOrder];
}
var index = 0,
count = [indexPath length],
node = self;
- (CPEnumerator)inOrder
{
return [_CPTreeNodeEnumerator enumeratorWithTreeNode:self order:_CPTreeNodeEnumeratorInOrder];
}
for (; index < count; ++index)
node = [node objectInChildNodesAtIndex:[indexPath indexAtPosition:index]];
- (CPEnumerator)postOrder
{
return [_CPTreeNodeEnumerator enumeratorWithTreeNode:self order:_CPTreeNodeEnumeratorPostOrder];
}
- (CPEnumerator)levelOrder
{
return [_CPTreeNodeEnumerator enumeratorWithTreeNode:self order:_CPTreeNodeEnumeratorLevelOrder];
}
- (int)countByEnumeratingWithState:(id)aState objects:(id)objects count:(id)aCount
{
if (aState.state !== 0)
return 0;
// FIXME: Change this to inorder when implemented?
var count = [[self preOrder] countByEnumeratingWithState:aState objects:objects count:aCount];
// Dangerous?
aState.state = YES;
return count;
return node;
}
@end
@@ -151,166 +130,3 @@ var CPTreeNodeRepresentedObjectKey = @"CPTreeNodeRepresentedObjectKey",
}
@end
var _CPTreeNodeEnumeratorPreOrder = 0,
_CPTreeNodeEnumeratorInOrder = 1,
_CPTreeNodeEnumeratorPostOrder = 2,
_CPTreeNodeEnumeratorLevelOrder = 3;
@implementation _CPTreeNodeEnumerator : CPEnumerator
{
int _order;
Object _state;
CPTreeNode _treeNode;
}
+ (_CPTreeNodeEnumerator)enumeratorWithTreeNode:(CPTreeNode)aTreeNode order:(int)anOrder
{
return [[self alloc] initWithTreeNode:aTreeNode order:anOrder];
}
- (id)initWithTreeNode:(CPTreeNode)aTreeNode order:(int)anOrder
{
self = [super init];
if (self)
{
_order = anOrder
_state = [self _newState];
_treeNode = aTreeNode;
}
return self;
}
- (id)_newState
{
return { stack:[_treeNode], visited:[CPSet set] };
}
- (id)_preOrderFromState:(Object)state allObjects:(BOOL)shouldReturnAllObjects
{
var stack = state.stack;
if (stack.length <= 0)
return nil;
if (shouldReturnAllObjects)
var allObjects = [];
while (stack.length)
{
var currentNode = stack.pop(),
childNodes = currentNode._childNodes,
count = childNodes.length;
while (count--)
stack.push(childNodes[count]);
if (shouldReturnAllObjects)
allObjects.push(currentNode);
else
return currentNode;
}
return allObjects;
}
- (id)_inOrderFromState:(Object)state allObjects:(BOOL)shouldReturnAllObjects
{
// Implement.
}
- (id)_postOrderFromState:(Object)state allObjects:(BOOL)shouldReturnAllObjects
{
var stack = state.stack;
if (stack.length <= 0)
return nil;
var visited = state.visited;
if (shouldReturnAllObjects)
var allObjects = [];
while (stack.length)
{
var currentNode = [stack lastObject],
childNodes = currentNode._childNodes,
originalCount = stack.length,
count = childNodes.length;
while (count--)
{
var treeNode = childNodes[count];
if ([visited containsObject:treeNode])
continue;
else
stack.push(treeNode);
}
if (originalCount === stack.length)
{
[visited addObject:currentNode];
if (shouldReturnAllObjects)
allObjects.push(stack.pop());
else
return stack.pop();
}
}
return allObjects;
}
- (id)_levelOrderFromState:(Object)state allObjects:(BOOL)shouldReturnAllObjects
{
// Implement.
}
- (id)nextObject
{
if (_order === _CPTreeNodeEnumeratorPreOrder)
return [self _preOrderFromState:[self _newState] allObjects:NO];
else if (_order === _CPTreeNodeEnumeratorInOrder)
return [self _inOrderFromState:[self _newState] allObjects:NO];
else if (_order === _CPTreeNodeEnumeratorPostOrder)
return [self _postOrderFromState:[self _newState] allObjects:NO];
//else if (_order === _CPTreeNodeEnumeratorLevelOrder)
return [self _levelOrderFromState:[self _newState] allObjects:NO];
}
- (CPArray)allObjects
{
if (_order === _CPTreeNodeEnumeratorPreOrder)
return [self _preOrderFromState:[self _newState] allObjects:YES];
else if (_order === _CPTreeNodeEnumeratorInOrder)
return [self _inOrderFromState:[self _newState] allObjects:YES];
else if (_order === _CPTreeNodeEnumeratorPostOrder)
return [self _postOrderFromState:[self _newState] allObjects:YES];
//else if (_order === _CPTreeNodeEnumeratorLevelOrder)
return [self _levelOrderFromState:[self _newState] allObjects:NO];
}
- (int)countByEnumeratingWithState:(id)aState objects:(id)objects count:(id)aCount
{
if (aState.state !== 0)
return 0;
var count = [[self allObjects] countByEnumeratingWithState:aState objects:objects count:aCount];
// Dangerous?
aState.state = YES;
return count;
}
@end
+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
+115 -15
View File
@@ -186,6 +186,9 @@ var CPViewFlags = { },
CPView _previousKeyView;
unsigned _viewClassFlags;
// ToolTips
CPString _toolTip @accessors(property=toolTip);
}
/*
@@ -292,7 +295,7 @@ var CPViewFlags = { },
_DOMImageSizes = [];
#endif
_theme = [CPTheme defaultTheme];
_theme = [CPTheme themeForView:self];
_themeState = CPThemeStateNormal;
[self setupViewFlags];
@@ -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
@@ -1566,6 +1577,16 @@ var CPViewFlags = { },
return CGPointApplyAffineTransform(aPoint, _CPViewGetTransform(aView, self));
}
/*!
Converts the point from the base coordinate system to the receivers coordinate system.
@param aPoint A point specifying a location in the base coordinate system
@return The point converted to the receivers base coordinate system
*/
- (CGPoint)convertPointFromBase:(CGPoint)aPoint
{
return CGPointApplyAffineTransform(aPoint, _CPViewGetTransform(nil, self));
}
/*!
Converts \c aPoint from the receiver's coordinate space to the coordinate space of \c aView.
@param aPoint the point to convert
@@ -1577,6 +1598,16 @@ var CPViewFlags = { },
return CGPointApplyAffineTransform(aPoint, _CPViewGetTransform(self, aView));
}
/*!
Converts the point from the receivers coordinate system to the base coordinate system.
@param aPoint A point specifying a location in the coordinate system of the receiver
@return The point converted to the base coordinate system
*/
- (CGPoint)convertPointToBase:(CGPoint)aPoint
{
return CGPointApplyAffineTransform(aPoint, _CPViewGetTransform(self, nil));
}
/*!
Convert's \c aSize from \c aView's coordinate space to the receiver's coordinate space.
@param aSize the size to convert
@@ -1610,6 +1641,16 @@ var CPViewFlags = { },
return CGRectApplyAffineTransform(aRect, _CPViewGetTransform(aView, self));
}
/*!
Converts the rectangle from the base coordinate system to the receivers coordinate system.
@param aRect A rectangle specifying a location in the base coordinate system
@return The rectangle converted to the receivers base coordinate system
*/
- (CGRect)convertRectFromBase:(CGRect)aRect
{
return CGRectApplyAffineTransform(aRect, _CPViewGetTransform(nil, self));
}
/*!
Converts \c aRect from the receiver's coordinate space to \c aView's coordinate space.
@param aRect the rectangle to convert
@@ -1621,6 +1662,16 @@ var CPViewFlags = { },
return CGRectApplyAffineTransform(aRect, _CPViewGetTransform(self, aView));
}
/*!
Converts the rectangle from the receivers coordinate system to the base coordinate system.
@param aRect A rectangle specifying a location in the coordinate system of the receiver
@return The rectangle converted to the base coordinate system
*/
- (CGRect)convertRectToBase:(CGRect)aRect
{
return CGRectApplyAffineTransform(aRect, _CPViewGetTransform(self, nil));
}
/*!
Sets whether the receiver posts a CPViewFrameDidChangeNotification notification
to the default notification center when its frame is changed. The default is \c NO.
@@ -1695,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
*/
@@ -1710,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
*/
@@ -2060,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
@@ -2081,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];
@@ -2105,11 +2170,18 @@ setBoundsOrigin:
- (CPView)nextValidKeyView
{
var result = [self nextKeyView];
var result = [self nextKeyView],
firstResult = result;
while (result && ![result canBecomeKeyView])
{
result = [result nextKeyView];
// Cycled.
if (result === firstResult)
return nil;
}
return result;
}
@@ -2120,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
@@ -2213,6 +2300,10 @@ setBoundsOrigin:
- (BOOL)hasThemeState:(CPThemeState)aState
{
// Because CPThemeStateNormal is defined as 0 we need to check for it explicitly here
if (aState === CPThemeStateNormal && _themeState === CPThemeStateNormal)
return YES;
return !!(_themeState & ((typeof aState === "string") ? CPThemeState(aState) : aState));
}
@@ -2447,6 +2538,11 @@ setBoundsOrigin:
return [_themeAttributes[aName] valueForState:_themeState];
}
- (BOOL)hasThemeAttribute:(CPString)aName
{
return (_themeAttributes && _themeAttributes[aName] !== undefined);
}
- (CPView)createEphemeralSubviewNamed:(CPString)aViewName
{
return nil;
@@ -2469,7 +2565,7 @@ setBoundsOrigin:
var frame = [self rectForEphemeralSubviewNamed:aViewName];
if (frame && !_CGRectIsEmpty(frame))
if (frame)
{
if (!_ephemeralSubviewsForNames[aViewName])
{
@@ -2558,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];
@@ -2595,7 +2695,7 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
[self setupViewFlags];
_theme = [CPTheme defaultTheme];
_theme = [CPTheme themeForView:self];
_themeClass = [aCoder decodeObjectForKey:CPViewThemeClassKey];
_themeState = CPThemeState([aCoder decodeIntForKey:CPViewThemeStateKey]);
_themeAttributes = {};
@@ -2676,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];
+57 -9
View File
@@ -23,19 +23,49 @@
@import "CPAnimation.j"
CPViewAnimationTargetKey = @"CPViewAnimationTarget";
CPViewAnimationStartFrameKey = @"CPViewAnimationStartFrame";
CPViewAnimationEndFrameKey = @"CPViewAnimationEndFrame";
CPViewAnimationEffectKey = @"CPViewAnimationEffect";
CPViewAnimationTargetKey = @"CPViewAnimationTargetKey";
CPViewAnimationStartFrameKey = @"CPViewAnimationStartFrameKey";
CPViewAnimationEndFrameKey = @"CPViewAnimationEndFrameKey";
CPViewAnimationEffectKey = @"CPViewAnimationEffectKey";
CPViewAnimationFadeInEffect = @"CPViewAnimationFadeIn";
CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut";
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])
@@ -61,7 +91,7 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut";
if (effect === CPViewAnimationFadeInEffect)
{
[view setAlphaValue:0.0];
[view setHidden:NO];
[self _targetView:view setHidden:NO];
}
else if (effect === CPViewAnimationFadeOutEffect)
[view setAlphaValue:1.0];
@@ -104,7 +134,7 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut";
[view setAlphaValue:1.0 + ( 0.0 - 1.0 ) * progress];
if (progress === 1.0)
[view setHidden:_CGRectIsNull(endFrame) || [view alphaValue] === 0.0];
[self _targetView:view setHidden:_CGRectIsNull(endFrame) || [view alphaValue] === 0.0];
}
}
@@ -125,12 +155,25 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut";
else if (effect === CPViewAnimationFadeOutEffect)
[view setAlphaValue:0.0];
[view setHidden:_CGRectIsNull(endFrame) || [view alphaValue] === 0.0];
[self _targetView:view setHidden:_CGRectIsNull(endFrame) || [view alphaValue] === 0.0];
}
[super stopAnimation];
}
- (void)_targetView:(id)theView setHidden:(BOOL)isHidden
{
if ([theView isKindOfClass:[CPWindow class]])
{
if (isHidden)
[theView orderOut:self];
else
[theView orderFront:self];
}
else
[theView setHidden:isHidden];
}
- (id)_targetView:(CPDictionary)dictionary
{
var targetView = [dictionary valueForKey:CPViewAnimationTargetKey];
@@ -168,6 +211,11 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOut";
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)
+62 -34
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
{
@@ -163,7 +186,7 @@ var CPViewControllerCachedCibs;
if (_view === nil && [cibOwner isKindOfClass:[CPDocument class]])
[self setView:[cibOwner valueForKey:@"view"]];
if (!_view)
if (!_view)
{
var reason = [CPString stringWithFormat:@"View for %@ could not be loaded from Cib or no view specified. Override loadView to load the view manually.", self];
@@ -182,19 +205,24 @@ 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 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.
*/
- (void)viewDidLoad
{
}
/*!
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.
*/
+487 -113
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];
}
@@ -107,75 +163,82 @@ CPWebViewScrollNative = 2;
_ignoreLoadEnd = YES;
_iframe = document.createElement("iframe");
_iframe.name = "iframe_" + Math.floor(Math.random()*10000);
_iframe.name = "iframe_" + FLOOR(RAND() * 10000);
_iframe.style.width = "100%";
_iframe.style.height = "100%";
_iframe.style.borderWidth = "0px";
_iframe.frameBorder = "0";
[self setDrawsBackground:YES];
[self _applyBackgroundColor];
_loadCallback = function() {
// HACK: this block handles the case where we don't know about loads initiated by the user clicking a link
if (!_ignoreLoadStart)
{
// post the start load notification
[self _startedLoading];
_loadCallback = function()
{
// HACK: this block handles the case where we don't know about loads initiated by the user clicking a link
if (!_ignoreLoadStart)
{
// post the start load notification
[self _startedLoading];
if (_mainFrameURL)
[_backwardStack addObject:_mainFrameURL];
if (_mainFrameURL)
[_backwardStack addObject:_mainFrameURL];
// FIXME: this doesn't actually get the right URL for different domains. Not possible due to browser security restrictions.
_mainFrameURL = _iframe.src;
// FIXME: this doesn't actually get the right URL for different domains. Not possible due to browser security restrictions.
_mainFrameURL = _iframe.src;
// clear the forward
[_forwardStack removeAllObjects];
}
else
[_forwardStack removeAllObjects];
}
else
_ignoreLoadStart = NO;
if (!_ignoreLoadEnd)
{
if (!_ignoreLoadEnd)
{
[self _finishedLoading];
}
else
_ignoreLoadEnd = NO;
}
else
_ignoreLoadEnd = NO;
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
}
if (_iframe.addEventListener)
_iframe.addEventListener("load", _loadCallback, false);
else if (_iframe.attachEvent)
_iframe.attachEvent("onload", _loadCallback);
}
if (_iframe.addEventListener)
_iframe.addEventListener("load", _loadCallback, false);
else if (_iframe.attachEvent)
_iframe.attachEvent("onload", _loadCallback);
_frameView = [[CPView alloc] initWithFrame:[self bounds]];
[_frameView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
[_frameView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
_scrollView = [[CPScrollView alloc] initWithFrame:[self bounds]];
[_scrollView setAutohidesScrollers:YES];
[_scrollView setAutoresizingMask:CPViewWidthSizable|CPViewHeightSizable];
[_scrollView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
[_scrollView setDocumentView:_frameView];
_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;
@@ -200,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];
@@ -276,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];
@@ -304,15 +444,12 @@ CPWebViewScrollNative = 2;
- (void)_loadMainFrameURL
{
[self _setScrollMode:CPWebViewScrollNative];
[self _startedLoading];
_ignoreLoadStart = YES;
_ignoreLoadEnd = NO;
_url = _mainFrameURL;
_html = null;
_html = nil;
[self _load];
}
@@ -321,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);
@@ -339,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);
@@ -349,6 +502,8 @@ CPWebViewScrollNative = 2;
- (void)_startedLoading
{
_isLoading = YES;
[[CPNotificationCenter defaultCenter] postNotificationName:CPWebViewProgressStartedNotification object:self];
if ([_frameLoadDelegate respondsToSelector:@selector(webView:didStartProvisionalLoadForFrame:)])
@@ -357,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)
@@ -381,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)
@@ -397,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)
@@ -413,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);
@@ -429,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];
@@ -452,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];
@@ -475,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
{
@@ -575,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])
@@ -590,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?
@@ -603,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;
@@ -624,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
*/
@@ -637,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;
@@ -651,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
@@ -662,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
+196 -96
View File
@@ -193,9 +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
];
/*!
@ingroup appkit
@@ -388,6 +403,7 @@ CPTexturedBackgroundWindowMask
_registeredDraggedTypes = [CPSet set];
_registeredDraggedTypesArray = [];
_isSheet = NO;
_acceptsMouseMovedEvents = YES;
// Set up our window number.
_windowNumber = [CPApp._windows count];
@@ -450,12 +466,26 @@ 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;
if (wasVisible)
[self orderFront:self];
}
/*!
@ignore
*/
@@ -523,6 +553,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])
@@ -563,6 +599,9 @@ CPTexturedBackgroundWindowMask
}
}
/*!
@return BOOL - YES if the CPWindow fills the browser window, otherwise NO.
*/
- (BOOL)isFullPlatformWindow
{
return _isFullPlatformWindow;
@@ -578,6 +617,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
@@ -619,7 +670,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
{
@@ -628,6 +679,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);
@@ -705,6 +763,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];
@@ -712,6 +775,7 @@ CPTexturedBackgroundWindowMask
/*!
Sets the window's frame rectangle
@param aFrame - The CGRect of the windows new frame
*/
- (void)setFrame:(CGRect)aFrame
{
@@ -937,7 +1001,7 @@ CPTexturedBackgroundWindowMask
/*!
Sets the window's minimum size. If the provided
size is the same as the current minimum size, the method simply returns.
@aSize the new minimum size for the window
@param aSize the new minimum size for the window
*/
- (void)setMinSize:(CGSize)aSize
{
@@ -1095,6 +1159,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;
@@ -1223,10 +1298,10 @@ CPTexturedBackgroundWindowMask
if (_firstResponder === aResponder)
return YES;
if(![_firstResponder resignFirstResponder])
if (![_firstResponder resignFirstResponder])
return NO;
if(!aResponder || ![aResponder acceptsFirstResponder] || ![aResponder becomeFirstResponder])
if (!aResponder || ![aResponder acceptsFirstResponder] || ![aResponder becomeFirstResponder])
{
_firstResponder = self;
@@ -1615,7 +1690,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
*/
@@ -1652,7 +1727,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
*/
@@ -1803,7 +1878,7 @@ CPTexturedBackgroundWindowMask
}
/*!
Restores a mimized window to it's original size.
Restores a minimized window to it's original size.
*/
- (void)deminiaturize:(id)sender
{
@@ -2155,7 +2230,7 @@ CPTexturedBackgroundWindowMask
aSheet._isSheet = YES;
aSheet._parentView = self;
var originx = frame.origin.x + FLOOR((frame.size.width - sheetFrame.size.width)/2),
var originx = frame.origin.x + FLOOR((frame.size.width - sheetFrame.size.width) / 2),
originy = frame.origin.y + [[self contentView] frame].origin.y,
startFrame = CGRectMake(originx, originy, sheetFrame.size.width, 0),
endFrame = CGRectMake(originx, originy, sheetFrame.size.width, sheetFrame.size.height);
@@ -2314,25 +2389,26 @@ CPTexturedBackgroundWindowMask
// Apple's documentation is inconsistent with their behavior here. According to the docs
// 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
// 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];
}
/*
@ignore
Interprets the key event for action messages and sends the action message down the responder chain
Cocoa only sends moveDown:, moveUp:, moveLeft:, moveRight:, pageUp:, pageDown: and complete: messages.
We deviate from this by sending (the default) scrollPageUp: scrollPageDown: for pageUp and pageDown keys.
@param anEvent the event to handle.
We deviate from this by sending (the default) scrollPageUp:, scrollPageDown:, scrollToBeginningOfDocument: and scrollToEndOfDocument: for pageUp, pageDown, home and end keys.
@param anEvent the event to handle.
@return YES if the key event was handled, NO if no responder handled the key event
*/
- (BOOL)_processKeyboardUIKey:(CPEvent)anEvent
{
var character = [anEvent charactersIgnoringModifiers],
uiKeys = [CPLeftArrowFunctionKey, CPRightArrowFunctionKey, CPUpArrowFunctionKey, CPDownArrowFunctionKey, CPPageUpFunctionKey, CPPageDownFunctionKey, CPEscapeFunctionKey];
var character = [anEvent charactersIgnoringModifiers];
if (![uiKeys containsObject:character])
if (![CPWindowActionMessageKeys containsObject:character])
return NO;
var selectors = [CPKeyBinding selectorsForKey:character modifierFlags:0];
@@ -2352,49 +2428,8 @@ CPTexturedBackgroundWindowMask
// The difference is that doCommandBySelector: will also send the action to the window and application delegates.
[[self firstResponder] doCommandBySelector:@selector(complete:)];
}
}
/*
@ignore
Interprets the key event for action messages and sends the action message down the responder chain
Cocoa only sends moveDown:, moveUp:, moveLeft:, moveRight:, pageUp:, pageDown: and complete: messages.
We deviate from this by sending (the default) scrollPageUp: scrollPageDown: for pageUp and pageDown keys.
@param anEvent the event to handle.
@return YES if the key event was handled, NO if no responder handled the key event
*/
- (BOOL)_processKeyboardUIKey:(CPEvent)anEvent
{
var character = [anEvent charactersIgnoringModifiers],
uiKeys = [
CPLeftArrowFunctionKey,
CPRightArrowFunctionKey,
CPUpArrowFunctionKey,
CPDownArrowFunctionKey,
CPPageUpFunctionKey,
CPPageDownFunctionKey,
CPEscapeFunctionKey
];
if (![uiKeys containsObject:character])
return NO;
var selectors = [CPKeyBinding selectorsForKey:character modifierFlags:0];
if ([selectors count] <= 0)
return NO;
if (character !== CPEscapeFunctionKey)
{
var selector = [selectors objectAtIndex:0];
return [[self firstResponder] tryToPerform:selector with:self];
}
else
{
// Cocoa sends complete: for the escape key (in stead of the default cancelOperation:)
// This is also the only action that is not sent directly to the first responder, but through doCommandBySelector.
// 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
@@ -2405,45 +2440,31 @@ CPTexturedBackgroundWindowMask
- (BOOL)_hasKeyViewLoop
{
var subviews = [];
var views = allViews(self),
index = [views count];
[self _appendSubviewsOf:_contentView toArray:subviews];
for (var i = 0, count = [subviews count]; i<count; i++)
{
if (subviews[i]._nextKeyView)
while (index--)
if ([views[index] nextKeyView])
return YES;
}
return NO;
}
- (void)recalculateKeyViewLoop
{
var subviews = [];
var views = allViews(self);
[self _appendSubviewsOf:_contentView toArray:subviews];
[views sortUsingFunction:keyViewComparator context:nil];
var keyViewOrder = [subviews sortedArrayUsingFunction:keyViewComparator context:_contentView],
count = [keyViewOrder count];
var index = 0,
count = [views count];
for (var i=0; i<count; i++)
[keyViewOrder[i] setNextKeyView:keyViewOrder[(i+1)%count]];
for (; index < count; ++index)
[views[index] setNextKeyView:views[(index + 1) % count]];
_keyViewLoopIsDirty = NO;
}
- (void)_appendSubviewsOf:(CPView)aView toArray:(CPArray)anArray
{
var subviews = [aView subviews],
count = [subviews count];
while (count--)
[self _appendSubviewsOf:subviews[count] toArray:anArray];
[anArray addObject:aView];
}
- (void)setAutorecalculatesKeyViewLoop:(BOOL)shouldRecalculate
{
if (_autorecalculatesKeyViewLoop === shouldRecalculate)
@@ -2490,16 +2511,31 @@ CPTexturedBackgroundWindowMask
[self makeFirstResponder:[aView 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)
@@ -2514,26 +2550,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];
@@ -2541,19 +2594,46 @@ CPTexturedBackgroundWindowMask
@end
var keyViewComparator = function(a, b, context)
var allViews = function(aWindow)
{
var viewBounds = [a convertRect:[a bounds] toView:nil],
otherBounds = [b convertRect:[b bounds] toView:nil];
var views = [[aWindow contentView] subviews],
index = 0;
if (CGRectGetMinY(viewBounds) < CGRectGetMinY(otherBounds))
return -1;
else if (CGRectGetMinY(viewBounds) == CGRectGetMinY(otherBounds) && CGRectGetMinX(viewBounds) < CGRectGetMinX(otherBounds))
return -1;
else if (CGRectGetMinX(viewBounds) == CGRectGetMinX(otherBounds) && CGRectGetMinX(viewBounds) == CGRectGetMinX(otherBounds))
return 0;
else
return 1;
for (; index < views.length; ++index)
views = views.concat([views[index] subviews]);
return views;
}
var keyViewComparator = function(lhs, rhs, context)
{
var lhsBounds = [lhs convertRect:[lhs bounds] toView:nil],
rhsBounds = [rhs convertRect:[rhs bounds] toView:nil],
lhsY = _CGRectGetMinY(lhsBounds),
rhsY = _CGRectGetMinY(rhsBounds),
lhsX = _CGRectGetMinX(lhsBounds),
rhsX = _CGRectGetMinX(rhsBounds),
intersectsVertically = MIN(_CGRectGetMaxY(lhsBounds), _CGRectGetMaxY(rhsBounds)) - MAX(lhsY, rhsY);
// If two views are "on the same line" (intersect vertically), then rely on the x comparison.
if (intersectsVertically > 0)
{
if (lhsX < rhsX)
return CPOrderedAscending;
if (lhsX === rhsX)
return CPOrderedSame;
return CPOrderedDescending;
}
if (lhsY < rhsY)
return CPOrderedAscending;
if (lhsY === rhsY)
return CPOrderedSame;
return CPOrderedDescending;
}
@implementation CPWindow (MenuBar)
@@ -2618,16 +2698,25 @@ var keyViewComparator = function(a, b, 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])
@@ -2638,6 +2727,9 @@ var keyViewComparator = function(a, b, 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])
@@ -2727,12 +2819,19 @@ var keyViewComparator = function(a, b, 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];
@@ -2825,6 +2924,7 @@ CPCustomWindowShadowStyle = 3;
@import "_CPWindowView.j"
@import "_CPStandardWindowView.j"
@import "_CPDocModalWindowView.j"
@import "_CPToolTipWindowView.j"
@import "_CPHUDWindowView.j"
@import "_CPBorderlessWindowView.j"
@import "_CPBorderlessBridgeWindowView.j"
@@ -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];
+15 -8
View File
@@ -6,35 +6,42 @@ var _CPStandardWindowViewBodyBackgroundColor = nil;
@implementation _CPDocModalWindowView : _CPWindowView
{
CPView _bodyView;
CPView _shadowView;
}
+ (CPColor)bodyBackgroundColor
{
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 = [[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]];
_shadowView = [[CPView alloc] initWithFrame:CGRectMake(0, 0, _CGRectGetWidth(bounds), 8)];
[_shadowView setAutoresizingMask:CPViewWidthSizable];
[_shadowView setBackgroundColor:[CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/CPWindowAttachedSheetShadow.png"] size:CGSizeMake(9,8)]]];
[self addSubview:_shadowView];
}
return self;
return self;
}
- (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
+34 -32
View File
@@ -19,9 +19,11 @@
* 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"
var _CPHUDWindowViewBackgroundColor = nil,
CPHUDCloseButtonImage = nil;
var HUD_TITLEBAR_HEIGHT = 26.0;
@@ -29,7 +31,7 @@ var HUD_TITLEBAR_HEIGHT = 26.0;
@implementation _CPHUDWindowView : _CPWindowView
{
CPView _toolbarView;
CPTextField _titleField;
CPButton _closeButton;
}
@@ -38,19 +40,19 @@ var HUD_TITLEBAR_HEIGHT = 26.0;
{
if (self != [_CPHUDWindowView class])
return;
var bundle = [CPBundle bundleForClass:self];
_CPHUDWindowViewBackgroundColor = [CPColor colorWithPatternImage:[[CPNinePartImage alloc] initWithImageSlices:
[
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground0.png"] size:CPSizeMake(7.0, 37.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground1.png"] size:CPSizeMake(1.0, 37.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground2.png"] size:CPSizeMake(7.0, 37.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground3.png"] size:CPSizeMake(7.0, 1.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground4.png"] size:CPSizeMake(2.0, 2.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground5.png"] size:CPSizeMake(7.0, 1.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground6.png"] size:CPSizeMake(7.0, 3.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground7.png"] size:CPSizeMake(1.0, 3.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/HUD/CPWindowHUDBackground8.png"] size:CPSizeMake(7.0, 3.0)]
@@ -64,7 +66,7 @@ var HUD_TITLEBAR_HEIGHT = 26.0;
{
var contentRect = CGRectMakeCopy(aFrameRect),
titleBarHeight = HUD_TITLEBAR_HEIGHT;
contentRect.origin.y += titleBarHeight;
contentRect.size.height -= titleBarHeight;
@@ -75,92 +77,92 @@ var HUD_TITLEBAR_HEIGHT = 26.0;
{
var frameRect = CGRectMakeCopy(aContentRect),
titleBarHeight = HUD_TITLEBAR_HEIGHT;
frameRect.origin.y -= titleBarHeight;
frameRect.size.height += titleBarHeight;
return frameRect;
}
- (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
{
var contentRect = [[self class] contentRectForFrameRect:aFrameRect];
if ([[[self window] toolbar] isVisible])
{
toolbarHeight = CGRectGetHeight([[self toolbarView] frame]);
contentRect.origin.y += toolbarHeight;
contentRect.size.height -= toolbarHeight;
}
return contentRect;
}
- (CGRect)frameRectForContentRect:(CGRect)aContentRect
{
var frameRect = [[self class] frameRectForContentRect:aContentRect];
if ([[[self window] toolbar] isVisible])
{
toolbarHeight = CGRectGetHeight([[self toolbarView] frame]);
frameRect.origin.y -= toolbarHeight;
frameRect.size.height += toolbarHeight;
}
return frameRect;
}
- (id)initWithFrame:(CPRect)aFrame styleMask:(unsigned)aStyleMask
{
self = [super initWithFrame:aFrame styleMask:aStyleMask];
if (self)
{
var bounds = [self bounds];
[self setBackgroundColor:_CPHUDWindowViewBackgroundColor];
_titleField = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
[_titleField setHitTests:NO];
[_titleField setFont:[CPFont systemFontOfSize:11.0]];
[_titleField setTextColor:[CPColor whiteColor]];
[_titleField setTextShadowColor:[CPColor blackColor]];
[_titleField setTextShadowOffset:CGSizeMake(0.0, 1.0)];
[_titleField setAutoresizingMask:CPViewWidthSizable];
// FIXME: Make this to CPLineBreakByTruncatingMiddle once it's implemented.
[_titleField setLineBreakMode:CPLineBreakByTruncatingTail];
[_titleField setAlignment:CPCenterTextAlignment];
[_titleField setStringValue:@"Untitled"];
[_titleField sizeToFit];
[_titleField setAutoresizingMask:CPViewWidthSizable];
[_titleField setStringValue:@""];
[_titleField setFrame:CGRectMake(20.0, 3.0, CGRectGetWidth([self bounds]) - 40.0, CGRectGetHeight([_titleField frame]))];
[self addSubview:_titleField];
if (_styleMask & CPClosableWindowMask)
{
var closeSize = [_CPHUDWindowViewCloseImage size];
_closeButton = [[CPButton alloc] initWithFrame:CGRectMake(8.0, 5.0, closeSize.width, closeSize.height)];
[_closeButton setBordered:NO];
[_closeButton setImage:_CPHUDWindowViewCloseImage];
[_closeButton setAlternateImage:_CPHUDWindowViewCloseActiveImage];
[self addSubview:_closeButton];
}
[self setResizeIndicatorOffset:CGSizeMake(5.0, 5.0)];
}
return self;
}
+44 -43
View File
@@ -20,6 +20,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPTextField.j"
@import "_CPWindowView.j"
@@ -40,7 +41,7 @@ var _CPTexturedWindowHeadGradientColor = nil,
if (!_CPTexturedWindowHeadGradientColor)
{
var bundle = [CPBundle bundleForClass:[_CPWindowView class]];
_CPTexturedWindowHeadGradientColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPWindow/Standard/CPWindowStandardTop0.png"] size:CGSizeMake(6.0, 41.0)],
@@ -50,7 +51,7 @@ var _CPTexturedWindowHeadGradientColor = nil,
isVertical:NO
]];
}
return _CPTexturedWindowHeadGradientColor;
}
@@ -58,37 +59,37 @@ var _CPTexturedWindowHeadGradientColor = nil,
{
if (!_CPTexturedWindowHeadSolidColor)
_CPTexturedWindowHeadSolidColor = [CPColor colorWithCalibratedRed:195.0 / 255.0 green:195.0 / 255.0 blue:195.0 / 255.0 alpha:1.0];
return _CPTexturedWindowHeadSolidColor;
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
var theClass = [self class],
bounds = [self bounds];
_gradientView = [[CPView alloc] initWithFrame:CGRectMake(0.0, 0.0, CGRectGetWidth(bounds), GRADIENT_HEIGHT)];
[_gradientView setBackgroundColor:[theClass gradientColor]];
[self addSubview:_gradientView];
_solidView = [[CPView alloc] initWithFrame:CGRectMake(0.0, GRADIENT_HEIGHT, CGRectGetWidth(bounds), CGRectGetHeight(bounds) - GRADIENT_HEIGHT)];
[_solidView setBackgroundColor:[theClass solidColor]];
[self addSubview:_solidView];
}
return self;
}
- (void)resizeSubviewsWithOldSize:(CGSize)aSize
{
var bounds = [self bounds];
[_gradientView setFrameSize:CGSizeMake(CGRectGetWidth(bounds), GRADIENT_HEIGHT)];
[_solidView setFrameSize:CGSizeMake(CGRectGetWidth(bounds), CGRectGetHeight(bounds) - GRADIENT_HEIGHT)];
}
@@ -105,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
@@ -114,7 +115,7 @@ var STANDARD_GRADIENT_HEIGHT = 41.0;
CPView _dividerView;
CPView _bodyView;
CPView _toolbarView;
CPTextField _titleField;
CPButton _closeButton;
CPButton _minimizeButton;
@@ -126,15 +127,15 @@ var STANDARD_GRADIENT_HEIGHT = 41.0;
{
if (!_CPStandardWindowViewBodyBackgroundColor)
_CPStandardWindowViewBodyBackgroundColor = [CPColor colorWithWhite:0.96 alpha:1.0];
return _CPStandardWindowViewBodyBackgroundColor;
return _CPStandardWindowViewBodyBackgroundColor;
}
+ (CPColor)dividerBackgroundColor
{
if (!_CPStandardWindowViewDividerBackgroundColor)
_CPStandardWindowViewDividerBackgroundColor = [CPColor colorWithCalibratedRed:125.0 / 255.0 green:125.0 / 255.0 blue:125.0 / 255.0 alpha:1.0];
return _CPStandardWindowViewDividerBackgroundColor;
}
@@ -142,7 +143,7 @@ var STANDARD_GRADIENT_HEIGHT = 41.0;
{
if (!_CPStandardWindowViewTitleBackgroundColor)
_CPStandardWindowViewTitleBackgroundColor = [CPColor colorWithCalibratedRed:44.0 / 255.0 green:44.0 / 255.0 blue:44.0 / 255.0 alpha:1.0];
return _CPStandardWindowViewTitleBackgroundColor;
}
@@ -150,7 +151,7 @@ var STANDARD_GRADIENT_HEIGHT = 41.0;
{
var contentRect = CGRectMakeCopy(aFrameRect),
titleBarHeight = [self titleBarHeight] + 1.0;
contentRect.origin.y += titleBarHeight;
contentRect.size.height -= titleBarHeight;
@@ -161,10 +162,10 @@ var STANDARD_GRADIENT_HEIGHT = 41.0;
{
var frameRect = CGRectMakeCopy(aContentRect),
titleBarHeight = [self titleBarHeight] + 1.0;
frameRect.origin.y -= titleBarHeight;
frameRect.size.height += titleBarHeight;
return frameRect;
}
@@ -177,15 +178,15 @@ var STANDARD_GRADIENT_HEIGHT = 41.0;
{
var contentRect = [[self class] contentRectForFrameRect:aFrameRect],
theToolbar = [[self window] toolbar];
if ([theToolbar isVisible])
{
toolbarHeight = CGRectGetHeight([[theToolbar _toolbarView] frame]);
contentRect.origin.y += toolbarHeight;
contentRect.size.height -= toolbarHeight;
}
return contentRect;
}
@@ -193,72 +194,72 @@ var STANDARD_GRADIENT_HEIGHT = 41.0;
{
var frameRect = [[self class] frameRectForContentRect:aContentRect],
theToolbar = [[self window] toolbar];
if ([theToolbar isVisible])
{
toolbarHeight = CGRectGetHeight([[theToolbar _toolbarView] frame]);
frameRect.origin.y -= toolbarHeight;
frameRect.size.height += toolbarHeight;
}
return frameRect;
}
- (id)initWithFrame:(CPRect)aFrame styleMask:(unsigned)aStyleMask
{
self = [super initWithFrame:aFrame styleMask:aStyleMask];
if (self)
{
var theClass = [self class],
bounds = [self bounds];
_headView = [[_CPTexturedWindowHeadView alloc] initWithFrame:CGRectMake(0.0, 0.0, CGRectGetWidth(bounds), [[self class] titleBarHeight])];
[_headView setAutoresizingMask:CPViewWidthSizable];;
[_headView setHitTests:NO];
[self addSubview:_headView];
_dividerView = [[CPView alloc] initWithFrame:CGRectMake(0.0, CGRectGetMaxY([_headView frame]), CGRectGetWidth(bounds), 1.0)];
[_dividerView setAutoresizingMask:CPViewWidthSizable];
[_dividerView setBackgroundColor:[theClass dividerBackgroundColor]];
[_dividerView setHitTests:NO];
[self addSubview:_dividerView];
var y = CGRectGetMaxY([_dividerView frame]);
_bodyView = [[CPView alloc] initWithFrame:CGRectMake(0.0, y, CGRectGetWidth(bounds), CGRectGetHeight(bounds) - y)];
[_bodyView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
[_bodyView setBackgroundColor:[theClass bodyBackgroundColor]];
[_bodyView setHitTests:NO];
[self addSubview:_bodyView];
[self setResizeIndicatorOffset:CGSizeMake(2.0, 2.0)];
_titleField = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
[_titleField setFont:[CPFont boldSystemFontOfSize:12.0]];
[_titleField setAutoresizingMask:CPViewWidthSizable];
// FIXME: Make this to CPLineBreakByTruncatingMiddle once it's implemented.
[_titleField setLineBreakMode:CPLineBreakByTruncatingTail];
[_titleField setAlignment:CPCenterTextAlignment];
[_titleField setTextShadowColor:[CPColor whiteColor]];
[_titleField setTextShadowOffset:CGSizeMake(0.0, 1.0)];
[_titleField setStringValue:@"Untitled"];
[_titleField sizeToFit];
[_titleField setAutoresizingMask:CPViewWidthSizable];
[_titleField setStringValue:@""];
[self addSubview:_titleField];
if (_styleMask & CPClosableWindowMask)
{
if (!_CPStandardWindowViewCloseButtonImage)
@@ -341,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
+38 -39
View File
@@ -29,15 +29,14 @@ var _CPWindowViewResizeIndicatorImage = nil;
@implementation _CPWindowView : CPView
{
unsigned _styleMask;
CPImageView _resizeIndicator;
CGSize _resizeIndicatorOffset;
CPView _toolbarView;
CGSize _toolbarOffset;
// BOOL _isAnimatingToolbar;
CGRect _resizeFrame;
CGPoint _mouseDraggedPoint;
@@ -48,7 +47,7 @@ var _CPWindowViewResizeIndicatorImage = nil;
{
if (self != [_CPWindowView class])
return;
_CPWindowViewResizeIndicatorImage = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPWindow class]] pathForResource:@"_CPWindowView/_CPWindowViewResizeIndicator.png"] size:CGSizeMake(12.0, 12.0)];
}
@@ -75,14 +74,14 @@ var _CPWindowViewResizeIndicatorImage = nil;
- (id)initWithFrame:(CPRect)aFrame styleMask:(unsigned)aStyleMask
{
self = [super initWithFrame:aFrame];
if (self)
{
_styleMask = aStyleMask;
_resizeIndicatorOffset = CGSizeMakeZero();
_toolbarOffset = CGSizeMakeZero();
}
return self;
}
@@ -107,14 +106,14 @@ var _CPWindowViewResizeIndicatorImage = nil;
{
// FIXME: This should be better
var frame = [_resizeIndicator frame];
if (CGRectContainsPoint(frame, [self convertPoint:[anEvent locationInWindow] fromView:nil]))
return [self trackResizeWithEvent:anEvent];
}
if ([theWindow isMovableByWindowBackground])
[self trackMoveWithEvent:anEvent];
else
[super mouseDown:anEvent];
}
@@ -123,29 +122,29 @@ var _CPWindowViewResizeIndicatorImage = nil;
{
var location = [anEvent locationInWindow],
type = [anEvent type];
if (type === CPLeftMouseUp)
return;
var theWindow = [self window];
if (type === CPLeftMouseDown)
{
var frame = [theWindow frame];
_resizeFrame = CGRectMake(location.x, location.y, CGRectGetWidth(frame), CGRectGetHeight(frame));
}
else if (type === CPLeftMouseDragged)
{
var newSize = CGSizeMake(CGRectGetWidth(_resizeFrame) + location.x - CGRectGetMinX(_resizeFrame), CGRectGetHeight(_resizeFrame) + location.y - CGRectGetMinY(_resizeFrame));
{
var newSize = CGSizeMake(CGRectGetWidth(_resizeFrame) + location.x - CGRectGetMinX(_resizeFrame), CGRectGetHeight(_resizeFrame) + location.y - CGRectGetMinY(_resizeFrame));
if (theWindow._isSheet && theWindow._parentView && (theWindow._frame.size.width !== newSize.width))
[theWindow._parentView _setAttachedSheetFrameOrigin];
[theWindow setFrameSize:newSize];
[theWindow._parentView _setAttachedSheetFrameOrigin];
[theWindow setFrameSize:newSize];
}
[CPApp setTarget:self selector:@selector(trackResizeWithEvent:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
}
@@ -161,10 +160,10 @@ var _CPWindowViewResizeIndicatorImage = nil;
visibleFrame = [[CPPlatformWindow primaryPlatformWindow] visibleFrame];
var minPointY = 0;
if([CPMenu menuBarVisible])
if ([CPMenu menuBarVisible])
minPointY = [[CPApp mainMenu] menuBarHeight];
var restrictedPoint = CGPointMake(0, 0);
restrictedPoint.x = MIN(MAX(aPoint.x, -_frame.size.width + 4.0), CGRectGetMaxX(visibleFrame) - 4.0);
@@ -194,14 +193,14 @@ var _CPWindowViewResizeIndicatorImage = nil;
var theWindow = [self window],
frame = [theWindow frame],
location = [theWindow convertBaseToGlobal:[anEvent locationInWindow]],
origin = [self _pointWithinScreenFrame:CGPointMake(_CGRectGetMinX(frame) + (location.x - _mouseDraggedPoint.x),
origin = [self _pointWithinScreenFrame:CGPointMake(_CGRectGetMinX(frame) + (location.x - _mouseDraggedPoint.x),
_CGRectGetMinY(frame) + (location.y - _mouseDraggedPoint.y))];
[theWindow setFrameOrigin:origin];
_mouseDraggedPoint = [self _pointWithinScreenFrame:location];
}
[CPApp setTarget:self selector:@selector(trackMoveWithEvent:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
}
@@ -211,9 +210,9 @@ var _CPWindowViewResizeIndicatorImage = nil;
{
var size = [_CPWindowViewResizeIndicatorImage size],
boundsSize = [self frame].size;
_resizeIndicator = [[CPImageView alloc] initWithFrame:CGRectMake(boundsSize.width - size.width - _resizeIndicatorOffset.width, boundsSize.height - size.height - _resizeIndicatorOffset.height, size.width, size.height)];
[_resizeIndicator setImage:_CPWindowViewResizeIndicatorImage];
[_resizeIndicator setAutoresizingMask:CPViewMinXMargin | CPViewMinYMargin];
@@ -236,15 +235,15 @@ var _CPWindowViewResizeIndicatorImage = nil;
{
if (CGSizeEqualToSize(_resizeIndicatorOffset, anOffset))
return;
_resizeIndicatorOffset = anOffset;
if (!_resizeIndicator)
return;
var size = [_resizeIndicator frame].size,
boundsSize = [self frame].size;
[_resizeIndicator setFrameOrigin:CGPointMake(boundsSize.width - size.width - anOffset.width, boundsSize.height - size.height - anOffset.height)];
}
@@ -280,7 +279,7 @@ var _CPWindowViewResizeIndicatorImage = nil;
{
if (!_toolbarView || [_toolbarView isHidden])
return [self toolbarOffset].height;
return CGRectGetMaxY([_toolbarView frame]);
}
@@ -294,20 +293,20 @@ var _CPWindowViewResizeIndicatorImage = nil;
var theWindow = [self window],
bounds = [self bounds],
width = CGRectGetWidth(bounds);
if ([[theWindow toolbar] isVisible])
{
var toolbarView = [self toolbarView],
toolbarOffset = [self toolbarOffset];
[toolbarView setFrame:CGRectMake(toolbarOffset.width, toolbarOffset.height, width, CGRectGetHeight([toolbarView frame]))];
}
if ([self showsResizeIndicator])
{
var size = [_resizeIndicator frame].size,
boundsSize = [self bounds].size;
[_resizeIndicator setFrameOrigin:CGPointMake(boundsSize.width - size.width - _resizeIndicatorOffset.width, boundsSize.height - size.height - _resizeIndicatorOffset.height)];
}
}
@@ -317,11 +316,11 @@ var _CPWindowViewResizeIndicatorImage = nil;
var theWindow = [self window],
toolbar = [theWindow toolbar],
toolbarView = [toolbar _toolbarView];
if (_toolbarView !== toolbarView)
{
[_toolbarView removeFromSuperview];
if (toolbarView)
{
[toolbarView removeFromSuperview];
@@ -329,7 +328,7 @@ var _CPWindowViewResizeIndicatorImage = nil;
[self addSubview:toolbarView];
}
_toolbarView = toolbarView;
}
+25 -14
View File
@@ -28,14 +28,19 @@
@import "CPDocument.j"
/*!
/*!
@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
{
@@ -171,8 +178,8 @@
if (_window === nil && [_cibOwner isKindOfClass:[CPDocument class]])
[self setWindow:[_cibOwner valueForKey:@"window"]];
if (!_window)
if (!_window)
{
var reason = [CPString stringWithFormat:@"Window for %@ could not be loaded from Cib or no window specified. \
Override loadWindow to load the window manually.", self];
@@ -232,7 +239,7 @@
{
if (![self supportsMultipleDocuments])
[self removeDocument:_document];
[defaultCenter removeObserver:self
name:CPDocumentWillSaveNotification
object:_document];
@@ -276,6 +283,10 @@
[self setViewController:viewController];
[self synchronizeWindowTitleWithDocumentName];
// Change of document means toolbar items may no longer make sense.
// FIXME: DOCUMENT ARCHITECTURE Should we setToolbar: as well?
[[[self window] toolbar] validateVisibleItems];
}
- (void)setSupportsMultipleDocuments:(BOOL)shouldSupportMultipleDocuments
@@ -373,7 +384,7 @@
}
/*!
Returns the document in the controlled window.
Returns the CPDocument in the controlled window.
*/
- (CPDocument)document
{
@@ -381,7 +392,7 @@
}
/*!
Sets whether the document has unsaved changes. The window can use this as a hint to
Sets whether the document has unsaved changes. The window can use this as a hint to
@param isEdited \c YES means the document has unsaved changes.
*/
- (void)setDocumentEdited:(BOOL)isEdited
+2 -2
View File
@@ -38,7 +38,7 @@ 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]];
+62
View File
@@ -0,0 +1,62 @@
/*
* CPCibBindingConnector.j
* AppKit
*
* Created by Ross Boucher.
* Copyright 2010, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPCibConnector.j"
var CPCibBindingConnectorBindingKey = @"CPCibBindingConnectorBindingKey",
CPCibBindingConnectorKeyPathKey = @"CPCibBindingConnectorKeyPathKey",
CPCibBindingConnectorOptionsKey = @"CPCibBindingConnectorOptionsKey";
@implementation CPCibBindingConnector : CPCibConnector
{
id _binding;
id _keyPath;
id _options;
}
- (id)initWithCoder:(CPCoder)aCoder
{
if (self = [super initWithCoder:aCoder])
{
_binding = [aCoder decodeObjectForKey:CPCibBindingConnectorBindingKey];
_keyPath = [aCoder decodeObjectForKey:CPCibBindingConnectorKeyPathKey];
_options = [aCoder decodeObjectForKey:CPCibBindingConnectorOptionsKey];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:_binding forKey:CPCibBindingConnectorBindingKey];
[aCoder encodeObject:_keyPath forKey:CPCibBindingConnectorKeyPathKey];
[aCoder encodeObject:_options forKey:CPCibBindingConnectorOptionsKey];
}
- (void)establishConnection
{
[_source bind:_binding toObject:_destination withKeyPath:_keyPath options:_options];
}
@end
+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);

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