Compare commits

...
675 Commits
Author SHA1 Message Date
Randall Luecke a80147bafd Merge branch 'master' into coretext 2011-06-25 22:03:51 -07:00
Randall Luecke fc81483371 Fix typeo in CPToolbar.j CPToolbarItems to not respect maxSize. Closes #1305. 2011-06-25 00:45:07 -07:00
Klaas Pieter Annema e552b022ba Merge branch 'pull-request-1302' 2011-06-24 12:21:02 +02:00
Antoine Mercadal 6c34bec51e do not return 0 if any conversion fail (return 2 instead) 2011-06-19 19:32:42 +02:00
Randall Luecke f170e4812d Documented CoreText. 2011-06-19 01:00:22 -07:00
Randall Luecke 070728aea9 Typo 2011-06-18 23:57:31 -07:00
Randall Luecke 5e3ae58d42 Added view drawing methods to CPAttributedString 2011-06-18 23:54:56 -07:00
Randall Luecke b4e4bdb924 Added string drawing methods for CPString. 2011-06-18 23:44:32 -07:00
Randall Luecke 0f097e0ff4 Added support for center alginment of in CTFrameDraw. 2011-06-18 22:59:28 -07:00
Randall Luecke e38845f993 Default to left alignment for frameDraw. 2011-06-18 22:54:03 -07:00
Randall Luecke f4f4dd8025 Default the text position point to (0,0) if it's undefined. 2011-06-18 21:53:50 -07:00
Randall Luecke c942259c90 Import CPAttributedString in Foundation.j now that we can actually use it! :D 2011-06-18 18:59:01 -07:00
Nicholas Small a4fb0920f6 Forgot key file of CoreText. 2011-06-16 11:49:05 -04:00
Ross Boucher cbabb544ab bootstrap should have a +x bit. 2011-06-15 12:54:11 -07:00
Nicholas Small 4d47b5abf5 CoreText.
Still needs a lot of work; there are bugs,
performance issues, and missing features.
2011-06-13 01:30:50 -07:00
Alexander Ljungberg aac09d8208 Clicking on a non-editable level indicator in a table row now selects that row. 2011-06-06 00:44:15 -04:00
Alexander Ljungberg a127fc9ec3 'Enabled' support for nib2cib of NSLevelIndicator. 2011-06-06 00:35:41 -04:00
Alexander Ljungberg 551aa300ea Merge branch 'master' of github.com:280north/cappuccino 2011-06-06 00:11:23 -04:00
Alexander Ljungberg 485e59b5eb More handlesContentAsCompoundValue, although fairly guess-work based. More research needed in the future. 2011-06-06 00:11:04 -04:00
Alexander Ljungberg fdfcbf1da2 CPArrayController handlesContentAsCompoundValue support for contentArray binding. 2011-06-05 19:39:28 -04:00
Alexander Ljungberg 0f5eee0258 nib2cib compatible CPNumberFormatter skeleton. 2011-06-05 19:27:21 -04:00
Alexander Ljungberg 870492eb96 Fix selection behaviour in previous commit. 2011-06-05 19:19:14 -04:00
Alexander Ljungberg b50005049e Fixed: array controller remove: would not only remove selected rows, but any other rows isEqual: to the selected rows. 2011-06-05 18:57:36 -04:00
Alexander Ljungberg 0e890e19ea Fixed: during CPUserDefault change notifications, objectForKey: could return the value from prior to the change. 2011-06-05 17:32:56 -04:00
Alexander Ljungberg 59aabc150c Crude but functional infinite recursion checker, optional at compile time. 2011-06-04 01:23:24 -04:00
Alexander Ljungberg b159815349 Suppress binding updates support. 2011-06-04 00:57:57 -04:00
Tom Robinson fa0a4d3b56 Fix tests for CI. 2011-06-03 21:15:25 -07:00
Alexander Ljungberg bfe5afaddd Whitespace cleanup. 2011-06-03 00:05:30 -04:00
Alexander Ljungberg 64e907156c Minor array controller optimisation: don't send a filterPredicate change notification if clearsFilterPredicateOnInsertion is YES but filterPredicate is already nil when insertObject:atArrangedObjectIndex: is called. 2011-06-03 00:00:39 -04:00
Alexander Ljungberg 5d01ca428c Optimise CPArrayController insertObject:atArrangedObjectIndex: by not attempting to arrange the content array. The given index is only meant for the arrangedObjects. 2011-06-02 23:41:03 -04:00
Alexander Ljungberg 0a9c9741e8 CPArray mutableCopy. 2011-06-02 15:09:54 -04:00
Alexander Ljungberg 2a3b9e13c3 Merge branch 'master' of github.com:280north/cappuccino 2011-06-02 12:35:23 -04:00
Alexander Ljungberg 4e07c9f9ee Decode but mostly ignore NSImages in nib2cib. Fixed: radio groups in IB come with an NSImage and so would not nib2cib anymore after the recent addition of template image support in NSButton. 2011-06-02 12:33:43 -04:00
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
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
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
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
Ross Boucher 6c6ac4bd2e Merge pull request #1276 from hammerdr/Documentation
Elaborate what setItemPrototype expects and does in CPCollectionView.
2011-05-22 17:17:04 -07:00
Aparajita Fishman 59e5689d1a On WebKit (at least on Mac), right Command key code is 93, not 91. This was not being interpreted correctly. 2011-05-22 17:07:49 -07:00
Derek Hammer 7194a6961a Forgot a forward slash to end the pre tag. 2011-05-22 17:58:25 -05:00
Derek Hammer e404217e8b Elaborate what setItemPrototype expects and does in CPCollectionView. 2011-05-22 17:55:17 -05:00
Randy Luecke f419629ce4 Merge pull request #1260 from aparajita/cpmenu-remove-all
Added CPMenu -removeAll
2011-05-21 18:21:15 -07:00
Randy Luecke 35f958f1a7 Merge pull request #1273 from aparajita/cornerview-fix
CPTableView does not remove corner view if header view is removed
2011-05-21 18:20:43 -07:00
Alexander Ljungberg 64f9309994 Merge pull request #1268 from primalmotion/cappuccino
---

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

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

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

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

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

- Added a missing @endverbatim to CPExpression.j.

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

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

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

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

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

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

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

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

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

These commits make the tooltips looking like cocoa ones.

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

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

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

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

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

Uncaught CPInvalidArgumentException: Unsupported method on CPArray

The reason for this exception is that the old implementation set _arrangedObjects to an instance of _CPJavaScriptArray, whereas the new one will set it to a _CPObservableArray.
2011-04-13 21:18:33 -07:00
Aparajita Fishman 025e761929 If $CAPP_BUILD is not set or entity is not found in it, look in the narwhal cappuccino package. 2011-04-13 18:02:08 -04:00
Klaas Pieter Annema 1a99ac7681 Merge branch 'master' of github.com:280north/cappuccino 2011-04-13 17:34:40 +02:00
Francisco Ryan Tolmasky IandKlaas Pieter Annema 1ecbe997df Change NibApplication template's slider to be continuous since it makes for a better first experience.
Reviewed by me.
2011-04-13 17:33:52 +02:00
Klaas Pieter Annema 1d28b120dc fix CPOutlineView providing the dragged items in reverse order 2011-04-13 17:31:29 +02:00
Klaas Pieter Annema 97289d9070 add CPCoding support to CPIndexPath 2011-04-13 17:31:14 +02:00
Klaas Pieter Annema a303b3c04f Merge branch '0.9.1' 2011-04-13 08:27:53 +02:00
Klaas Pieter Annema c317274a26 Merge branch 'purem-master' into 0.9.1 2011-04-13 08:27:45 +02:00
Klaas Pieter Annema 547e57c014 Merge branch 'master' of https://github.com/purem/cappuccino into purem-master 2011-04-13 08:27:23 +02:00
Klaas Pieter Annema 5a1a7f2c86 Merge branch 'purem-master' 2011-04-13 08:24:56 +02:00
Klaas Pieter Annema fb866699e5 Merge branch 'master' of https://github.com/purem/cappuccino into purem-master 2011-04-13 08:24:47 +02:00
Francisco Ryan Tolmasky I cf487ba4de Change NibApplication template's slider to be continuous since it makes for a better first experience.
Reviewed by me.
2011-04-12 09:49:14 -07:00
Brian Donovan f79203f5d5 Fix feedback view when retargeting the drop row & operation.
CPTableView was inappropriately preserving the retargeted drop row & operation as the drag operation continued, causing the data source call to - tableView:validateDrop:proposedRow:proposedDropOperation: to echo any row and operation set by the first call to -setDropRow:dropOperation:, making it impossible for the data source to determine new values for -setDropRow:dropOperation:, making the feedback view stay in the same place it was initially drawn.
2011-04-11 15:00:20 -07:00
purem d7fe42387c Edited bootstrap to find zsh's configuration file ~/.zshrc by default 2011-04-11 11:16:10 -07:00
Alexander Ljungberg ff7f469f9f Fixed: CPColor colorWithCSSString did not properly handle the alpha component of the CSS rbga() syntax. Fixes #687. 2011-04-10 22:16:28 -04:00
Alexander Ljungberg e44ffdc7f4 CPString subtringWithRange: and rangeOfString:options:range now throws CPRangeException for out of bounds ranges. 2011-04-10 21:20:22 -04:00
Alexander Ljungberg 91ef6bf925 Fixed: CPString rangeOfString:options:range returned locations relative to the passed-in range instead of the full string. 2011-04-10 21:05:43 -04:00
Alexander Ljungberg a33dd51d8e Fixed: searching a string for @"" with CPString rangeOfString returned results other than CPNotFound. 2011-04-10 20:38:51 -04:00
Alexander Ljungberg 2166fc1d51 Fixed: CPString rangeOfString: anchored backwards search did not work. 2011-04-10 20:19:04 -04:00
Alexander Ljungberg b29e722132 Fixed: CPString rangeOfString: backwards search did not work. Fixes #1065. 2011-04-10 20:12:33 -04:00
Alexander Ljungberg 06122bba19 Test CPString rangeOfString: in CPCaseInsensitiveSearch | CPBackwardsSearch mode. 2011-04-10 20:10:08 -04:00
Alexander Ljungberg b40f920ec6 Fixed: don't crash on the first mouse move event after merge #1211. Fixes #1221. 2011-04-10 18:33:57 -04:00
Alexander Ljungberg e327c39776 Code formatting. 2011-04-10 17:26:22 -04:00
Alexander Ljungberg c7a1717ebe Added CPDate test which catches mishandling of timezones in initWithString.
(Unfortunately the test is rather crude and only works when your current timezone offset is not 0 (UTC).)
2011-04-10 17:24:18 -04:00
Randall Luecke b9533386b4 Merge branch 'natemartinsf-master' into 0.9.1 2011-04-08 09:32:14 -04:00
Mike FellowsandRandall Luecke 69d27364d5 Trivial fix, add missing spinner.gif from manual scroll view test 2011-04-08 09:30:56 -04:00
Aparajita FishmanandRandall Luecke e3abd4e407 Fixed timezone calculation in initWithString. 2011-04-08 09:29:45 -04:00
Mike FellowsandRandall Luecke 2f501ad736 Add a manual test for drag and drop in a CPTableView 2011-04-08 09:28:30 -04:00
Randall Luecke ae5359f953 Merge branch '0.9.1' of git://github.com/280north/cappuccino into 0.9.1 2011-04-08 09:26:55 -04:00
Mike FellowsandRandall Luecke 4a57f6a1c4 Better inset bounds to improve autoscrolling while dragging in a scrollview. 2011-04-08 09:26:04 -04:00
Nathaniel Martin 9b1eac1923 deltaX and deltaY now set on mousemoved, based on last mouse event 2011-04-07 22:00:09 -07:00
Nathaniel Martin 875dbaa78f Fix for issue 1210 2011-04-06 23:16:13 -07:00
Klaas Pieter Annema 6b64291690 Merge branch 'aparajita-nib2cib-man' 2011-04-06 11:55:17 +02:00
Aparajita Fishman 52ce4c1ebf Properly documented the -F option, some formatting tweaks 2011-04-06 05:15:52 -04:00
Aparajita Fishman a7161e3ca7 Changed comparison in initial check to <=, a cib with an equal mtime could not have been converted from an IB file, it would have a later mtime. 2011-04-06 04:40:05 -04:00
Aparajita Fishman 73746e00b0 Fixes and enhancements...
- If an IB file is deleted, the corresponding cib is no longer deleted.
- In watch mode, the first time through no conversion is done if an IB file has a corresponding cib file with a later mtime.
- In watch mode, an add does not convert if there is a corresponding cib file with a later mtime.
- When catching exceptions, deal correctly with both CPException and strings.
2011-04-06 04:34:56 -04:00
Klaas Pieter Annema 327d796653 implement outlineViewDeleteKeyPressed 2011-04-06 08:14:29 +02:00
Aparajita Fishman af6d38fd16 Fixes and enhancements
- When a xib/nib is deleted, the corresponding cib is deleted.
- Fixed the calculation of the output path when given a relative path.
- Works with .nib files now.
- Works with -R option now. NSCustomResource was assuming an image path would always be relative to cwd().
- The Resources directory is always inferred from the input path, so the -R option is usually unnecessary.
- Added --default-theme option.
- Multiple extra themes can be specified with the --theme option.
- Verbose mode displays the inferred application and resources paths, and the source theme used when doing font substitutions.
- Added a man page.
- Themes are read using StaticResource instead of parsing the file myself.
- Error message tweaks.
2011-04-05 16:57:16 -04:00
Klaas Pieter Annema ab105e7273 Merge branch 'capp-man' of https://github.com/aparajita/cappuccino into aparajita-capp-man 2011-04-05 13:53:02 +02:00
Alexander Ljungberg 6115acea05 Merge branch '0.9.1' 2011-04-04 23:58:13 -04:00
Alexander Ljungberg 0d8bd95c86 Fixed: systems without xcodebuild would fail jake clean and jake clobber. 2011-04-04 23:56:30 -04:00
Klaas Pieter Annema 40bfb55b64 don't resolve nib2cib output path 2011-04-04 14:23:36 +02:00
Alexander Ljungberg f0bba44e45 Completed CPTabView documentation. 2011-04-03 17:56:31 -04:00
Alexander Ljungberg 7107adfe16 Minor doc formatting. 2011-04-03 17:45:53 -04:00
Alexander Ljungberg 501c15775e Use bsdtar explicitly for 'jake docs' in case the user has GNU tar installed through e.g. fink.
This enables the -s parameter to work.
2011-04-03 16:58:39 -04:00
Alexander Ljungberg f29dcc9c6b Document CPScreen. 2011-04-03 16:12:27 -04:00
Alexander Ljungberg 370960418f Better formatting, clickable links and basic code styling for the Doxygen docs front page. This look will resemble that of the GitHub front page.
The README file was converted to Markdown which is nice to read in the terminal and automatically formatted by GitHub. For Doxygen, the markdown is first converted to HTML.
2011-04-03 14:34:20 -04:00
Aparajita Fishman c9fb862ee2 Tweak 2011-04-03 07:56:16 -04:00
Antoine Mercadal 6e1acf1f06 fix wrong AGPL header in CPUserDefaultTest.j 2011-04-03 11:41:56 +02:00
Alexander Ljungberg 2952070698 Whitespace, comment tweak. 2011-04-03 00:56:28 -04:00
Alexander Ljungberg dbb10f69f6 Merge branch 'aparajita-fonts' into 0.9.1 2011-04-02 23:32:59 -04:00
Alexander Ljungberg 9fc10260fb Merge branch 'fonts' of https://github.com/aparajita/cappuccino into aparajita-fonts 2011-04-02 22:26:21 -04:00
Alexander Ljungberg 2fbd54521d Fix up and restore all functionality to ArrayController manual test. 2011-04-02 20:08:36 -04:00
Alexander Ljungberg ae3780c0cf Recreated and cleaned up ArrayController1 since MainMenu.xib was missing. 2011-04-02 19:43:51 -04:00
Alexander Ljungberg ccf9225773 Minor KVO optimisation. 2011-04-02 18:10:13 -04:00
Alexander Ljungberg 8aaa5fe07f Test array controller KVC binding correctness.
This change splits the insertObjectAtArrangedObjectIndex:, addObject:, and removeObject: tests into two versions: one for a regular AC setContent: setup and one for when the AC is bound to an array-like destination implementing KVC.
2011-04-02 18:09:16 -04:00
Alexander Ljungberg fa1a10730e Fixed: an array controller with a bound contentArray would sometimes fail when add:, remove: and similar methods were called.
In particular the AC would fail when a _CPKeyValueCodingArray proxy was required (the destination implements insertObject:in<key>AtIndex etc.). The previous commit by cacaodev is the larger part of this fix as it enables use of mutableArrayValueForKeyPath properly. This commit merely fixes an error exposed by the previous commit where e.g. add: would apparently add two objects rather than one. This was caused by the AC observing and reacting to its own change even that it already had an optimised path to update arrangedObjects.
2011-04-02 18:03:21 -04:00
cacaodevandAlexander Ljungberg e91bc3eeef Adds a binder subclass for CPArrayController's contentArray binding. This binder allows destination.keypath who are kvc compliant, still works if they're not (through _CPKVCArray). Fixes addObject: error when contentArray is bound to a kvc array, a bug visible in ArrayController1 manual test. 2011-04-01 21:29:37 -04:00
Alexander Ljungberg 76400ecca9 Make table column internal bindings support methods private. 2011-03-31 20:48:51 -04:00
Alexander Ljungberg 9a0cf2b37d Manual test for bindings based table view editing. 2011-03-31 20:35:11 -04:00
Alexander Ljungberg dae36cda56 Bindings support for inline table view cell editing. 2011-03-31 20:26:56 -04:00
Aparajita Fishman e07ff706ab Fixed stupid bug in figuring out what directory to watch 2011-03-31 20:10:18 -04:00
Aparajita Fishman 7ec31a7c53 If no directory is passed to --watch, default to Resources 2011-03-31 19:51:22 -04:00
Aparajita Fishman b4221aebcb fontinfo binary is built directly in $CAPP_BUILD, and intermediate build products are put there also. 2011-03-31 16:43:58 -04:00
Aparajita Fishman fdcd56e0ae Added a man page for capp, global function for copying a man page 2011-03-31 14:52:38 -04:00
Alexander Ljungberg 2532c760ea Closes #1202. Test that CPEvent deltaX, deltaY and deltaZ do work. Also initialise deltas to 0 instead of nil. 2011-03-31 11:11:57 -04:00
Aparajita Fishman 0f68fa0141 Added ability to pass a string and get its width, removed some unnecessary releases 2011-03-30 00:28:45 -04:00
Aparajita Fishman 26fba1fdd9 Remove bogus line, not sure how it got there 2011-03-29 17:44:34 -04:00
Aparajita Fishman 16bacae7e3 More cool stuff...
- The holy grail! I took Klaas' great autonib2cib and rolled it into nib2cib.
- Removed check for stream in CPLogColorize, it isn't necessary and reduces its general-purpose usage.
2011-03-29 16:06:19 -04:00
Aparajita Fishman d00a8b9d18 Use a parser action to show version and quit 2011-03-29 12:54:54 -04:00
Alexander Ljungberg 094b798765 Fixed: when table view grid lines were active they did not draw on top of selection highlights like in Cocoa. 2011-03-29 00:45:25 -04:00
Alexander Ljungberg 89974796b1 Fixed: table view's rectOfColumn: method returned a rect reduced by the intercell spacing. It should return the rect of the entire column. Fixed: when a column was selected the column selection colour would not cover the whole column. Fixed: in recent builds, table view header divider lines did not line up with body divider lines.
Ultimately, intercell spacing is only applied, as the name implies, inside of cells. It is not applied in the header, nor at the column or row level. Only data views inside of cells are offset.
2011-03-29 00:33:32 -04:00
Aparajita Fishman 90c19b1856 Added explicit size for completeness of sample, fixed font substitution if theme has no font, used LucidaGrande-Bold 13 to do better code coverage. 2011-03-28 23:55:31 -04:00
Aparajita Fishman 044a605e47 Added font methods so that nib2cib can do font substitution 2011-03-28 23:51:45 -04:00
Aparajita Fishman 7d62b6e1eb Made the defaults global constants 2011-03-28 23:50:56 -04:00
Aparajita Fishman 93f36a2326 Added missing license, added a lot more support for radio button attributes, included fix for issue #1190 2011-03-28 22:44:03 -04:00
Aparajita Fishman 0218246678 Added key equivalents to radio buttons, more attributes to test new radio button support 2011-03-28 22:42:46 -04:00
Aparajita Fishman 79fde3fbeb Factored out font substitution code, added special case for radio buttons 2011-03-28 22:38:26 -04:00
Alexander Ljungberg 539ea2e589 Merge branch '0.9.1' of github.com:280north/cappuccino into 0.9.1 2011-03-28 22:14:32 -04:00
Alexander Ljungberg 4f6d939634 Minor table view cleanup. 2011-03-28 22:14:11 -04:00
Alexander Ljungberg d68d84cfdf Merge branch '0.9.1' of github.com:280north/cappuccino into 0.9.1 2011-03-28 21:24:45 -04:00
Alexander Ljungberg 1ef7fc45f5 Added a note to the CPContinuouslyUpdates test clarifying the purpose of the sliders. 2011-03-28 21:23:53 -04:00
Alexander Ljungberg 430a74735b Fixed: CPSliders always became continuous when archived/unarchived through CPCoding. 2011-03-28 21:18:47 -04:00
Randall Luecke de08addfa1 Fix for grid lines not being drawn in the headers of table columns which were not originally exposed. 2011-03-28 21:10:59 -04:00
Alexander Ljungberg 26003365bc Fixed: CPSlider isContinuous disagreed with setContinuous. 2011-03-28 21:06:07 -04:00
Alexander Ljungberg 11ab9a77ad Minor performance improvement to CPContinuouslyUpdatesValueBindingOption. 2011-03-28 20:12:32 -04:00
Aparajita Fishman 52f3f81265 Changed window title 2011-03-28 18:59:03 -04:00
Aparajita Fishman 2599f820c7 Merge branch 'font-fun' into fonts
Conflicts:
	Tools/nib2cib/NSButton.j
2011-03-28 18:51:10 -04:00
Aparajita Fishman 8fed2c7a9a Factored code into functions, fixed input and output path computation 2011-03-28 18:45:03 -04:00
Alexander Ljungberg f9f03c8b54 Manual test for CPContinuouslyUpdatesValueBindingOption and CPNullPlaceholderBindingOption. 2011-03-28 18:23:17 -04:00
Alexander Ljungberg 110d75b1e5 Text field support for CPContinuouslyUpdatesValueBindingOption. 2011-03-28 18:20:19 -04:00
Alexander Ljungberg 79ec12e2a2 Added support for the CPNullPlaceholderBindingOption for bound text fields. 2011-03-28 18:02:52 -04:00
Aparajita Fishman 5133a7dc91 Fix NSButton so it will merge with master 2011-03-28 16:28:28 -04:00
Klaas Pieter Annema 425401c049 Merge branch 'keyview' of https://github.com/aparajita/cappuccino into aparajita-keyview 2011-03-28 20:12:45 +02:00
Klaas Pieter Annema 38f896d018 fix CPURL equality check 2011-03-28 18:56:25 +02:00
Alexander Ljungberg 7b3ae56031 CPObjectController automaticallyPreparesContent support. 2011-03-28 11:06:12 -04:00
Klaas Pieter Annema 4418b2403f add test case for firstObject 2011-03-28 15:23:03 +02:00
Klaas Pieter Annema 42c60913c6 add firstObject method to CPArray 2011-03-28 13:14:25 +02:00
Alexander Ljungberg 65ce93ce42 Merge branch '0.9.1' of github.com:280north/cappuccino into 0.9.1 2011-03-27 18:18:30 -04:00
Alexander Ljungberg 651882b3c8 Merge branch 'aparajita-keyEquivalent' into 0.9.1 2011-03-27 18:18:07 -04:00
Aparajita Fishman ac7ff24dd7 These got left out in f1f78d6c6a 2011-03-27 15:22:13 -04:00
Aparajita Fishman b54ea6e8ac Ignore Xcode project user data, added fontinfo package 2011-03-25 23:38:49 -04:00
Randall Luecke cf6d7f2d85 Rev version number to 0.9.1 2011-03-25 23:36:07 -04:00
Alexander Ljungberg 65043c5d78 Added some missing LGPL headers. 2011-03-25 22:52:57 -04:00
Aparajita Fishman 30484e04b9 Moved some useful functions to common.jake and made some private functions global so they can be reused by our Jakefiles 2011-03-25 18:51:37 -04:00
Aparajita Fishman 4decc6d9c7 Use a relative path in the symlink 2011-03-25 18:47:41 -04:00
Aparajita Fishman 1a5b8f5210 Fixed install-symlinks to actually work, added sudo-install-symlinks 2011-03-25 18:47:24 -04:00
Aparajita Fishman 93119233cd Prevent self-reference in _next/_previousKeyView 2011-03-25 14:45:19 -04:00
Alexander Ljungberg 2f56f899cf Merge branch 'master' of https://github.com/eventualbuddha/cappuccino into eventualbuddha-master 2011-03-25 12:53:42 -04:00
Brian Donovan b69c25bc2a Fix documentation typo. 2011-03-25 08:50:06 -07:00
Alexander Ljungberg bdcf84ec15 Merge branch '0.9.1' of github.com:280north/cappuccino into 0.9.1 2011-03-25 00:43:36 -04:00
Aparajita FishmanandRandall Luecke f1f78d6c6a Fixed the infamous "wandering checkbox" bug 2011-03-24 23:39:25 -04:00
Randall Luecke 83e4e7ecce Merge branch 'jake-install-symlinks' of https://github.com/aparajita/cappuccino into aparajita-jake-install-symlinks 2011-03-24 23:38:45 -04:00
Alexander Ljungberg e6eb14e819 Fixed: in Firefox, certain web views would not send the first webView:didFinishLoadForFrame: delegate message nor detect the need for AppKit scrollbars. 2011-03-24 23:33:44 -04:00
Alexander Ljungberg 380a860ba9 Fixed: loading an empty string into a web view would make it entirely white regardless of the background colour specified. 2011-03-24 21:20:55 -04:00
Alexander Ljungberg 5cbbafdf72 Support for web views with transparent or coloured backgrounds. 2011-03-24 21:13:41 -04:00
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
Stephen Ierodiaconou 76b5682234 Missing imports in CPSet+KVO 2010-12-26 10:29:46 +02:00
Stephen Ierodiaconou 4aa4f1a62a Some more missing imports 2010-12-26 01:47:26 +02:00
Stephen Ierodiaconou 7ae14e9eb5 CPCharacterSet lint and fixes 2010-12-26 01:34:43 +02:00
Stephen Ierodiaconou bfe03a8874 CPJSONPConnection Missing imports and self check 2010-12-26 01:34:43 +02:00
Stephen Ierodiaconou 66b6b44f86 CPPredicate lint, import fixes, and some bug fixes 2010-12-26 01:34:43 +02:00
Stephen Ierodiaconou b70018bd80 Import fixes and lint 2010-12-26 01:34:37 +02:00
Jeremy Lujan 41d757e0c4 *Fix issue in setParameters due to expression in while condition in CPFlashView
*Protect against overwriting flashvars in _params when setParams is called after setFlashVars in CPFlashView
2010-12-14 21:38:52 -06:00
Andreas Falk a302fdfb8f CPTextField should not bother with handling tab to go to the next key
view, CPWindow does that for us.
2010-11-15 19:44:02 +01:00
Andreas bb9e1a830d Add cancelOperation action to clear text when pressing ESC 2010-11-13 15:21:37 +01:00
Andreas 9b7f8ec31e Add -insertTabIgnoringFieldEditor: and -insertNewlineIgnoringFieldEditor: 2010-11-13 15:16:25 +01:00
Andreas 17b40fcb9d Adapt CPTextField to use interpretKeyEvents and actions instead of directly reading from keyDown 2010-11-13 15:14:09 +01:00
cacaodev 602a2c47c2 CPScanner fixes with tests. 2010-11-13 02:29:04 +01:00
cacaodev 3cfbca5a19 CPScanner: When the scanner did not accumulate any string, do not change (to nil) the object passed as a ref in ...intoSring:ref() methods. With tests. 2010-10-23 10:25:42 +02:00
Paul Baumgart 2cc6c54fbf Start index for var-args needs to be 2, not 0. I only got lucky that it worked anyway. 2010-09-29 15:19:20 -07:00
Paul Baumgart e62fd3cf40 Add a test case to test some reductions of regexes that current cause errors in the Preprocessor. 2010-09-24 16:46:31 -07:00
Paul Baumgart 8cc61cccfd add behavior tests for methods, ivars, and inheritance; currently, one of the ivar tests fails due to bug #498 2010-09-24 15:10:06 -07:00
Paul Baumgart 0802b80c35 Make local param shadowing detection print a warning instead of throwing a SyntaxError. This way it's easier to test that particular scenario, since this is actually a bug in the Preprocessor. 2010-09-24 15:03:22 -07:00
Paul Baumgart 8de508381a re-organize directory structure of preprocessor tests 2010-09-24 15:02:07 -07:00
Paul Baumgart 086fa29d78 Objective-J Preprocessor Tests: fix scoping bug that caused only the last file in FILENAMES to be tested. 2010-09-22 00:50:15 -07:00
601 changed files with 84764 additions and 13785 deletions
+4
View File
@@ -5,3 +5,7 @@ Demos
./Aristo
WebSite
.push-package
*.xcodeproj/*.pbxuser
*.xcodeproj/*.perspectivev3
xcuserdata/
!*.xcodeproj/project.pbxproj
+8 -1
View File
@@ -25,6 +25,7 @@
@import "CPAnimation.j"
@import "CPApplication.j"
@import "CPArrayController.j"
@import "CPAttributedString+Additions.j"
@import "CPBezierPath.j"
@import "CPBox.j"
@import "CPBrowser.j"
@@ -59,6 +60,7 @@
@import "CPImage.j"
@import "CPImageView.j"
@import "CPKeyBinding.j"
@import "CPLevelIndicator.j"
@import "CPMenu.j"
@import "CPMenuItem.j"
@import "CPOpenPanel.j"
@@ -66,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"
@@ -79,6 +84,7 @@
@import "CPSound.j"
@import "CPSplitView.j"
@import "CPStepper.j"
@import "CPString+Additions.j"
@import "CPTableColumn.j"
@import "CPTableView.j"
@import "CPTabView.j"
@@ -87,11 +93,12 @@
@import "CPTokenField.j"
@import "CPToolbar.j"
@import "CPToolbarItem.j"
@import "_CPToolTip.j"
@import "CPTreeNode.j"
@import "CPUserDefaultsController.j"
@import "CPView.j"
@import "CPViewAnimation.j"
@import "CPViewController.j"
@import "CPWebView.j"
@import "CPWindow.j"
@import "CPWindowController.j"
+1 -1
View File
@@ -69,7 +69,7 @@
@class CPAccordionView
<p>CPAccordionView provides a container for CPAccordionViewItem objects and manages layout state
for all sublayout items.</p>
for all sub-layout items.</p>
<strong>Example</strong><br />
<pre>
+1 -1
View File
@@ -6,7 +6,7 @@
* Copyright 2008, Jake MacMullin.
*
* 11/10/2008 Ross Boucher
* - Make it conform to style guidelines, general cleanup and ehancements
* - Make it conform to style guidelines, general cleanup and enhancements
* 11/10/2010 Antoine Mercadal
* - Enhancements, better compliance with Cocoa API
*
+1
View File
@@ -21,6 +21,7 @@
*/
@import <Foundation/CPObject.j>
@import <Foundation/CPTimer.j>
@import "CAMediaTimingFunction.j"
+145 -8
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;
@@ -293,11 +292,21 @@ CPRunContinuesResponse = -1002;
}
}
/*!
Sets the applications icon image. This image is used in the default "About" window.
By default this value is pulled from the CPApplicationIcon key in your info.plist file.
@param anImage - The image to set.
*/
- (void)setApplicationIconImage:(CPImage)anImage
{
_applicationIconImage = anImage;
}
/*!
Returns the application icon image. By default this is pulled from the CPApplicationIcon key of info.plist.
@return CPImage - Your application icon image.
*/
- (CPImage)applicationIconImage
{
if (_applicationIconImage)
@@ -310,11 +319,38 @@ CPRunContinuesResponse = -1002;
return _applicationIconImage;
}
/*!
Opens the standard about panel with no options.
*/
- (void)orderFrontStandardAboutPanel:(id)sender
{
[self orderFrontStandardAboutPanelWithOptions:nil];
}
/*!
Opens the standard about panel. This method takes a single argument \c options.
Options is a dictionary that can contain any of the following keys:
<pre>
ApplicationName - The name of your application.
ApplicationIcon - Application icon image.
Version - The full version of your application
ApplicationVersion - The shorter version number of your application.
Copyright - Human readable copyright information.
</pre>
If you choose not the include any of the above keys, they will default
to the following respective keys in your info.plist file.
<pre>
CPBundleName
CPApplicationIcon (through a call to -applicationIconImage, see documentation for that method for more details)
CPBundleVersion
CPBundleShortVersionString
CPHumanReadableCopyright
</pre>
@param options - A dictionary with the aboe listed keys. You can pass nil to default to your plist values.
*/
- (void)orderFrontStandardAboutPanelWithOptions:(CPDictionary)options
{
if (!_aboutPanel)
@@ -530,7 +566,7 @@ CPRunContinuesResponse = -1002;
- (BOOL)_handleKeyEquivalent:(CPEvent)anEvent
{
return [[self keyWindow] performKeyEquivalent:anEvent] ||
[_mainMenu performKeyEquivalent:anEvent];
[[self mainMenu] performKeyEquivalent:anEvent];
}
/*!
@@ -574,6 +610,10 @@ CPRunContinuesResponse = -1002;
[[anEvent window] sendEvent:anEvent];
}
/*!
If the delegate responds to the given selector it will call the method on the delegate,
otherwise the method will be passed to CPResponder.
*/
- (void)doCommandBySelector:(SEL)aSelector
{
if ([_delegate respondsToSelector:aSelector])
@@ -637,7 +677,7 @@ CPRunContinuesResponse = -1002;
*/
- (CPMenu)mainMenu
{
return _mainMenu;
return [self menu];
}
/*!
@@ -645,21 +685,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 +877,38 @@ CPRunContinuesResponse = -1002;
return nil;
}
/*!
Fires a callback function when an event matching a given mask occurs.
@param aCallback - A js function to be fired.
@prarm aMask - An event mask for the next event.
@param anExpiration - The date for which this callback expires (not implemented).
@param inMode (not implemented).
@param shouldDequeue (not implemented).
*/
- (void)setCallback:(Function)aCallback forNextEventMatchingMask:(unsigned int)aMask untilDate:(CPDate)anExpiration inMode:(CPString)aMode dequeue:(BOOL)shouldDequeue
{
_eventListeners.push(_CPEventListenerMake(aMask, aCallback));
}
- (CPEvent)setTarget:(id)aTarget selector:(SEL)aSelector forNextEventMatchingMask:(unsigned int)aMask untilDate:(CPDate)anExpiration inMode:(CPString)aMode dequeue:(BOOL)shouldDequeue
/*!
Assigns a target and action for the next event matching a given event mask.
The callback method called will be passed the CPEvent when it fires.
@param aTarget - The target object for the callback.
@param aSelector - The selector which should be called on the target object.
@param aMask - The mask for a given event which should trigger the callback.
@param anExpiration - The date for which the callback expires (not implemented).
@param aMode (not implemented).
@param shouldDequeue (not implemented).
*/
- (void)setTarget:(id)aTarget selector:(SEL)aSelector forNextEventMatchingMask:(unsigned int)aMask untilDate:(CPDate)anExpiration inMode:(CPString)aMode dequeue:(BOOL)shouldDequeue
{
_eventListeners.push(_CPEventListenerMake(aMask, function (anEvent) { objj_msgSend(aTarget, aSelector, anEvent); }));
}
/*!
Returns the last event recieved by your application.
*/
- (CPEvent)currentEvent
{
return _currentEvent;
@@ -867,6 +938,19 @@ CPRunContinuesResponse = -1002;
[aWindow _attachSheet:aSheet modalDelegate:aModalDelegate didEndSelector:aDidEndSelector contextInfo:aContextInfo];
}
/*!
Ends a sheet modal.
The following are predefined return codes:
<pre>
CPRunStoppedResponse
CPRunAbortedResponse
CPRunContinuesResponse
</pre>
@param sheet - The window object (sheet) to dismiss.
@param returnCode - The return code to send to the delegate. You can use one of the return codes above or a custom value that you define.
*/
- (void)endSheet:(CPWindow)sheet returnCode:(int)returnCode
{
var count = [_windows count];
@@ -885,11 +969,31 @@ CPRunContinuesResponse = -1002;
}
}
/*!
Ends a sheet and sends the return code "0".
@param sheet - The CPWindow object (sheet) that should be dismissed.
*/
- (void)endSheet:(CPWindow)sheet
{
// FIX ME: this is wrong: by Cocoa this should be: CPRunStoppedResponse.
[self endSheet:sheet returnCode:0];
}
/*!
Returns and array of slash seperated arugments to your application.
These values are pulled from your window location hash.
For exampled if your application loaded:
<pre>
index.html#280north/cappuccino/issues
</pre>
The follow array would be returned:
<pre>
["280north", "cappuccino", "issues"]
</pre>
@return CPArray - The array of arguments.
*/
- (CPArray)arguments
{
if (_fullArgsString !== window.location.hash)
@@ -898,6 +1002,22 @@ CPRunContinuesResponse = -1002;
return _args;
}
/*!
Sets the arguments of your application.
That is, set the slash seperated values of an array as the window location hash.
For example if you pass an array:
<pre>
["280north", "cappuccino", "issues"]
</pre>
The new window location would be
<pre>
index.html#280north/cappuccino/issues
</pre>
@param args - An array of arguments.
*/
- (void)setArguments:(CPArray)args
{
if (!args || args.length == 0)
@@ -939,6 +1059,23 @@ CPRunContinuesResponse = -1002;
_args = [];
}
/*!
Returns a dictionary of the window location named arguments.
For example if your location was:
<pre>
index.html?owner=280north&repo=cappuccino&type=issues
</pre>
a CPDictionary with the keys:
<pre>
owner, repo, type
</pre>
and respective values:
<pre>
280north, cappuccino, issues
</pre>
Will be returned.
*/
- (CPDictionary)namedArguments
{
return _namedArgs;
+509 -40
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,56 +112,176 @@
return [CPSet setWithObjects:"selectionIndexes"];
}
- (id)init
{
self = [super init];
if (self)
{
_sortDescriptors = [CPArray array];
_selectionIndexes = [CPIndexSet indexSet];
_preservesSelection = YES;
_selectsInsertedObjects = YES;
_avoidsEmptySelection = YES;
_clearsFilterPredicateOnInsertion = YES;
_alwaysUsesMultipleValuesMarker = NO;
_automaticallyRearrangesObjects = NO;
_filterRestrictsInsertion = YES; // FIXME: Not in use
[self _init];
}
return self;
}
- (void)_init
{
_sortDescriptors = [CPArray array];
_filterPredicate = nil;
_selectionIndexes = [CPIndexSet indexSet];
[self __setArrangedObjects:[CPArray array]];
}
- (void)prepareContent
{
[self _setContentArray:[[self newObject]]];
}
/*!
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 = [];
@@ -183,9 +313,11 @@
// Don't use [super setContent:] as that would fire the contentObject change.
// We need to be in control of when notifications fire.
// Note that if we have a contentArray binding, setting the content does /not/
// cause a reverse binding set.
_contentObject = value;
if (_clearsFilterPredicateOnInsertion)
if (_clearsFilterPredicateOnInsertion && _filterPredicate != nil)
[self __setFilterPredicate:nil]; // Causes a _rearrangeObjects.
else
[self _rearrangeObjects];
@@ -199,32 +331,53 @@
[self didChangeValueForKey:@"filterPredicate"];
}
/*!
@ignore
*/
- (void)_setContentArray:(id)anArray
{
[self setContent:anArray];
}
/*!
@ignore
*/
- (void)_setContentSet:(id)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 [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];
@@ -232,12 +385,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"];
@@ -271,24 +427,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)
@@ -300,14 +472,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"];
}
/*
@@ -320,33 +511,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]
@@ -400,6 +614,10 @@
return YES;
}
/*!
Returns an array of the selected objects.
@return CPArray - the selected objects.
*/
- (CPArray)selectedObjects
{
var objects = [[self arrangedObjects] objectsAtIndexes:[self selectionIndexes]];
@@ -407,6 +625,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"];
@@ -441,12 +665,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;
@@ -455,11 +687,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;
@@ -470,22 +711,49 @@
//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];
if (_clearsFilterPredicateOnInsertion)
[self __setFilterPredicate:nil];
// Allow handlesContentAsCompoundValue reverse sets to trigger.
[[CPBinder getBinding:@"contentArray" forObject:self] _contentArrayDidChange];
if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:object])
_disableSetContent = NO;
if (willClearPredicate)
{
// Full rearrange needed due to changed filter.
_filterPredicate = nil;
[self _rearrangeObjects];
}
else if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:object])
{
// Insert directly into the array.
var pos = [_arrangedObjects insertObject:object inArraySortedByDescriptors:_sortDescriptors];
// selectionIndexes change notification will be fired as a result of the
@@ -495,26 +763,55 @@
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 in the receiver's arrangedObjects. Also add the object
to the content collection (although at the end rather than the given index).
@param id anObject - The object to add to the collection.
@param int anIndex - The index to insert the object at.
*/
- (void)insertObject:(id)anObject atArrangedObjectIndex:(int)anIndex
{
if (![self canAdd])
return;
if (_clearsFilterPredicateOnInsertion)
var willClearPredicate = NO;
if (_clearsFilterPredicateOnInsertion && _filterPredicate)
{
[self willChangeValueForKey:@"filterPredicate"];
willClearPredicate = YES;
}
[self willChangeValueForKey:@"content"];
[_contentObject insertObject:anObject atIndex:anIndex];
if (_clearsFilterPredicateOnInsertion)
/*
See _disableSetContent explanation in addObject:.
*/
_disableSetContent = YES;
// The atArrangedObjectIndex: part of this method's name only refers to where the
// object goes in arrangedObjects, not in the content array. So use addObject:,
// not insertObject:atIndex: here for speed.
[_contentObject addObject:anObject];
// Allow handlesContentAsCompoundValue reverse sets to trigger.
[[CPBinder getBinding:@"contentArray" forObject:self] _contentArrayDidChange];
_disableSetContent = NO;
if (willClearPredicate)
[self __setFilterPredicate:nil];
[[self arrangedObjects] insertObject:anObject atIndex:anIndex];
@@ -530,28 +827,46 @@
[self __setSelectionIndexes:[CPIndexSet indexSetWithIndex:0]];
[self didChangeValueForKey:@"content"];
if (_clearsFilterPredicateOnInsertion)
if (willClearPredicate)
[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
{
[self willChangeValueForKey:@"content"];
[_contentObject removeObject:object];
[self willChangeValueForKey:@"content"];
if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:object])
{
// selectionIndexes change notification will be fired as a result of the
// content change. Don't fire manually.
// See _disableSetContent explanation in addObject:.
_disableSetContent = YES;
[_contentObject removeObject:object];
// Allow handlesContentAsCompoundValue reverse sets to trigger.
[[CPBinder getBinding:@"contentArray" forObject:self] _contentArrayDidChange];
_disableSetContent = NO;
if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:object])
{
// selectionIndexes change notification will be fired as a result of the
// content change. Don't fire manually.
var pos = [_arrangedObjects indexOfObject:object];
[_arrangedObjects removeObjectAtIndex:pos];
[_selectionIndexes shiftIndexesStartingAtIndex:pos by:-1];
}
}
[self didChangeValueForKey:@"content"];
[self didChangeValueForKey:@"content"];
}
/*!
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])
@@ -560,6 +875,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])
@@ -570,17 +889,74 @@
[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]]];
[self removeObjectsAtArrangedObjectIndexes:_selectionIndexes];
}
- (void)removeObjectsAtArrangedObjectIndexes:(CPIndexSet)indexes
/*!
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)anIndexSet
{
[self _removeObjects:[[self arrangedObjects] objectsAtIndexes:indexes]];
[self willChangeValueForKey:@"content"];
/*
See _disableSetContent explanation in addObject:.
*/
_disableSetContent = YES;
var arrangedObjects = [self arrangedObjects],
index = [anIndexSet lastIndex],
position = CPNotFound,
newSelectionIndexes = [_selectionIndexes copy];
while (index !== CPNotFound)
{
var object = [arrangedObjects objectAtIndex:index];
// First try the simple case which should work if there are no sort descriptors.
if ([_contentObject objectAtIndex:index] === object)
[_contentObject removeObjectAtIndex:index];
else
{
// Since we don't have a reverse mapping between the sorted order and the
// unsorted one, we'll just simply have to remove an arbitrary pointer. It might
// be the 'wrong' one - as in not the one the user selected - but the wrong
// one is still just another pointer to the same object, so the user will not
// be able to see any difference.
contentIndex = [_contentObject indexOfObjectIdenticalTo:object];
[_contentObject removeObjectAtIndex:contentIndex];
}
[arrangedObjects removeObjectAtIndex:index];
// Deselect this row if it was selected, and either way shift all selection indexes
// following it up by 1.
[newSelectionIndexes removeIndex:index];
[newSelectionIndexes shiftIndexesStartingAtIndex:index by:-1];
index = [anIndexSet indexLessThanIndex:index];
}
// Allow handlesContentAsCompoundValue reverse sets to trigger.
[[CPBinder getBinding:@"contentArray" forObject:self] _contentArrayDidChange];
_disableSetContent = NO;
// This will automatically handle the avoidsEmptySelection case.
[self __setSelectionIndexes:newSelectionIndexes];
[self didChangeValueForKey:@"content"];
}
/*!
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])
@@ -593,17 +969,34 @@
[contentArray addObject:[objects objectAtIndex:i]];
[self setContent:contentArray];
// Allow handlesContentAsCompoundValue reverse sets to trigger.
[[CPBinder getBinding:@"contentArray" forObject:self] _contentArrayDidChange];
}
/*!
Removes an array of objects from the collection.
@param CPArray anArray - The array of objects to remove
*/
- (void)removeObjects:(CPArray)objects
{
[self _removeObjects:objects];
}
/*!
@ignore
*/
- (void)_removeObjects:(CPArray)objects
{
[self willChangeValueForKey:@"content"];
// See _disableSetContent explanation in addObject:.
_disableSetContent = YES;
[_contentObject removeObjectsInArray:objects];
// Allow handlesContentAsCompoundValue reverse sets to trigger.
[[CPBinder getBinding:@"contentArray" forObject:self] _contentArrayDidChange];
_disableSetContent = NO;
var arrangedObjects = [self arrangedObjects],
position = [arrangedObjects indexOfObject:[objects objectAtIndex:0]];
@@ -631,6 +1024,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];
@@ -638,12 +1035,81 @@
@end
@implementation CPArrayController (CPBinder)
+ (Class)_binderClassForBinding:(CPString)theBinding
{
if (theBinding == @"contentArray")
return [_CPArrayControllerContentBinder class];
return [super _binderClassForBinding:theBinding];
}
@end
@implementation _CPArrayControllerContentBinder : CPBinder
- (void)setValueFor:(CPString)aBinding
{
var destination = [_info objectForKey:CPObservedObjectKey],
keyPath = [_info objectForKey:CPObservedKeyPathKey],
options = [_info objectForKey:CPOptionsKey],
isCompound = [self handlesContentAsCompoundValue];
if (!isCompound)
{
newValue = [destination mutableArrayValueForKeyPath:keyPath];
}
else
{
// handlesContentAsCompoundValue == YES so we cannot just set up a proxy.
// Every read and every write must go through transformValue and
// reverseTransformValue, and the resulting object cannot be described by
// a key path.
newValue = [destination valueForKeyPath:keyPath];
}
newValue = [self transformValue:newValue withOptions:options];
if (isCompound)
{
// Make sure we can edit our copy of the content. TODO In Cocoa, this copy
// appears to be deferred until the array actually needs to be edited.
newValue = [newValue mutableCopy];
}
[_source setValue:newValue forKey:aBinding];
}
- (void)_contentArrayDidChange
{
// When handlesContentAsCompoundValue == YES, it is not sufficient to modify the content object
// in place because what we are holding is an array 'unwrapped' from a compound value by
// a value transformer. So when we modify it we need a reverse set and transform to create
// a new compound value.
//
// (The Cocoa documentation on the subject is not very clear but after substantial
// experimentation this seems both reasonable and compliant.)
if ([self handlesContentAsCompoundValue])
{
var destination = [_info objectForKey:CPObservedObjectKey],
keyPath = [_info objectForKey:CPObservedKeyPathKey];
[self suppressSpecificNotificationFromObject:destination keyPath:keyPath];
[self reverseSetValueFor:@"contentArray"];
[self unsuppressSpecificNotificationFromObject:destination keyPath:keyPath];
}
}
@end
var CPArrayControllerAvoidsEmptySelection = @"CPArrayControllerAvoidsEmptySelection",
CPArrayControllerClearsFilterPredicateOnInsertion = @"CPArrayControllerClearsFilterPredicateOnInsertion",
CPArrayControllerFilterRestrictsInsertion = @"CPArrayControllerFilterRestrictsInsertion",
CPArrayControllerPreservesSelection = @"CPArrayControllerPreservesSelection",
CPArrayControllerSelectsInsertedObjects = @"CPArrayControllerSelectsInsertedObjects",
CPArrayControllerAlwaysUsesMultipleValuesMarker = @"CPArrayControllerAlwaysUsesMultipleValuesMarker";
CPArrayControllerAlwaysUsesMultipleValuesMarker = @"CPArrayControllerAlwaysUsesMultipleValuesMarker",
CPArrayControllerAutomaticallyRearrangesObjects = @"CPArrayControllerAutomaticallyRearrangesObjects";
@implementation CPArrayController (CPCoding)
@@ -659,6 +1125,8 @@ var CPArrayControllerAvoidsEmptySelection = @"CPArrayControllerAvoid
_preservesSelection = [aCoder decodeBoolForKey:CPArrayControllerPreservesSelection];
_selectsInsertedObjects = [aCoder decodeBoolForKey:CPArrayControllerSelectsInsertedObjects];
_alwaysUsesMultipleValuesMarker = [aCoder decodeBoolForKey:CPArrayControllerAlwaysUsesMultipleValuesMarker];
_automaticallyRearrangesObjects = [aCoder decodeBoolForKey:CPArrayControllerAutomaticallyRearrangesObjects];
_sortDescriptors = [CPArray array];
if (![self content] && [self automaticallyPreparesContent])
[self prepareContent];
@@ -679,6 +1147,7 @@ var CPArrayControllerAvoidsEmptySelection = @"CPArrayControllerAvoid
[aCoder encodeBool:_preservesSelection forKey:CPArrayControllerPreservesSelection];
[aCoder encodeBool:_selectsInsertedObjects forKey:CPArrayControllerSelectsInsertedObjects];
[aCoder encodeBool:_alwaysUsesMultipleValuesMarker forKey:CPArrayControllerAlwaysUsesMultipleValuesMarker];
[aCoder encodeBool:_automaticallyRearrangesObjects forKey:CPArrayControllerAutomaticallyRearrangesObjects];
}
- (void)awakeFromCib
+62
View File
@@ -0,0 +1,62 @@
/*
* CPAttributedString+Additions.j
* AppKit
*
* Created by Randy Luecke
* Copyright 2011, RCLConcepts, LLC.
*
* 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
*/
/*
AppKit adds two methods to the CPAttributedString class to support drawing string directly in an CPView.
AppKit also adds similar methods to CPString.
*/
@implementation CPAttributedString (AppKitAdditions)
/*!
Draws a string in the current graphics context.
This method and draws the reciver on a single "infinately long" line.
@param aPoint - The starting point to draw the string
*/
- (void)drawAtPoint:(CGPoint)aPoint
{
var context = [[CPGraphicsContext currentContext] graphicsPort],
line = CTLineCreateWithAttributedString([self copy]);
CGContextSetTextPosition(context, aPoint.x, aPoint.y);
CTLineDraw(line, context);
}
/*!
Draws a string in the current graphics context.
@param aRect - The rect for which the string should be drawn into
*/
- (void)drawInRect:(CGRect)aRect
{
var context = [[CPGraphicsContext currentContext] graphicsPort],
frameSetter = CTFramesetterCreateWithAttributedString([self copy]),
path = CGPathCreateMutable();
CGPathAddRect(path, nil, aRect);
var frame = CTFramesetterCreateFrame(frameSetter, CPMakeRange(0, [self length]), path, nil);
CTFrameDraw(frame, context);
}
@end
+1 -1
View File
@@ -38,7 +38,7 @@ var DefaultLineWidth = 1.0;
@class CPBezierPath
A CPBezierPath allows you to create paths for drawing to the screen using a simpler API than CoreGraphics.
Paths can form any shape, including regular polgyons like squares and triangles; circles, arcs; or complex
Paths can form any shape, including regular polygons like squares and triangles; circles, arcs; or complex
line segments.
A path can be stroked and filled using the relevant method. The currently active fill and stroke color will
+68 -2
View File
@@ -35,6 +35,12 @@ CPLineBorder = 1;
CPBezelBorder = 2;
CPGrooveBorder = 3;
/*!
@ingroup appkit
@class CPBox
A CPBox is a simple view which can display a border.
*/
@implementation CPBox : CPView
{
CPBoxType _boxType;
@@ -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)
@@ -235,8 +301,8 @@ CPGrooveBorder = 3;
switch (_boxType)
{
case CPBoxSeparator:
// NSBox does not include a horitontal flag for the seperator type. We have to determine
// the type of seperator to draw by the width and height of the frame.
// NSBox does not include a horizontal flag for the separator type. We have to determine
// the type of separator to draw by the width and height of the frame.
if (CGRectGetWidth(bounds) === 5.0)
return [self _drawVerticalSeperatorInRect:bounds];
else if (CGRectGetHeight(bounds) === 5.0)
+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
+91 -16
View File
@@ -106,6 +106,11 @@ CPButtonImageOffset = 3.0;
CPString _keyEquivalent;
unsigned _keyEquivalentModifierMask;
CPTimer _continuousDelayTimer;
CPTimer _continuousTimer;
float _periodicDelay;
float _periodicInterval;
}
+ (id)buttonWithTitle:(CPString)aTitle
@@ -152,18 +157,27 @@ CPButtonImageOffset = 3.0;
[self setValue:CPImageLeft forThemeAttribute:@"image-position"];
[self setValue:CPScaleNone forThemeAttribute:@"image-scaling"];
_controlSize = CPRegularControlSize;
_keyEquivalent = @"";
_keyEquivalentModifierMask = 0;
[self setBezelStyle:CPRoundRectBezelStyle];
[self setBordered:YES];
[self _init];
}
return self;
}
- (void)_init
{
_controlSize = CPRegularControlSize;
_keyEquivalent = @"";
_keyEquivalentModifierMask = 0;
// Continuous button defaults.
_periodicInterval = 0.05;
_periodicDelay = 0.5;
}
// Setting the state
/*!
Returns a Boolean value indicating whether the button allows a mixed state.
@@ -450,6 +464,34 @@ CPButtonImageOffset = 3.0;
return _imageDimsWhenDisabled;
}
- (void)setPeriodicDelay:(float)aDelay interval:(float)anInterval
{
_periodicDelay = aDelay;
_periodicInterval = anInterval;
}
- (void)mouseDown:(CPEvent)anEvent
{
if ([self isContinuous])
{
_continuousDelayTimer = [CPTimer scheduledTimerWithTimeInterval:_periodicDelay callback: function()
{
if (!_continuousTimer)
_continuousTimer = [CPTimer scheduledTimerWithTimeInterval:_periodicInterval target:self selector:@selector(onContinousEvent:) userInfo:anEvent repeats:YES];
}
repeats:NO];
}
[super mouseDown:anEvent];
}
- (void)onContinousEvent:(CPTimer)aTimer
{
if (_target && _action && [_target respondsToSelector:_action])
[_target performSelector:_action withObject:self];
}
- (BOOL)startTrackingAt:(CGPoint)aPoint
{
[self highlight:YES];
@@ -460,6 +502,7 @@ CPButtonImageOffset = 3.0;
- (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp
{
[self highlight:NO];
[self invalidateTimers];
[super stopTracking:lastPoint at:aPoint mouseIsUp:mouseIsUp];
@@ -467,6 +510,21 @@ CPButtonImageOffset = 3.0;
[self setNextState];
}
- (void)invalidateTimers
{
if (_continuousTimer)
{
[_continuousTimer invalidate];
_continuousTimer = nil;
}
if (_continuousDelayTimer)
{
[_continuousDelayTimer invalidate];
_continuousDelayTimer = nil;
}
}
- (CGRect)contentRectForBounds:(CGRect)bounds
{
var contentInset = [self currentValueForThemeAttribute:@"content-inset"];
@@ -502,14 +560,9 @@ CPButtonImageOffset = 3.0;
return bounds;
}
/*!
Adjust the size of the button to fit the title and surrounding button image.
*/
- (void)sizeToFit
- (CGSize)_minimumFrameSize
{
[self layoutSubviews];
var size,
var size = CGSizeMakeZero(),
contentView = [self ephemeralSubviewNamed:@"content-view"];
if (contentView)
@@ -533,9 +586,19 @@ CPButtonImageOffset = 3.0;
if (maxSize.height >= 0.0)
size.height = MIN(size.height, maxSize.height);
[self setFrameSize:size];
return size;
}
if (contentView)
/*!
Adjust the size of the button to fit the title and surrounding button image.
*/
- (void)sizeToFit
{
[self layoutSubviews];
[self setFrameSize:[self _minimumFrameSize]];
if ([self ephemeralSubviewNamed:@"content-view"])
[self layoutSubviews];
}
@@ -719,7 +782,9 @@ var CPButtonImageKey = @"CPButtonImageKey",
CPButtonImageDimsWhenDisabledKey = @"CPButtonImageDimsWhenDisabledKey",
CPButtonImagePositionKey = @"CPButtonImagePositionKey",
CPButtonKeyEquivalentKey = @"CPButtonKeyEquivalentKey",
CPButtonKeyEquivalentMaskKey = @"CPButtonKeyEquivalentMaskKey";
CPButtonKeyEquivalentMaskKey = @"CPButtonKeyEquivalentMaskKey",
CPButtonPeriodicDelayKey = @"CPButtonPeriodicDelayKey",
CPButtonPeriodicIntervalKey = @"CPButtonPeriodicIntervalKey";
@implementation CPButton (CPCoding)
@@ -733,7 +798,7 @@ var CPButtonImageKey = @"CPButtonImageKey",
if (self)
{
_controlSize = CPRegularControlSize;
[self _init];
_title = [aCoder decodeObjectForKey:CPButtonTitleKey];
_alternateTitle = [aCoder decodeObjectForKey:CPButtonAlternateTitleKey];
@@ -749,6 +814,12 @@ var CPButtonImageKey = @"CPButtonImageKey",
if ([aCoder containsValueForKey:CPButtonKeyEquivalentKey])
[self setKeyEquivalent:CFData.decodeBase64ToUtf16String([aCoder decodeObjectForKey:CPButtonKeyEquivalentKey])];
if ([aCoder containsValueForKey:CPButtonPeriodicDelayKey])
_periodicDelay = [aCoder decodeObjectForKey:CPButtonPeriodicDelayKey];
if ([aCoder containsValueForKey:CPButtonPeriodicIntervalKey])
_periodicInterval = [aCoder decodeObjectForKey:CPButtonPeriodicIntervalKey];
_keyEquivalentModifierMask = [aCoder decodeIntForKey:CPButtonKeyEquivalentMaskKey];
[self setNeedsLayout];
@@ -765,6 +836,7 @@ var CPButtonImageKey = @"CPButtonImageKey",
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[self invalidateTimers];
[aCoder encodeObject:_title forKey:CPButtonTitleKey];
[aCoder encodeObject:_alternateTitle forKey:CPButtonAlternateTitleKey];
@@ -778,6 +850,9 @@ var CPButtonImageKey = @"CPButtonImageKey",
[aCoder encodeObject:CFData.encodeBase64Utf16String(_keyEquivalent) forKey:CPButtonKeyEquivalentKey];
[aCoder encodeInt:_keyEquivalentModifierMask forKey:CPButtonKeyEquivalentMaskKey];
[aCoder encodeObject:_periodicDelay forKey:CPButtonPeriodicDelayKey];
[aCoder encodeObject:_periodicInterval forKey:CPButtonPeriodicIntervalKey];
}
@end
+83 -5
View File
@@ -131,6 +131,49 @@
/*!
Sets the item prototype to \c anItem
The item prototype should implement the CPCoding protocol
because the item is copied by archiving and unarchiving the
prototypal view.
Example:
<pre>
@implement MyCustomView : CPCollectionViewItem
{
CPArray items @accessors;
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
items = [];
}
return self;
}
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
items = [aCoder decodeObjectForKey:@"KEY"];
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[aCoder encodeObject:items forKey:@"KEY"];
[super encodeWithCoder:aCoder];
}
@end
</pre>
This will allow the collection view to create multiple 'clean' copies
of the item prototype which will maintain the original values for item
and all of the properties archived by the super class.
@param anItem the new item prototype
*/
- (void)setItemPrototype:(CPCollectionViewItem)anItem
@@ -343,7 +386,7 @@
_items = [];
if (!_itemPrototype || !_content)
if (!_itemPrototype)
return;
var index = 0;
@@ -369,7 +412,7 @@
{
var width = CGRectGetWidth([self bounds]);
if (![_content count] || width == _tileWidth)
if (width == _tileWidth)
return;
// We try to fit as many views per row as possible. Any remaining space is then
@@ -589,9 +632,7 @@
_mouseDownEvent = anEvent;
var location = [self convertPoint:[anEvent locationInWindow] fromView:nil],
row = FLOOR(location.y / (_itemSize.height + _verticalMargin)),
column = FLOOR(location.x / (_itemSize.width + _horizontalMargin)),
index = row * _numberOfColumns + column;
index = [self _indexAtPoint:location];
if (index >= 0 && index < _items.length)
{
@@ -727,6 +768,28 @@
return _delegate;
}
/*!
@ignore
*/
- (CPMenu)menuForEvent:(CPEvent)theEvent
{
if (![[self delegate] respondsToSelector:@selector(collectionView:menuForItemAtIndex:)])
return [super menuForEvent:theEvent];
var location = [self convertPoint:[theEvent locationInWindow] fromView:nil],
index = [self _indexAtPoint:location];
return [_delegate collectionView:self menuForItemAtIndex:index];
}
- (int)_indexAtPoint:(CGPoint)thePoint
{
var row = FLOOR(thePoint.y / (_itemSize.height + _verticalMargin)),
column = FLOOR(thePoint.x / (_itemSize.width + _horizontalMargin));
return row * _numberOfColumns + column;
}
- (CPCollectionViewItem)itemAtIndex:(unsigned)anIndex
{
return [_items objectAtIndex:anIndex];
@@ -898,6 +961,21 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeK
@implementation CPCollectionView (CPCoding)
- (void)awakeFromCib
{
[super awakeFromCib];
if (CGSizeEqualToSize(_minItemSize, CGSizeMakeZero()) || CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero()))
{
var item = _itemPrototype;
if (CGSizeEqualToSize(_minItemSize, CGSizeMakeZero()))
_minItemSize = [[item view] frameSize];
else if (CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero()))
_maxItemSize = [[item view] frameSize];
}
}
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
+16 -4
View File
@@ -125,7 +125,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 +416,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 +605,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,7 +616,19 @@ 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
+2 -1
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:)];
+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)
+185 -62
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
@@ -149,6 +146,18 @@ var CPControlBlackColor = [CPColor blackColor];
return [super _binderClassForBinding:theBinding];
}
/*!
Reverse set the binding iff the CPContinuouslyUpdatesValueBindingOption is set.
*/
- (void)_continuouslyReverseSetBinding
{
var binderClass = [[self class] _binderClassForBinding:CPValueBinding],
theBinding = [binderClass getBinding:CPValueBinding forObject:self];
if ([theBinding continuouslyUpdatesValue])
[theBinding reverseSetValueFor:@"objectValue"];
}
- (void)_reverseSetBinding
{
var binderClass = [[self class] _binderClassForBinding:CPValueBinding],
@@ -171,7 +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
@@ -180,7 +190,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Returns the receiver's target action
Returns the receiver's target action.
*/
- (SEL)action
{
@@ -189,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
@@ -206,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
*/
@@ -224,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.
*/
@@ -262,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
@@ -272,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;
@@ -334,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])
@@ -356,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;
@@ -411,7 +411,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Returns the receiver's object value
Returns the receiver's object value.
*/
- (id)objectValue
{
@@ -419,7 +419,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Set's the receiver's object value
Sets the receiver's object value.
*/
- (void)setObjectValue:(id)anObject
{
@@ -430,7 +430,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Returns the receiver's float value
Returns the receiver's float value.
*/
- (float)floatValue
{
@@ -439,7 +439,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Sets the receiver's float value
Sets the receiver's float value.
*/
- (void)setFloatValue:(float)aValue
{
@@ -447,7 +447,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Returns the receiver's double value
Returns the receiver's double value.
*/
- (double)doubleValue
{
@@ -456,7 +456,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Set's the receiver's double value
Sets the receiver's double value.
*/
- (void)setDoubleValue:(double)anObject
{
@@ -464,7 +464,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Returns the receiver's int value
Returns the receiver's int value.
*/
- (int)intValue
{
@@ -473,7 +473,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Set's the receiver's int value
Sets the receiver's int value.
*/
- (void)setIntValue:(int)anObject
{
@@ -481,7 +481,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Returns the receiver's int value
Returns the receiver's int value.
*/
- (int)integerValue
{
@@ -490,7 +490,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Set's the receiver's int value
Sets the receiver's int value.
*/
- (void)setIntegerValue:(int)anObject
{
@@ -498,7 +498,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Returns the receiver's string value
Returns the receiver's string value.
*/
- (CPString)stringValue
{
@@ -506,7 +506,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Set's the receiver's string value
Sets the receiver's string value.
*/
- (void)setStringValue:(CPString)anObject
{
@@ -582,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)
@@ -680,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)
@@ -698,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];
@@ -721,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
*/
@@ -744,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
@@ -753,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
+2 -2
View File
@@ -24,7 +24,7 @@
@import <Foundation/CPBundle.j>
@import "CPDocument.j"
@import "CPOpenPanel.j";
@import "CPOpenPanel.j"
var CPSharedDocumentController = nil;
@@ -177,7 +177,7 @@ var CPSharedDocumentController = nil;
@param aType the document type
@param aDelegate the delegate to notify
@param aSelector the selector to notify with
@param aContextInfo the context infomration passed to the delegate
@param aContextInfo the context information passed to the delegate
*/
- (CPDocument)makeDocumentWithContentsOfURL:(CPURL)anAbsoluteURL ofType:(CPString)aType delegate:(id)aDelegate didReadSelector:(SEL)aSelector contextInfo:(id)aContextInfo
{
+23 -19
View File
@@ -28,13 +28,13 @@
@import "CPWindow.j"
CPDragOperationNone = 0,
CPDragOperationCopy = 1 << 1,
CPDragOperationLink = 1 << 1,
CPDragOperationGeneric = 1 << 2,
CPDragOperationPrivate = 1 << 3,
CPDragOperationMove = 1 << 4,
CPDragOperationDelete = 1 << 5,
CPDragOperationNone = 0;
CPDragOperationCopy = 1 << 1;
CPDragOperationLink = 1 << 1;
CPDragOperationGeneric = 1 << 2;
CPDragOperationPrivate = 1 << 3;
CPDragOperationMove = 1 << 4;
CPDragOperationDelete = 1 << 5;
CPDragOperationEvery = -1;
#define DRAGGING_WINDOW(anObject) ([anObject isKindOfClass:[CPWindow class]] ? anObject : [anObject window])
@@ -44,8 +44,8 @@ var CPDragServerPreviousEvent = nil,
var CPSharedDragServer = nil;
var CPDragServerSource = nil;
var CPDragServerDraggingInfo = nil;
var CPDragServerSource = nil,
CPDragServerDraggingInfo = nil;
/*
CPDraggingInfo is a container of information about a specific dragging session.
@@ -261,7 +261,7 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
{
var contentView = [scrollView contentView],
bounds = [contentView bounds],
insetBounds = CGRectInset(bounds, 10, 10),
insetBounds = CGRectInset(bounds, 30, 30),
eventLocation = [contentView convertPoint:_draggingLocation fromView:nil],
deltaX = 0,
deltaY = 0;
@@ -270,10 +270,10 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
{
if ([scrollView hasVerticalScroller])
{
if (eventLocation.y < CGRectGetMinY(insetBounds))
deltaY = CGRectGetMinY(insetBounds) - eventLocation.y;
else if (eventLocation.y > CGRectGetMaxY(insetBounds))
deltaY = CGRectGetMaxY(insetBounds) - eventLocation.y;
if (eventLocation.y < _CGRectGetMinY(insetBounds))
deltaY = _CGRectGetMinY(insetBounds) - eventLocation.y;
else if (eventLocation.y > _CGRectGetMaxY(insetBounds))
deltaY = _CGRectGetMaxY(insetBounds) - eventLocation.y;
if (deltaY < -insetBounds.size.height)
deltaY = -insetBounds.size.height;
if (deltaY > insetBounds.size.height)
@@ -282,17 +282,21 @@ var CPDraggingSource_draggedImage_movedTo_ = 1 << 0,
if ([scrollView hasHorizontalScroller])
{
if (eventLocation.x < CGRectGetMinX(insetBounds))
deltaX = CGRectGetMinX(insetBounds) - eventLocation.x;
else if (eventLocation.x > CGRectGetMaxX(insetBounds))
deltaX = CGRectGetMaxX(insetBounds) - eventLocation.x;
if (eventLocation.x < _CGRectGetMinX(insetBounds))
deltaX = _CGRectGetMinX(insetBounds) - eventLocation.x;
else if (eventLocation.x > _CGRectGetMaxX(insetBounds))
deltaX = _CGRectGetMaxX(insetBounds) - eventLocation.x;
if (deltaX < -insetBounds.size.width)
deltaX = -insetBounds.size.width;
if (deltaX > insetBounds.size.width)
deltaX = insetBounds.size.width;
}
[contentView scrollToPoint:CGPointMake(bounds.origin.x - deltaX, bounds.origin.y - deltaY)];
var scrollPoint = _CGPointMake(bounds.origin.x - deltaX, bounds.origin.y - deltaY);
[contentView scrollToPoint:scrollPoint];
[[scrollView _headerView] scrollPoint:scrollPoint];
}
}
}
+54 -40
View File
@@ -161,21 +161,21 @@ CPEscapeFunctionKey = "\u001B";
CPSpaceFunctionKey = "\u0020";
CPDOMEventDoubleClick = "dblclick",
CPDOMEventMouseDown = "mousedown",
CPDOMEventMouseUp = "mouseup",
CPDOMEventMouseMoved = "mousemove",
CPDOMEventMouseDragged = "mousedrag",
CPDOMEventKeyUp = "keyup",
CPDOMEventKeyDown = "keydown",
CPDOMEventKeyPress = "keypress";
CPDOMEventCopy = "copy";
CPDOMEventPaste = "paste";
CPDOMEventScrollWheel = "mousewheel";
CPDOMEventTouchStart = "touchstart";
CPDOMEventTouchMove = "touchmove";
CPDOMEventTouchEnd = "touchend";
CPDOMEventTouchCancel = "touchcancel";
CPDOMEventDoubleClick = "dblclick";
CPDOMEventMouseDown = "mousedown";
CPDOMEventMouseUp = "mouseup";
CPDOMEventMouseMoved = "mousemove";
CPDOMEventMouseDragged = "mousedrag";
CPDOMEventKeyUp = "keyup";
CPDOMEventKeyDown = "keydown";
CPDOMEventKeyPress = "keypress";
CPDOMEventCopy = "copy";
CPDOMEventPaste = "paste";
CPDOMEventScrollWheel = "mousewheel";
CPDOMEventTouchStart = "touchstart";
CPDOMEventTouchMove = "touchmove";
CPDOMEventTouchEnd = "touchend";
CPDOMEventTouchCancel = "touchcancel";
var _CPEventPeriodicEventPeriod = 0,
_CPEventPeriodicEventTimer = nil,
@@ -211,6 +211,7 @@ var _CPEventPeriodicEventPeriod = 0,
/*!
Creates a new keyboard event.
@param anEventType the event type. Must be one of CPKeyDown, CPKeyUp or CPFlagsChanged
@param aPoint the location of the cursor in the window specified by \c aWindowNumber
@param modifierFlags a bitwise combination of the modifiers specified in the CPEvent globals
@@ -235,7 +236,8 @@ var _CPEventPeriodicEventPeriod = 0,
}
/*!
Creates a new mouse event
Creates a new mouse event.
@param anEventType the event type
@param aPoint the location of the cursor in the window specified by \c aWindowNumber
@param modifierFlags a bitwise combination of the modifiers specified in the CPEvent globals
@@ -257,7 +259,8 @@ var _CPEventPeriodicEventPeriod = 0,
}
/*!
Creates a new custom event
Creates a new custom event.
@param anEventType the event type. Must be one of CPAppKitDefined, CPSystemDefined, CPApplicationDefined or CPPeriodic
@param aLocation the location of the cursor in the window specified by \c aWindowNumber
@param modifierFlags a bitwise combination of the modifiers specified in the CPEvent globals
@@ -278,16 +281,28 @@ var _CPEventPeriodicEventPeriod = 0,
timestamp:aTimestamp windowNumber:aWindowNumber context:aGraphicsContext subtype:aSubtype data1:aData1 data2:aData2];
}
- (id)_initWithType:(CPEventType)anEventType
{
if (self = [super init])
{
_type = anEventType;
// Make sure these are 0 rather than nil.
_deltaX = 0;
_deltaY = 0;
_deltaZ = 0;
}
return self;
}
/* @ignore */
- (id)_initMouseEventWithType:(CPEventType)anEventType location:(CPPoint)aPoint modifierFlags:(unsigned)modifierFlags
timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
eventNumber:(int)anEventNumber clickCount:(int)aClickCount pressure:(float)aPressure
{
self = [super init];
if (self)
if (self = [self _initWithType:anEventType])
{
_type = anEventType;
_location = CPPointCreateCopy(aPoint);
_modifierFlags = modifierFlags;
_timestamp = aTimestamp;
@@ -306,11 +321,8 @@ var _CPEventPeriodicEventPeriod = 0,
timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
characters:(CPString)characters charactersIgnoringModifiers:(CPString)unmodCharacters isARepeat:(BOOL)isARepeat keyCode:(unsigned short)code
{
self = [super init];
if (self)
if (self = [self _initWithType:anEventType])
{
_type = anEventType;
_location = CPPointCreateCopy(aPoint);
_modifierFlags = modifierFlags;
_timestamp = aTimestamp;
@@ -330,11 +342,8 @@ var _CPEventPeriodicEventPeriod = 0,
timestamp:(CPTimeInterval)aTimestamp windowNumber:(int)aWindowNumber context:(CPGraphicsContext)aGraphicsContext
subtype:(short)aSubtype data1:(int)aData1 data2:(int)aData2
{
self = [super init];
if (self)
if (self = [self _initWithType:anEventType])
{
_type = anEventType;
_location = CPPointCreateCopy(aPoint);
_modifierFlags = modifierFlags;
_timestamp = aTimestamp;
@@ -349,10 +358,10 @@ var _CPEventPeriodicEventPeriod = 0,
/*!
Returns the location of the mouse (for mouse events).
If this is not a mouse event, it returns \c nil.
If \c window returns \c nil, then
the mouse coordinates will be based on the screen coordinates.
If the receiver is not a mouse event, it returns \c nil.
If \c window returns \c nil, then the mouse coordinates will be based on the screen coordinates.
Otherwise, the coordinates are relative to the window's coordinates.
@return the location of the mouse, or \c nil for non-mouse events.
*/
- (CGPoint)locationInWindow
@@ -372,7 +381,7 @@ var _CPEventPeriodicEventPeriod = 0,
}
/*!
Returns event information as a bit mask
Returns event information as a bit mask.
*/
- (unsigned)modifierFlags
{
@@ -380,7 +389,7 @@ var _CPEventPeriodicEventPeriod = 0,
}
/*!
Returns the time the event occurred
Returns the time the event occurred.
*/
- (CPTimeInterval)timestamp
{
@@ -396,7 +405,7 @@ var _CPEventPeriodicEventPeriod = 0,
}
/*!
Returns the event's associated window
Returns the event's associated window.
*/
- (CPWindow)window
{
@@ -427,7 +436,7 @@ var _CPEventPeriodicEventPeriod = 0,
}
/*!
Returns the number of clicks that caused this event. (mouse only)
Returns the number of clicks that caused this event (mouse only).
*/
- (int)clickCount
{
@@ -435,7 +444,8 @@ var _CPEventPeriodicEventPeriod = 0,
}
/*!
Returns the characters associated with this event (keyboard only)
Returns the characters associated with this event (keyboard only).
@throws CPInternalInconsistencyException if this method is called on a non-key event
*/
- (CPString)characters
@@ -445,6 +455,7 @@ var _CPEventPeriodicEventPeriod = 0,
/*!
Returns the character ignoring any modifiers (except shift).
@throws CPInternalInconsistencyException if this method is called on a non-key event
*/
- (CPString)charactersIgnoringModifiers
@@ -454,6 +465,7 @@ var _CPEventPeriodicEventPeriod = 0,
/*!
Returns \c YES if the keyboard event was caused by the key being held down.
@throws CPInternalInconsistencyException if this method is called on a non-key event
*/
- (BOOL)isARepeat
@@ -463,6 +475,7 @@ var _CPEventPeriodicEventPeriod = 0,
/*!
Returns the key's key code.
@throws CPInternalInconsistencyException if this method is called on a non-key event
*/
- (unsigned short)keyCode
@@ -495,7 +508,7 @@ var _CPEventPeriodicEventPeriod = 0,
return _DOMEvent;
}
// Getting Scroll Wheel Event Infomration
// Getting Scroll Wheel Event Information
/*!
Returns the change in the x-axis for a mouse event.
*/
@@ -586,7 +599,8 @@ var _CPEventPeriodicEventPeriod = 0,
}
/*!
Gene rates periodic events every \c aPeriod seconds.
Generates periodic events every \c aPeriod seconds.
@param aDelay the number of seconds before the first event
@param aPeriod the length of time in seconds between successive events
*/
@@ -599,7 +613,7 @@ var _CPEventPeriodicEventPeriod = 0,
}
/*!
Stops the periodic events from being generated
Stops the periodic events from being generated.
*/
+ (void)stopPeriodicEvents
{
+5 -2
View File
@@ -134,7 +134,10 @@ var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
_DOMObjectElement.removeChild([elements objectAtIndex:i]);
}
#endif
_params = aDictionary;
if (!_params)
_params = aDictionary;
else
[_params addEntriesFromDictionary:aDictionary];
#if PLATFORM(DOM)
if (!CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
{
@@ -143,7 +146,7 @@ var IEFlashCLSID = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
var enumerator = [_params keyEnumerator],
key;
while (key = [enumerator nextObject] && _DOMObjectElement)
while (_DOMObjectElement && (key = [enumerator nextObject]))
{
var param = document.createElement(@"param");
param.name = key;
+186 -29
View File
@@ -25,20 +25,49 @@
@import "CPView.j"
CPFontDefaultSystemFontFace = @"Arial, sans-serif";
CPFontDefaultSystemFontSize = 12;
var _CPFonts = {},
_CPFontSystemFontFace = @"Arial, sans-serif",
_CPWrapRegExp = new RegExp("\\s*,\\s*", "g");
var _CPFonts = {},
_CPFontSystemFontFace = CPFontDefaultSystemFontFace,
_CPFontSystemFontSize = 12,
_CPFontFallbackFaces = CPFontDefaultSystemFontFace.split(", "),
_CPFontStripRegExp = new RegExp("(^\\s*[\"']?|[\"']?\\s*$)", "g");
#define _CPCreateCSSString(aName, aSize, isBold) (isBold ? @"bold " : @"") + ROUND(aSize) + @"px " + ((aName === _CPFontSystemFontFace) ? aName : (@"\"" + aName.replace(_CPWrapRegExp, '", "') + @"\", " + _CPFontSystemFontFace))
#define _CPCachedFont(aName, aSize, isBold) _CPFonts[_CPCreateCSSString(aName, aSize, isBold)]
#define _CPFontNormalizedNames(aName) _CPFontNormalizedNameArray(aName).join(", ")
#define _CPCachedFont(aName, aSize, isBold, isItalic) _CPFonts[_CPFontCreateCSSString(_CPFontNormalizedNames(aName), aSize, isBold, isItalic)]
/*!
@ingroup appkit
@class CPFont
The CPFont class allows control of the fonts used for displaying text anywhere on the screen. The primary method for getting a particular font is through one of the class methods that take a name and/or size as arguments, and return the appropriate CPFont.
The CPFont class allows control of the fonts used for displaying text anywhere on the screen.
The primary method for getting a particular font is through one of the class methods that take
a name and/or size as arguments, and return the appropriate CPFont.
By default the system font face/size is Arial 12px, with a fallback to sans-serif. You may
configure this at runtime in two ways:
- By sending [CPFont @link CPFont::setSystemFontFace: setSystemFontFace:@endlink] and/or [CPFont @link CPFont::setSystemFontSize: setSystemFontSize:@endlink].
- By configuring Info.plist for your application or for AppKit. You can set the font face
by adding a CPSystemFontFace string item to the Info.plist, and you can set the font size
by adding a CPSystemFontSize integer item to the Info.plist.
Note that in either case, you can specify a comma-delimited list of fonts as the font face.
The browser will use the first available font in the list. CPFont always ensures that Arial
and sans-serif are in the generated CSS string, so there is no need to add them to the end
of your font list.
If you are using nib2cib, you should use the second method (using Info.plist),
and be sure to run nib2cib again any time you modify the CPSystemFontFace or CPSystemFontSize items.
For example, you might add this to your application's Info.plist to set the system font to Lucida Grande,
with an automatic fallback to Arial or sans-serif:
@code
<key>CPSystemFontFace</key>
<string>Lucida Grande</string>
@endcode
*/
@implementation CPFont : CPObject
{
@@ -47,78 +76,153 @@ var _CPFonts = {},
float _ascender;
float _descender;
float _lineHeight;
BOOL _isBold;
BOOL _isBold @accessors(readonly, getter=isBold);
BOOL _isItalic @accessors(readonly, getter=isItalic);
CPString _cssString;
}
+ (void)initialize
{
var systemFont = [[CPBundle bundleForClass:[CPView class]] objectForInfoDictionaryKey:"CPSystemFontFace"];
var systemFontFace = [[CPBundle mainBundle] objectForInfoDictionaryKey:@"CPSystemFontFace"];
if (systemFont)
_CPFontSystemFontFace = systemFont;
if (!systemFontFace)
systemFontFace = [[CPBundle bundleForClass:[CPView class]] objectForInfoDictionaryKey:@"CPSystemFontFace"];
if (systemFontFace)
[self setSystemFontFace:systemFontFace];
var systemFontSize = [[CPBundle mainBundle] objectForInfoDictionaryKey:@"CPSystemFontSize"];
if (!systemFontSize)
systemFontSize = [[CPBundle bundleForClass:[CPView class]] objectForInfoDictionaryKey:@"CPSystemFontSize"];
if (systemFontSize)
_CPFontSystemFontSize = systemFontSize;
}
/*!
Returns the default system font face, which may consist of several comma-separated family names.
*/
+ (CPString)systemFontFace
{
return _CPFontSystemFontFace;
}
/*!
Sets the default system font face, which may consist of several comma-separated family names.
*/
+ (CPString)setSystemFontFace:(CPString)aFace
{
_CPFontSystemFontFace = _CPFontNormalizedNames(aFace);
}
/*!
Returns the default system font size.
*/
+ (float)systemFontSize
{
return _CPFontSystemFontSize;
}
/*!
Sets the default system font size.
*/
+ (float)setSystemFontSize:(float)size
{
if (size > 0)
_CPFontSystemFontSize = size;
}
/*!
Returns a font with the specified name and size.
@param aName the name of the font
@param aSize the size of the font (in points)
@param aSize the size of the font (in px)
@return the requested font
*/
+ (CPFont)fontWithName:(CPString)aName size:(float)aSize
{
return _CPCachedFont(aName, aSize, NO) || [[CPFont alloc] _initWithName:aName size:aSize bold:NO];
return _CPCachedFont(aName, aSize, NO, NO) || [[CPFont alloc] _initWithName:aName size:aSize bold:NO italic:NO];
}
/*!
Returns a font with the specified name, size and style.
@param aName the name of the font
@param aSize the size of the font (in px)
@param italic whether the font should be italicized
@return the requested font
*/
+ (CPFont)fontWithName:(CPString)aName size:(float)aSize italic:(BOOL)italic
{
return _CPCachedFont(aName, aSize, NO, NO) || [[CPFont alloc] _initWithName:aName size:aSize bold:NO italic:italic];
}
/*!
Returns a bold font with the specified name and size.
@param aName the name of the font
@param aSize the size of the font (in points)
@param aSize the size of the font (in px)
@return the requested bold font
*/
+ (CPFont)boldFontWithName:(CPString)aName size:(float)aSize
{
return _CPCachedFont(aName, aSize, YES) || [[CPFont alloc] _initWithName:aName size:aSize bold:YES];
return _CPCachedFont(aName, aSize, YES, NO) || [[CPFont alloc] _initWithName:aName size:aSize bold:YES italic:NO];
}
/*!
Returns a bold font with the specified name, size and style.
@param aName the name of the font
@param aSize the size of the font (in px)
@param italic whether the font should be italicized
@return the requested font
*/
+ (CPFont)boldFontWithName:(CPString)aName size:(float)aSize italic:(BOOL)italic
{
return _CPCachedFont(aName, aSize, NO, NO) || [[CPFont alloc] _initWithName:aName size:aSize bold:YES italic:italic];
}
/*!
Returns the system font scaled to the specified size
@param aSize the size of the font (in points)
@param aSize the size of the font (in px)
@return the requested system font
*/
+ (CPFont)systemFontOfSize:(CPSize)aSize
{
return _CPCachedFont(_CPFontSystemFontFace, aSize, NO) || [[CPFont alloc] _initWithName:_CPFontSystemFontFace size:aSize bold:NO];
return _CPCachedFont(_CPFontSystemFontFace, aSize, NO, NO) || [[CPFont alloc] _initWithName:_CPFontSystemFontFace size:aSize bold:NO italic:NO];
}
/*!
Returns the bold system font scaled to the specified size
@param aSize the size of the font (in points)
@param aSize the size of the font (in px)
@return the requested bold system font
*/
+ (CPFont)boldSystemFontOfSize:(CPSize)aSize
{
return _CPCachedFont(_CPFontSystemFontFace, aSize, YES) || [[CPFont alloc] _initWithName:_CPFontSystemFontFace size:aSize bold:YES];
return _CPCachedFont(_CPFontSystemFontFace, aSize, YES, NO) || [[CPFont alloc] _initWithName:_CPFontSystemFontFace size:aSize bold:YES italic:NO];
}
/* FIXME Font Descriptor
@ignore
*/
- (id)_initWithName:(CPString)aName size:(float)aSize bold:(BOOL)isBold
{
return [self _initWithName:aName size:aSize bold:isBold italic:NO];
}
- (id)_initWithName:(CPString)aName size:(float)aSize bold:(BOOL)isBold italic:(BOOL)isItalic
{
self = [super init];
if (self)
{
_name = aName;
_name = _CPFontNormalizedNames(aName);
_size = aSize;
_ascender = 0;
_descender = 0;
_lineHeight = 0;
_isBold = isBold;
_isItalic = isItalic;
_cssString = _CPCreateCSSString(_name, _size, _isBold);
_cssString = _CPFontCreateCSSString(_name, _size, _isBold, _isItalic);
_CPFonts[_cssString] = self;
}
@@ -139,7 +243,7 @@ var _CPFonts = {},
/*!
Returns the bottom y coordinate (in CSS px), offset from the baseline, of the receiver's longest descender.
Thus, if the longest descender extends 2 points below the baseline, descender will return 2.
Thus, if the longest descender extends 2 px below the baseline, descender will return 2.
*/
- (float)descender
{
@@ -188,12 +292,17 @@ var _CPFonts = {},
- (BOOL)isEqual:(id)anObject
{
return [anObject isKindOfClass:[CPFont class]] && [anObject cssString] === [self cssString];
return [anObject isKindOfClass:[CPFont class]] && [anObject cssString] === _cssString;
}
- (CPString)description
{
return [CPString stringWithFormat:@"%@ %@ %f pt.", [super description], [self familyName], [self size]];
return [CPString stringWithFormat:@"%@ %@", [super description], [self cssString]];
}
- (id)copy
{
return [[CPFont alloc] _initWithName:_name size:_size bold:_isBold italic:_isItalic];
}
- (void)_getMetrics
@@ -207,9 +316,10 @@ var _CPFonts = {},
@end
var CPFontNameKey = @"CPFontNameKey",
CPFontSizeKey = @"CPFontSizeKey",
CPFontIsBoldKey = @"CPFontIsBoldKey";
var CPFontNameKey = @"CPFontNameKey",
CPFontSizeKey = @"CPFontSizeKey",
CPFontIsBoldKey = @"CPFontIsBoldKey",
CPFontIsItalicKey = @"CPFontIsItalicKey";
@implementation CPFont (CPCoding)
@@ -220,9 +330,12 @@ var CPFontNameKey = @"CPFontNameKey",
*/
- (id)initWithCoder:(CPCoder)aCoder
{
return [self _initWithName:[aCoder decodeObjectForKey:CPFontNameKey]
size:[aCoder decodeFloatForKey:CPFontSizeKey]
bold:[aCoder decodeBoolForKey:CPFontIsBoldKey]];
var fontName = [aCoder decodeObjectForKey:CPFontNameKey],
size = [aCoder decodeFloatForKey:CPFontSizeKey],
isBold = [aCoder decodeBoolForKey:CPFontIsBoldKey],
isItalic = [aCoder decodeBoolForKey:CPFontIsItalicKey];
return [self _initWithName:fontName size:size bold:isBold italic:isItalic];
}
/*!
@@ -234,6 +347,50 @@ var CPFontNameKey = @"CPFontNameKey",
[aCoder encodeObject:_name forKey:CPFontNameKey];
[aCoder encodeFloat:_size forKey:CPFontSizeKey];
[aCoder encodeBool:_isBold forKey:CPFontIsBoldKey];
[aCoder encodeBool:_isItalic forKey:CPFontIsItalicKey];
}
@end
// aName must be normalized
var _CPFontCreateCSSString = function(aName, aSize, isBold, isItalic)
{
var properties = (isItalic ? "italic " : "") + (isBold ? "bold " : "") + aSize + "px ";
return properties + _CPFontConcatNameWithFallback(aName);
};
var _CPFontConcatNameWithFallback = function(aName)
{
var names = _CPFontNormalizedNameArray(aName),
fallbackFaces = _CPFontFallbackFaces.slice(0);
// Remove the fallback names used in the names passed in
for (var i = 0; i < names.length; ++i)
{
for (var j = 0; j < fallbackFaces.length; ++j)
{
if (names[i].toLowerCase() === fallbackFaces[j].toLowerCase())
{
fallbackFaces.splice(j, 1);
break;
}
}
if (names[i].indexOf(" ") > 0)
names[i] = '"' + names[i] + '"';
}
return names.concat(fallbackFaces).join(", ");
};
var _CPFontNormalizedNameArray = function(aName)
{
var names = aName.split(",");
for (var i = 0; i < names.length; ++i)
names[i] = names[i].replace(_CPFontStripRegExp, "");
return names;
};
+2 -2
View File
@@ -25,7 +25,7 @@
@import "CGContext.j"
var CPGraphicsContextCurrent = nil;
var CPGraphicsContextCurrent = nil;
/*!
@ingroup appkit
@@ -33,7 +33,7 @@ var CPGraphicsContextCurrent = nil;
*/
@implementation CPGraphicsContext : CPObject
{
CPContext _graphicsPort;
CGContext _graphicsPort;
}
/*!
+61 -14
View File
@@ -39,6 +39,8 @@ var CPBindingOperationAnd = 0,
{
CPDictionary _info;
id _source;
JSObject _suppressedNotifications;
}
+ (void)exposeBinding:(CPString)aBinding forClass:(Class)aClass
@@ -122,6 +124,7 @@ var CPBindingOperationAnd = 0,
{
_source = aSource;
_info = [CPDictionary dictionaryWithObjects:[aDestination, aKeyPath] forKeys:[CPObservedObjectKey, CPObservedKeyPathKey]];
_suppressedNotifications = {};
if (options)
[_info setObject:options forKey:CPOptionsKey];
@@ -169,15 +172,15 @@ var CPBindingOperationAnd = 0,
if (!changes)
return;
var objectSuppressions = _suppressedNotifications[[anObject UID]];
if (objectSuppressions && objectSuppressions[aKeyPath])
return;
[self setValueFor:context];
}
- (id)transformValue:(id)aValue withOptions:(CPDictionary)options
{
var valueTransformerName,
valueTransformer,
placeholder;
var valueTransformerName = [options objectForKey:CPValueTransformerNameBindingOption],
valueTransformer;
@@ -224,6 +227,50 @@ var CPBindingOperationAnd = 0,
return aValue;
}
- (BOOL)continuouslyUpdatesValue
{
var options = [_info objectForKey:CPOptionsKey];
return [[options objectForKey:CPContinuouslyUpdatesValueBindingOption] boolValue];
}
- (BOOL)handlesContentAsCompoundValue
{
var options = [_info objectForKey:CPOptionsKey];
return [[options objectForKey:CPHandlesContentAsCompoundValueBindingOption] boolValue];
}
/*!
Use this to avoid reacting to the notifications coming out of a reverseTransformedValue:.
*/
- (void)suppressSpecificNotificationFromObject:(id)anObject keyPath:(CPString)aKeyPath
{
if (!anObject)
return;
var uid = [anObject UID],
objectSuppressions = _suppressedNotifications[uid];
if (!objectSuppressions)
_suppressedNotifications[uid] = objectSuppressions = {};
objectSuppressions[aKeyPath] = YES;
}
/*!
Use this to cancel suppressSpecificNotificationFromObject:keyPath:.
*/
- (void)unsuppressSpecificNotificationFromObject:(id)anObject keyPath:(CPString)aKeyPath
{
if (!anObject)
return;
var uid = [anObject UID],
objectSuppressions = _suppressedNotifications[uid];
if (!objectSuppressions)
return;
delete objectSuppressions[aKeyPath];
}
@end
@implementation CPObject (KeyValueBindingCreation)
@@ -233,7 +280,6 @@ var CPBindingOperationAnd = 0,
[CPBinder exposeBinding:aBinding forClass:[self class]];
}
+ (Class)_binderClassForBinding:(CPString)theBinding
{
return [CPBinder class];
@@ -430,16 +476,17 @@ CPOptionsKey = @"CPOptionsKey";
CPMultipleValuesMarker = @"CPMultipleValuesMarker";
CPNoSelectionMarker = @"CPNoSelectionMarker";
CPNotApplicableMarker = @"CPNotApplicableMarker";
CPNullMarker = @"CPNullMarker";
// Binding name constants
CPAlignmentBinding = @"CPAlignmentBinding";
CPEditableBinding = @"CPEditableBinding";
CPEnabledBinding = @"CPEnabledBinding";
CPFontBinding = @"CPFontBinding";
CPHiddenBinding = @"CPHiddenBinding";
CPSelectedIndexBinding = @"CPSelectedIndexBinding";
CPTextColorBinding = @"CPTextColorBinding";
CPToolTipBinding = @"CPToolTipBinding";
CPAlignmentBinding = @"alignment";
CPEditableBinding = @"editable";
CPEnabledBinding = @"enabled";
CPFontBinding = @"font";
CPHiddenBinding = @"hidden";
CPSelectedIndexBinding = @"selectedIndex";
CPTextColorBinding = @"textColor";
CPToolTipBinding = @"toolTip";
CPValueBinding = @"value";
//Binding options constants
@@ -470,5 +517,5 @@ CPValueTransformerBindingOption = @"CPValueTransformer";
CPIsControllerMarker = function(/*id*/anObject)
{
return anObject === CPMultipleValuesMarker || anObject === CPNoSelectionMarker || anObject === CPNotApplicableMarker;
return anObject === CPMultipleValuesMarker || anObject === CPNoSelectionMarker || anObject === CPNotApplicableMarker || anObject === CPNullMarker;
}
+412
View File
@@ -0,0 +1,412 @@
/*
* CPLevelIndicator.j
* AppKit
*
* Created by Alexander Ljungberg.
* Copyright 2011, WireLoad Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPControl.j"
CPTickMarkBelow = 0;
CPTickMarkAbove = 1;
CPTickMarkLeft = CPTickMarkAbove;
CPTickMarkRight = CPTickMarkBelow;
CPRelevancyLevelIndicatorStyle = 0;
CPContinuousCapacityLevelIndicatorStyle = 1;
CPDiscreteCapacityLevelIndicatorStyle = 2;
CPRatingLevelIndicatorStyle = 3;
var _CPLevelIndicatorBezelColor = nil,
_CPLevelIndicatorSegmentEmptyColor = nil,
_CPLevelIndicatorSegmentNormalColor = nil,
_CPLevelIndicatorSegmentWarningColor = nil,
_CPLevelIndicatorSegmentCriticalColor = nil,
_CPLevelIndicatorSpacing = 1;
/*!
@ingroup appkit
@class CPLevelIndicator
CPLevelIndicator is a control which indicates a value visually on a scale.
*/
@implementation CPLevelIndicator : CPControl
{
CPLevelIndicator _levelIndicatorStyle @accessors(property=levelIndicatorStyle);
double _minValue @accessors(property=minValue);
double _maxValue @accessors(property=maxValue);
double _warningValue @accessors(property=warningValue);
double _criticalValue @accessors(property=criticalValue);
CPTickMarkPosition _tickMarkPosition @accessors(property=tickMarkPosition);
int _numberOfTickMarks @accessors(property=numberOfTickMarks);
int _numberOfMajorTickMarks @accessors(property=numberOfMajorTickMarks);
BOOL _isEditable;
BOOL _isTracking;
}
+ (void)initialize
{
var bundle = [CPBundle bundleForClass:CPLevelIndicator];
_CPLevelIndicatorBezelColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-bezel-left.png"] size:CGSizeMake(3.0, 18.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-bezel-center.png"] size:CGSizeMake(1.0, 18.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-bezel-right.png"] size:CGSizeMake(3.0, 18.0)]
]
isVertical:NO
]];
_CPLevelIndicatorSegmentEmptyColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-empty-left.png"] size:CGSizeMake(3.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-empty-center.png"] size:CGSizeMake(1.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-empty-right.png"] size:CGSizeMake(3.0, 17.0)]
]
isVertical:NO
]];
_CPLevelIndicatorSegmentNormalColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-normal-left.png"] size:CGSizeMake(3.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-normal-center.png"] size:CGSizeMake(1.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-normal-right.png"] size:CGSizeMake(3.0, 17.0)]
]
isVertical:NO
]];
_CPLevelIndicatorSegmentWarningColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-warning-left.png"] size:CGSizeMake(3.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-warning-center.png"] size:CGSizeMake(1.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-warning-right.png"] size:CGSizeMake(3.0, 17.0)]
]
isVertical:NO
]];
_CPLevelIndicatorSegmentCriticalColor = [CPColor colorWithPatternImage:[[CPThreePartImage alloc] initWithImageSlices:
[
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-critical-left.png"] size:CGSizeMake(3.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-critical-center.png"] size:CGSizeMake(1.0, 17.0)],
[[CPImage alloc] initWithContentsOfFile:[bundle pathForResource:@"CPLevelIndicator/level-indicator-segment-critical-right.png"] size:CGSizeMake(3.0, 17.0)]
]
isVertical:NO
]];
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
_levelIndicatorStyle = CPDiscreteCapacityLevelIndicatorStyle;
_maxValue = 2;
_warningValue = 2;
_criticalValue = 2;
[self _init];
}
return self;
}
- (void)_init
{
}
- (void)layoutSubviews
{
var bezelView = [self layoutEphemeralSubviewNamed:"bezel"
positioned:CPWindowBelow
relativeToEphemeralSubviewNamed:nil];
// TODO Make themable.
[bezelView setBackgroundColor:_CPLevelIndicatorBezelColor];
var segmentCount = _maxValue - _minValue;
if (segmentCount <= 0)
return;
var filledColor = _CPLevelIndicatorSegmentNormalColor,
value = [self doubleValue];
if (value < _criticalValue)
filledColor = _CPLevelIndicatorSegmentCriticalColor;
else if (value < _warningValue)
filledColor = _CPLevelIndicatorSegmentWarningColor;
for (var i = 0; i < segmentCount; i++)
{
var segmentView = [self layoutEphemeralSubviewNamed:"segment-bezel-" + i
positioned:CPWindowAbove
relativeToEphemeralSubviewNamed:bezelView];
[segmentView setBackgroundColor:(_minValue + i) < value ? filledColor : _CPLevelIndicatorSegmentEmptyColor];
}
}
- (CPView)createEphemeralSubviewNamed:(CPString)aName
{
return [[CPView alloc] initWithFrame:_CGRectMakeZero()];
}
- (CGRect)rectForEphemeralSubviewNamed:(CPString)aViewName
{
// TODO Put into theme attributes.
var bezelHeight = 18,
segmentHeight = 17,
bounds = _CGRectCreateCopy([self bounds]);
if (aViewName == "bezel")
{
bounds.origin.y = (_CGRectGetHeight(bounds) - bezelHeight) / 2.0;
bounds.size.height = bezelHeight;
return bounds;
}
else if (aViewName.indexOf("segment-bezel") === 0)
{
var segment = parseInt(aViewName.substring("segment-bezel-".length), 10),
segmentCount = _maxValue - _minValue;
if (segment >= segmentCount)
return _CGRectMakeZero();
var basicSegmentWidth = bounds.size.width / segmentCount,
segmentFrame = CGRectCreateCopy([self bounds]);
segmentFrame.origin.y = (_CGRectGetHeight(bounds) - bezelHeight) / 2.0;
segmentFrame.origin.x = FLOOR(segment * basicSegmentWidth);
segmentFrame.size.width = (segment == segmentCount - 1) ? bounds.size.width - segmentFrame.origin.x : FLOOR(((segment + 1) * basicSegmentWidth)) - FLOOR((segment * basicSegmentWidth)) - _CPLevelIndicatorSpacing;
segmentFrame.size.height = segmentHeight;
return segmentFrame;
}
return _CGRectMakeZero();
}
/*!
Sets whether or not the receiver level indicator can be edited.
*/
- (void)setEditable:(BOOL)shouldBeEditable
{
if (_isEditable === shouldBeEditable)
return;
_isEditable = shouldBeEditable;
}
/*!
Returns \c YES if the textfield is currently editable by the user.
*/
- (BOOL)isEditable
{
return _isEditable;
}
- (CPView)hitTest:(CPPoint)aPoint
{
// Don't swallow clicks when displayed in a table.
if (![self isEditable])
return nil;
return [super hitTest:aPoint];
}
- (void)mouseDown:(CPEvent)anEvent
{
if (![self isEditable] || ![self isEnabled])
return;
[self _trackMouse:anEvent];
}
- (void)_trackMouse:(CPEvent)anEvent
{
var type = [anEvent type];
if (type == CPLeftMouseDown || type == CPLeftMouseDragged)
{
var segmentCount = _maxValue - _minValue;
if (segmentCount <= 0)
return;
var location = [self convertPoint:[anEvent locationInWindow] fromView:nil],
bounds = [self bounds],
oldValue = [self doubleValue];
newValue = oldValue;
// Moving the mouse outside of the widget to the left sets it
// to its minimum, and moving outside on the right sets it to
// its maximum.
if (type == CPLeftMouseDragged && location.x < 0)
{
newValue = _minValue;
}
else if (type == CPLeftMouseDragged && location.x > bounds.size.width)
{
newValue = _maxValue;
}
else
{
for (var i = 0; i < segmentCount; i++)
{
var rect = [self rectForEphemeralSubviewNamed:"segment-bezel-" + i];
// Once we're tracking the mouse, we only care about horizontal mouse movement.
if (location.x >= CGRectGetMinX(rect) && location.x < CGRectGetMaxX(rect))
{
newValue = (_minValue + i + 1);
break;
}
}
}
if (newValue != oldValue)
[self setDoubleValue:newValue];
// Track the mouse to support click and slide value editing.
_isTracking = YES;
[CPApp setTarget:self selector:@selector(_trackMouse:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
if ([self isContinuous])
[self sendAction:[self action] to:[self target]];
}
else if (_isTracking)
{
_isTracking = NO;
[self sendAction:[self action] to:[self target]];
}
}
/*
- (CPLevelIndicatorStyle)style;
- (void)setLevelIndicatorStyle:(CPLevelIndicatorStyle)style;
*/
- (void)setMinValue:(double)minValue
{
if (_minValue === minValue)
return;
_minValue = minValue;
[self setNeedsLayout];
}
- (void)setMaxValue:(double)maxValue
{
if (_maxValue === maxValue)
return;
_maxValue = maxValue;
[self setNeedsLayout];
}
- (void)setWarningValue:(double)warningValue;
{
if (_warningValue === warningValue)
return;
_warningValue = warningValue;
[self setNeedsLayout];
}
- (void)setCriticalValue:(double)criticalValue;
{
if (_criticalValue === criticalValue)
return;
_criticalValue = criticalValue;
[self setNeedsLayout];
}
/*
- (CPTickMarkPosition)tickMarkPosition;
- (void)setTickMarkPosition:(CPTickMarkPosition)position;
- (int)numberOfTickMarks;
- (void)setNumberOfTickMarks:(int)count;
- (int)numberOfMajorTickMarks;
- (void)setNumberOfMajorTickMarks:(int)count;
- (double)tickMarkValueAtIndex:(int)index;
- (CGRect)rectOfTickMarkAtIndex:(int)index;
*/
@end
var CPLevelIndicatorStyleKey = "CPLevelIndicatorStyleKey",
CPLevelIndicatorMinValueKey = "CPLevelIndicatorMinValueKey",
CPLevelIndicatorMaxValueKey = "CPLevelIndicatorMaxValueKey",
CPLevelIndicatorWarningValueKey = "CPLevelIndicatorWarningValueKey",
CPLevelIndicatorCriticalValueKey = "CPLevelIndicatorCriticalValueKey",
CPLevelIndicatorTickMarkPositionKey = "CPLevelIndicatorTickMarkPositionKey",
CPLevelIndicatorNumberOfTickMarksKey = "CPLevelIndicatorNumberOfTickMarksKey",
CPLevelIndicatorNumberOfMajorTickMarksKey = "CPLevelIndicatorNumberOfMajorTickMarksKey",
CPLevelIndicatorIsEditableKey = "CPLevelIndicatorIsEditableKey";
@implementation CPLevelIndicator (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
_levelIndicatorStyle = [aCoder decodeIntForKey:CPLevelIndicatorStyleKey];
_minValue = [aCoder decodeDoubleForKey:CPLevelIndicatorMinValueKey];
_maxValue = [aCoder decodeDoubleForKey:CPLevelIndicatorMaxValueKey];
_warningValue = [aCoder decodeDoubleForKey:CPLevelIndicatorWarningValueKey];
_criticalValue = [aCoder decodeDoubleForKey:CPLevelIndicatorCriticalValueKey];
_tickMarkPosition = [aCoder decodeIntForKey:CPLevelIndicatorTickMarkPositionKey];
_numberOfTickMarks = [aCoder decodeIntForKey:CPLevelIndicatorNumberOfTickMarksKey];
_numberOfMajorTickMarks = [aCoder decodeIntForKey:CPLevelIndicatorNumberOfMajorTickMarksKey];
_isEditable = [aCoder decodeBoolForKey:CPLevelIndicatorIsEditableKey];
[self _init];
[self setNeedsLayout];
[self setNeedsDisplay:YES];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeInt:_levelIndicatorStyle forKey:CPLevelIndicatorStyleKey];
[aCoder encodeDouble:_minValue forKey:CPLevelIndicatorMinValueKey];
[aCoder encodeDouble:_maxValue forKey:CPLevelIndicatorMaxValueKey];
[aCoder encodeDouble:_warningValue forKey:CPLevelIndicatorWarningValueKey];
[aCoder encodeDouble:_criticalValue forKey:CPLevelIndicatorCriticalValueKey];
[aCoder encodeInt:_tickMarkPosition forKey:CPLevelIndicatorTickMarkPositionKey];
[aCoder encodeInt:_numberOfTickMarks forKey:CPLevelIndicatorNumberOfTickMarksKey];
[aCoder encodeInt:_numberOfMajorTickMarks forKey:CPLevelIndicatorNumberOfMajorTickMarksKey];
[aCoder encodeBool:_isEditable forKey:CPLevelIndicatorIsEditableKey];
}
@end
+113 -39
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
@@ -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];
+47 -8
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
@@ -595,19 +625,22 @@ CPControlKeyMask
needsShift = _keyEquivalentModifierMask & CPShiftKeyMask ||
(string === _keyEquivalent && _keyEquivalent.toLowerCase() !== _keyEquivalent.toUpperCase());
if ([CPMenuItemStringRepresentationDictionary objectForKey:string])
string = [CPMenuItemStringRepresentationDictionary objectForKey:string];
if (CPBrowserIsOperatingSystem(CPMacOperatingSystem))
{
if (_keyEquivalentModifierMask & CPCommandKeyMask)
string = "" + string;
string = "\u2318" + string;
if (needsShift)
string = "" + string;
string = "\u21E7" + string;
if (_keyEquivalentModifierMask & CPAlternateKeyMask)
string = "" + string;
string = "\u2325" + string;
if (_keyEquivalentModifierMask & CPControlKeyMask)
string = "^" + string;
string = "\u2303" + string;
}
else
{
@@ -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
@@ -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);
}
+149 -2
View File
@@ -1,10 +1,40 @@
/*
* 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;
@@ -53,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])
@@ -72,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"];
@@ -88,51 +135,91 @@
[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;
}
/*!
@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];
@@ -141,6 +228,10 @@
[[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)
@@ -150,54 +241,87 @@
[[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] 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)
@@ -207,6 +331,9 @@
[self didChangeValueForKey:@"selection"];
}
/*!
@return id - Returns the keys which are being observed.
*/
- (id)observedKeys
{
return _observedKeys;
@@ -266,6 +393,12 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
[aCoder encodeBool:[self automaticallyPreparesContent] forKey:CPObjectControllerAutomaticallyPreparesContentKey];
}
- (void)awakeFromCib
{
if (![self content] && [self automaticallyPreparesContent])
[self prepareContent];
}
@end
@implementation _CPObservationProxy : CPObject
@@ -365,7 +498,7 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
- (CPString)description
{
return "<_CPObservableArray: "+[super description]+" >";
return "<_CPObservableArray: " + [super description] + " >";
}
- (id)initWithArray:(CPArray)anArray
@@ -530,7 +663,7 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
- (id)_controllerMarkerForValues:(CPArray)theValues
{
var count = [theValues count];
var count = [theValues count];
if (!count)
value = CPNoSelectionMarker;
@@ -552,6 +685,9 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
}
}
if (value === nil || value.isa && [value isEqual:[CPNull null]])
value = CPNullMarker;
return value;
}
@@ -574,6 +710,17 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
{
[[_controller selectedObjects] setValue:theValue forKeyPath:theKeyPath];
[_cachedValues removeObjectForKey:theKeyPath];
// Allow handlesContentAsCompoundValue to work, based on observation of Cocoa's
// NSArrayController - when handlesContentAsCompoundValue and setValue:forKey:@"selection.X"
// is called, the array controller causes the compound value to be rewritten if
// handlesContentAsCompoundValue == YES. Note that
// A) this doesn't use observation (observe: X is not visible in backtraces)
// B) it only happens through the selection proxy and not on arrangedObject.X, content.X
// or even selectedObjects.X.
// FIXME The main code for this should somehow be in CPArrayController and also work
// for table based row edits.
[[CPBinder getBinding:@"contentArray" forObject:_controller] _contentArrayDidChange];
}
- (void)setValue:(id)theValue forKey:(CPString)theKeyPath
+21
View File
@@ -1,3 +1,24 @@
/*
* CPOpenPanel.j
* AppKit
*
* Created by Ross Boucher.
* Copyright 2009, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPPanel.j"
+296 -149
View File
@@ -71,19 +71,29 @@ var CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_
CPOutlineViewDelegate_outlineView_typeSelectStringForTableColumn_item_ = 1 << 21,
CPOutlineViewDelegate_outlineView_willDisplayOutlineView_forTableColumn_item_ = 1 << 22,
CPOutlineViewDelegate_outlineView_willDisplayView_forTableColumn_item_ = 1 << 23,
CPOutlineViewDelegate_selectionShouldChangeInOutlineView_ = 1 << 24;
CPOutlineViewDelegate_selectionShouldChangeInOutlineView_ = 1 << 24,
CPOutlineViewDelegate_outlineView_menuForTableColumn_item_ = 1 << 25;
CPOutlineViewDropOnItemIndex = -1;
var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
CPOutlineViewCoalesceSelectionNotificationStateOn = 1,
CPOutlineViewCoalesceSelectionNotificationStateDid = 2;
/*!
@ingroup appkit
@class CPOutlineView
CPOutlineView is a subclass of CPTableView that inherates the row and column format to display hierarchial data.
The outlineview adds the ability to expand and collapse items. This is useful for browsing a tree like structure such as directories or a filesystem.
CPOutlineView is a subclass of CPTableView that inherits the row and
column format to display hierarchical data. The outlineview adds the
ability to expand and collapse items. This is useful for browsing a tree
like structure such as directories or a filesystem.
Like the tableview, an outlineview uses a data source to supply its data. For this reason you must implement a couple data source methods (documented in setDataSource:)
Like the tableview, an outlineview uses a data source to supply its data.
For this reason you must implement a couple data source methods
(documented in setDataSource:).
Theme states for custom data views are documented in CPTableView.
*/
@implementation CPOutlineView : CPTableView
{
@@ -113,6 +123,8 @@ CPOutlineViewDropOnItemIndex = -1;
CPInteger _retargedChildIndex;
CPTimer _dragHoverTimer;
id _dropItem;
BOOL _coalesceSelectionNotificationState;
}
- (id)initWithFrame:(CGRect)aFrame
@@ -121,7 +133,6 @@ CPOutlineViewDropOnItemIndex = -1;
if (self)
{
_selectionHighlightStyle = CPTableViewSelectionHighlightStyleSourceList;
// The root item has weight "0", thus represents the weight solely of its descendants.
@@ -150,52 +161,55 @@ CPOutlineViewDropOnItemIndex = -1;
return self;
}
/*!
In addition to standard delegation, the outline view also supports data source delegation. This method sets the data source object.
Just like the TableView you have CPTableColumns but instead of rows you deal with items.
In addition to standard delegation, the outline view also supports data
source delegation. This method sets the data source object. Just like the
TableView you have CPTableColumns but instead of rows you deal with items.
You must implement these data source methods:
@section required You must implement these data source methods:
- (id)outlineView:(CPOutlineView)outlineView child:(CPInteger)index ofItem:(id)item;
Returns the child item at an index of a given item. if item is nil you should return the appropriate root item.
Returns the child item at an index of a given item. if item is nil you should return the appropriate root item.
@code - (id)outlineView:(CPOutlineView)outlineView child:(CPInteger)index ofItem:(id)item; @endcode
- (BOOL)outlineView:(CPOutlineView)outlineView isItemExpandable:(id)item;
Returns YES if the item is expandable, otherwise NO.
Returns YES if the item is expandable, otherwise NO.
@code - (BOOL)outlineView:(CPOutlineView)outlineView isItemExpandable:(id)item; @endcode
- (int)outlineView:(CPOutlineView)outlineView numberOfChildrenOfItem:(id)item;
Returns the number of child items of a given item. If item is nil you should return the number of top level (root) items.
Returns the number of child items of a given item. If item is nil you should return the number of top level (root) items.
@code - (int)outlineView:(CPOutlineView)outlineView numberOfChildrenOfItem:(id)item; @endcode
- (id)outlineView:(CPOutlineView)outlineView objectValueForTableColumn:(CPTableColumn)tableColumn byItem:(id)item;
Returns the object value of the item in a given column.
Returns the object value of the item in a given column.
@code - (id)outlineView:(CPOutlineView)outlineView objectValueForTableColumn:(CPTableColumn)tableColumn byItem:(id)item; @endcode
---------
@section optional The following methods are optional:
@section editin Editing:
Sets the data object value for an item in a given column. This needs to be implemented if you want inline editing support.
@code - (void)outlineView:(CPOutlineView)outlineView setObjectValue:(id)object forTableColumn:(CPTableColumn)tableColumn byItem:(id)item; @endcode
The following methods are optional:
@section sorting Sorting:
The outlineview will call this method if you click the table header. You should sort the datasource based off of the new sort descriptors and reload the data
@code - (void)outlineView:(CPOutlineView)outlineView sortDescriptorsDidChange:(CPArray)oldDescriptors; @endcode
Editing:
- (void)outlineView:(CPOutlineView)outlineView setObjectValue:(id)object forTableColumn:(CPTableColumn)tableColumn byItem:(id)item;
Sets the data object value for an item in a given column. This needs to be implemented if you want inline editing support.
@section draganddrop Drag and Drop:
@note In order for the outlineview to receive drops don't forget to first
register the tableview for drag types like you do with every other view @endnote
Return YES if the operation was successful otherwise return NO.
The data source should incorporate the data from the dragging pasteboard in this method implementation.
To get this data use the draggingPasteboard method on the CPDraggingInfo object.
@code - (BOOL)outlineView:(CPOutlineView)outlineView acceptDrop:(id < CPDraggingInfo >)info item:(id)item childIndex:(CPInteger)index; @endcode
Sorting:
- (void)outlineView:(CPOutlineView)outlineView sortDescriptorsDidChange:(CPArray)oldDescriptors;
The outlineview will call this method if you click the tableheader. You should sort the datasource based off of the new sort descriptors and reload the data
Drag and Drop:
In order for the outlineview to recieve drops dont forget to first register the tableview for drag types like you do with every other view
- (BOOL)outlineView:(CPOutlineView)outlineView acceptDrop:(id < CPDraggingInfo >)info item:(id)item childIndex:(CPInteger)index;
Return YES if the operation was successful otherwise return NO.
The data source should incorporate the data from the dragging pasteboard in this method implementation.
To get this data use the draggingPasteboard method on the CPDraggingInfo object.
- (CPDragOperation)outlineView:(CPOutlineView)outlineView validateDrop:(id < CPDraggingInfo >)info proposedItem:(id)item proposedChildIndex:(CPInteger)index;
Return the drag operation (move, copy, etc) that should be performaned if a registered drag type is over the tableview
The data source can retarget a drop if you want by calling -(void)setDropItem:(id)anItem dropChildIndex:(int)anIndex;
- (BOOL)outlineView:(CPOutlineView)outlineView writeItems:(CPArray)items toPasteboard:(CPPasteboard)pboard;
Returns YES if the drop operation is allowed otherwise NO.
This method is invoked by the outlineview after a drag should begin, but before it is started. If you dont want the drag to being return NO.
If you want the drag to begin you should return YES and place the drag data on the pboard.
Return the drag operation (move, copy, etc) that should be performed if a registered drag type is over the tableview
The data source can retarget a drop if you want by calling <pre>-(void)setDropItem:(id)anItem dropChildIndex:(int)anIndex;</pre>
@code - (CPDragOperation)outlineView:(CPOutlineView)outlineView validateDrop:(id < CPDraggingInfo >)info proposedItem:(id)item proposedChildIndex:(CPInteger)index; @endcode
Returns YES if the drop operation is allowed otherwise NO.
This method is invoked by the outlineview after a drag should begin, but before it is started. If you don't want the drag to being return NO.
If you want the drag to begin you should return YES and place the drag data on the pboard.
@code - (BOOL)outlineView:(CPOutlineView)outlineView writeItems:(CPArray)items toPasteboard:(CPPasteboard)pboard; @endcode
*/
- (void)setDataSource:(id)aDataSource
{
@@ -252,6 +266,7 @@ CPOutlineViewDropOnItemIndex = -1;
/*!
Returns the datasource object.
@return id - The data source object
*/
- (id)dataSource
@@ -280,7 +295,7 @@ CPOutlineViewDropOnItemIndex = -1;
}
/*!
Used to find if an item is already expanded.
Used to find if an item is already expanded.
@param anItem - the item you are interest in.
@@ -300,7 +315,7 @@ CPOutlineViewDropOnItemIndex = -1;
}
/*!
Expends a given item.
Expands a given item.
@param anItem - the item to expand.
*/
@@ -327,14 +342,31 @@ CPOutlineViewDropOnItemIndex = -1;
if (!itemInfo)
return;
// to prevent items which are already expanded from firing notifications
// When shouldExpandChildren is YES, we need to make sure we're collecting
// selection notifications so that exactly one IsChanging and one
// DidChange is sent as needed, for the totality of the operation.
var isTopLevel = NO;
if (!_coalesceSelectionNotificationState)
{
isTopLevel = YES;
_coalesceSelectionNotificationState = CPOutlineViewCoalesceSelectionNotificationStateOn;
}
// To prevent items which are already expanded from firing notifications.
if (!itemInfo.isExpanded)
{
[self _noteItemWillExpand:anItem];
var previousRowCount = [self numberOfRows];
itemInfo.isExpanded = YES;
// XXX Shouldn't the items reload before the notification is sent?
[self _noteItemDidExpand:anItem];
[self reloadItem:anItem reloadChildren:YES];
// Shift selection indexes below so that the same items remain selected.
var newRowCount = [_outlineViewDataSource outlineView:self numberOfChildrenOfItem:anItem];
if (newRowCount)
var rowCountDelta = [self numberOfRows] - previousRowCount;
if (rowCountDelta)
{
var selection = [self selectedRowIndexes],
expandIndex = [self rowForItem:anItem] + 1;
@@ -342,14 +374,10 @@ CPOutlineViewDropOnItemIndex = -1;
if ([selection intersectsIndexesInRange:CPMakeRange(expandIndex, _itemsForRows.length)])
{
[self _noteSelectionIsChanging];
[selection shiftIndexesStartingAtIndex:expandIndex by:newRowCount];
[self _setSelectedRowIndexes:selection];
[selection shiftIndexesStartingAtIndex:expandIndex by:rowCountDelta];
[self _setSelectedRowIndexes:selection]; // _noteSelectionDidChange will be suppressed.
}
}
itemInfo.isExpanded = YES;
[self _noteItemDidExpand:anItem];
[self reloadItem:anItem reloadChildren:YES];
}
if (shouldExpandChildren)
@@ -360,6 +388,14 @@ CPOutlineViewDropOnItemIndex = -1;
while (childIndex--)
[self expandItem:children[childIndex] expandChildren:YES];
}
if (isTopLevel)
{
var r = _coalesceSelectionNotificationState;
_coalesceSelectionNotificationState = CPOutlineViewCoalesceSelectionNotificationStateOff;
if (r === CPOutlineViewCoalesceSelectionNotificationStateDid)
[self _noteSelectionDidChange];
}
}
/*!
@@ -380,6 +416,9 @@ CPOutlineViewDropOnItemIndex = -1;
if (!itemInfo.isExpanded)
return;
// Don't spam notifications.
_coalesceSelectionNotificationState = CPOutlineViewCoalesceSelectionNotificationStateOn;
[self _noteItemWillCollapse:anItem];
// Update selections:
// * Deselect items inside the collapsed item.
@@ -392,39 +431,38 @@ CPOutlineViewDropOnItemIndex = -1;
collapseEndIndex++;
var collapseRange = CPMakeRange(collapseTopIndex + 1, collapseEndIndex - collapseTopIndex);
if (collapseRange.length)
{
var selection = [self selectedRowIndexes],
didChange = NO;
var selection = [self selectedRowIndexes];
if ([selection intersectsIndexesInRange:collapseRange])
{
[selection removeIndexesInRange:collapseRange];
[self _noteSelectionIsChanging];
didChange = YES;
// Will call _noteSelectionDidChange
[self _setSelectedRowIndexes:selection];
[selection removeIndexesInRange:collapseRange];
[self _setSelectedRowIndexes:selection]; // _noteSelectionDidChange will be suppressed.
}
// Shift any selected rows below upwards.
if ([selection intersectsIndexesInRange:CPMakeRange(collapseEndIndex + 1, _itemsForRows.length)])
{
// Notify if that wasn't already done above.
if (!didChange)
[self _noteSelectionIsChanging];
didChange = YES;
[self _noteSelectionIsChanging];
[selection shiftIndexesStartingAtIndex:collapseEndIndex + 1 by:-collapseRange.length];
[self _setSelectedRowIndexes:selection]; // _noteSelectionDidChange will be suppressed.
}
if (didChange)
[self _setSelectedRowIndexes:selection];
}
itemInfo.isExpanded = NO;
// XXX Shouldn't the items reload before the notification is sent?
[self _noteItemDidCollapse:anItem];
[self reloadItem:anItem reloadChildren:YES];
// Send selection notifications only after the items have loaded so that
// the new selection is consistent with the actual rows for any observers.
var r = _coalesceSelectionNotificationState;
_coalesceSelectionNotificationState = CPOutlineViewCoalesceSelectionNotificationStateOff;
if (r === CPOutlineViewCoalesceSelectionNotificationStateDid)
[self _noteSelectionDidChange];
}
/*!
@@ -456,7 +494,7 @@ CPOutlineViewDropOnItemIndex = -1;
/*!
Returns the item at a given row index. If no item exists nil is returned.
@param aRow - The rown index you want to find the item at.
@param aRow - The row index you want to find the item at.
@return id - The item at a given index.
*/
- (id)itemAtRow:(CPInteger)aRow
@@ -484,7 +522,8 @@ CPOutlineViewDropOnItemIndex = -1;
}
/*!
Sets the table column you want to display the disclosure button in.
Sets the table column you want to display the disclosure button in. If you
do not want an outline column pass nil.
@param aTableColumn - The CPTableColumn you want to use for hierarchical data.
*/
@@ -510,7 +549,9 @@ CPOutlineViewDropOnItemIndex = -1;
}
/*!
Returns the indentation level of a given item. If the item is nil (the top level root item) CPNotFound is returned. Indentation levels are zero based, thus items that are not indented return 0.
Returns the indentation level of a given item. If the item is nil (the top
level root item) CPNotFound is returned. Indentation levels are zero
based, thus items that are not indented return 0.
@param anItem - The item you want the indentation level for.
@return int - the indentation level of anItem.
@@ -529,9 +570,10 @@ CPOutlineViewDropOnItemIndex = -1;
}
/*!
Returns the indentation level for a given row. If the row is invalid CPNotFound is returned. Rows that are nto indented return 0.
Returns the indentation level for a given row. If the row is invalid
CPNotFound is returned. Rows that are not indented return 0.
@param aRow - the row of the reciever
@param aRow - the row of the receiver
@return int - the indentation level of aRow.
*/
- (CPInteger)levelForRow:(CPInteger)aRow
@@ -566,7 +608,9 @@ CPOutlineViewDropOnItemIndex = -1;
}
/*!
Sets the layout behaviour of disclosure button. If you pass NO the disclosure button will always align itself to the left of the outline column.
Sets the layout behavior of disclosure button. If you pass NO the
disclosure button will always align itself to the left of the outline
column.
@param indentationMarkerShouldFollowDataView - Pass YES if the disclosure control should be indented along with the dataview, otherwise NO.
*/
@@ -582,9 +626,11 @@ CPOutlineViewDropOnItemIndex = -1;
}
/*!
Returns the layout behaviour of the disclosure buttons.
Returns the layout behavior of the disclosure buttons.
@return BOOL - YES if the disclosure control indents itself with the dataview, otherwise NO if the control is always aligned to the left of the outline column
@return BOOL - YES if the disclosure control indents itself with the
dataview, otherwise NO if the control is always aligned to the left of
the outline column
*/
- (BOOL)indentationMarkerFollowsDataView
{
@@ -594,8 +640,9 @@ CPOutlineViewDropOnItemIndex = -1;
/*!
Returns the parent item for a given item. If the item is a top level root object nil is returned.
@param anItem - The item of the reciver.
@return id - The parent item of anItem. If no parent exists (the item is a root item) nil is returned.
@param anItem - The item of the receiver.
@return id - The parent item of anItem. If no parent exists (the item is a
root item) nil is returned.
*/
- (id)parentForItem:(id)anItem
{
@@ -619,7 +666,7 @@ CPOutlineViewDropOnItemIndex = -1;
/*!
@ignore
Returns the frame of the dataview at the row given for the outline column
Returns the frame of the dataview at the row given for the outline column.
*/
- (CGRect)_frameOfOutlineDataViewAtRow:(CPInteger)aRow
{
@@ -634,11 +681,11 @@ CPOutlineViewDropOnItemIndex = -1;
}
/*!
Returns the frame of the disclosure button for the outline column.
If the item is not expandable a CGZeroRect is returned.
Subclasses can return a CGZeroRect to prevent the disclosure control from being displayed.
Returns the frame of the disclosure button for the outline column. If the
item is not expandable a CGZeroRect is returned. Subclasses can return a
CGZeroRect to prevent the disclosure control from being displayed.
@param aRow - The row of the reciever
@param aRow - The row of the receiver
@return CGRect - The rect of the disclosure button at aRow.
*/
- (CGRect)frameOfOutlineDisclosureControlAtRow:(CPInteger)aRow
@@ -654,7 +701,7 @@ CPOutlineViewDropOnItemIndex = -1;
/*!
@ignore
Select or deselect rows, this is overridden because we need to change the color or the outline control
Select or deselect rows, this is overridden because we need to change the color or the outline control.
*/
- (void)_performSelection:(BOOL)select forRow:(CPInteger)rowIndex context:(id)context
{
@@ -667,66 +714,80 @@ CPOutlineViewDropOnItemIndex = -1;
}
/*!
Sets the delegate for the outlineview.
The following methods can be implemented:
@param aDelegate - the delegate object you wish to set for the receiver.
User Interaction Notifications:
- (void)outlineViewColumnDidMove:(CPNotification)notification;
Called when the user moves a column in the outlineview.
@section notifications User Interaction Notifications:
- (void)outlineViewColumnDidResize:(CPNotification)notification;
Called when the user resizes a column in the outlineview.
Called when the user moves a column in the outlineview.
@code - (void)outlineViewColumnDidMove:(CPNotification)notification; @endcode
- (void)outlineViewItemDidCollapse:(CPNotification)notification;
Called when the user collapses an item in teh outlineview.
Called when the user resizes a column in the outlineview.
@code - (void)outlineViewColumnDidResize:(CPNotification)notification; @endcode
- (void)outlineViewItemDidExpand:(CPNotification)notification;
Called when the user expands an item in the outlineview.
Called when the user collapses an item in the outlineview.
@code - (void)outlineViewItemDidCollapse:(CPNotification)notification; @endcode
- (void)outlineViewItemWillCollapse:(CPNotification)notification;
Called when the user collapses an item in the outlineview, but before the item is actually collapsed.
Called when the user expands an item in the outlineview.
@code - (void)outlineViewItemDidExpand:(CPNotification)notification; @endcode
- (void)outlineViewItemWillExpand:(CPNotification)notification;
Called when the used expands an item, but before the item is actually expanded.
Called when the user collapses an item in the outlineview, but before the item is actually collapsed.
@code - (void)outlineViewItemWillCollapse:(CPNotification)notification; @endcode
- (void)outlineViewSelectionDidChange:(CPNotification)notification;
Called when the user changes the selection of the outlineview.
Called when the used expands an item, but before the item is actually expanded.
@code - (void)outlineViewItemWillExpand:(CPNotification)notification; @endcode
- (void)outlineViewSelectionIsChanging:(CPNotification)notification
Called when the user changes the selection of the outlineview, but before the change is made.
Called when the user changes the selection of the outlineview.
@code - (void)outlineViewSelectionDidChange:(CPNotification)notification; @endcode
Expanding and collapsing items:
- (BOOL)outlineView:(CPOutlineView)outlineView shouldExpandItem:(id)item;
Return YES if the item should be given permission to expand, otherwise NO.
Called when the user changes the selection of the outlineview, but before the change is made.
@code - (void)outlineViewSelectionIsChanging:(CPNotification)notification; @endcode
- (BOOL)outlineView:(CPOutlineView)outlineView shouldCollapseItem:(id)item;
Return YES if the item should be given permission to collapse, otherwise NO.
@section expandingandcollapsing Expanding and collapsing items:
Selection:
- (BOOL)outlineView:(CPOutlineView)outlineView shouldSelectTableColumn:(CPTableColumn)tableColumn;
Return YES to allow the selection of tableColumn, otherwise NO.
Return YES if the item should be given permission to expand, otherwise NO.
@code - (BOOL)outlineView:(CPOutlineView)outlineView shouldExpandItem:(id)item; @endcode
- (BOOL)outlineView:(CPOutlineView)outlineView shouldSelectItem:(id)item;
Return YES to allow the selection of an item, otherwise NO.
Return YES if the item should be given permission to collapse, otherwise NO.
@code - (BOOL)outlineView:(CPOutlineView)outlineView shouldCollapseItem:(id)item; @endcode
- (BOOL)selectionShouldChangeInOutlineView:(CPOutlineView)outlineView;
Return YES to allow the selection of the outlineview to be changed, otherwise NO.
@section selection Selection:
Return YES to allow the selection of tableColumn, otherwise NO.
@code- (BOOL)outlineView:(CPOutlineView)outlineView shouldSelectTableColumn:(CPTableColumn)tableColumn; @endcode
Displaying DataViews:
- (void)outlineView:(CPOutlineView)outlineView willDisplayView:(id)dataView forTableColumn:(CPTableColumn)tableColumn item:(id)item;
Called when a dataView is about to be displayed. This gives you the ability to alter the dataView if needed.
Return YES to allow the selection of an item, otherwise NO.
@code- (BOOL)outlineView:(CPOutlineView)outlineView shouldSelectItem:(id)item; @endcode
Editing:
- (BOOL)outlineView:(CPOutlineView)outlineView shouldEditTableColumn:(CPTableColumn)tableColumn item:(id)item;
Return YES to allow for editing of a dataview at given item and tableColumn, otherwise NO to prevent the edit.
Return YES to allow the selection of the outlineview to be changed, otherwise NO.
@code - (BOOL)selectionShouldChangeInOutlineView:(CPOutlineView)outlineView; @endcode
Group Items:
- (BOOL)outlineView:(CPOutlineView)outlineView isGroupItem:(id)item;
Implement this to indicate whether a given item should be rendered using the group item style.
Return YES if the item is a group item, otherwise NO.
@section dataviews Displaying DataViews:
Called when a dataView is about to be displayed. This gives you the ability to alter the dataView if needed.
@code - (void)outlineView:(CPOutlineView)outlineView willDisplayView:(id)dataView forTableColumn:(CPTableColumn)tableColumn item:(id)item; @endcode
@section editin Editing:
Return YES to allow for editing of a dataview at given item and tableColumn, otherwise NO to prevent the edit.
@code - (BOOL)outlineView:(CPOutlineView)outlineView shouldEditTableColumn:(CPTableColumn)tableColumn item:(id)item; @endcode
@section groups Group Items:
Implement this to indicate whether a given item should be rendered using the group item style.
Return YES if the item is a group item, otherwise NO.
@code - (BOOL)outlineView:(CPOutlineView)outlineView isGroupItem:(id)item; @endcode
@section variableitems Variable Item Heights
Implement this method to get custom heights of rows based on the item.
This delegate method will be passed your 'item' object and expects you to return an integer height.
@note This should only be implemented if rows will be different heights, if you want to set a height for ALL of your rows see -setRowHeight:@endnote
@code - (int)outlineView:(CPOutlineView)outlineView heightOfRowByItem:(id)anItem; @endcode
@param aDelegate - the delegate object you wish to set for the reciever.
*/
- (void)setDelegate:(id)aDelegate
{
@@ -818,7 +879,8 @@ CPOutlineViewDropOnItemIndex = -1;
CPOutlineViewDelegate_outlineView_typeSelectStringForTableColumn_item_ , @selector(outlineView:typeSelectStringForTableColumn:item:),
CPOutlineViewDelegate_outlineView_willDisplayOutlineView_forTableColumn_item_ , @selector(outlineView:willDisplayOutlineView:forTableColumn:item:),
CPOutlineViewDelegate_outlineView_willDisplayView_forTableColumn_item_ , @selector(outlineView:willDisplayView:forTableColumn:item:),
CPOutlineViewDelegate_selectionShouldChangeInOutlineView_ , @selector(selectionShouldChangeInOutlineView:)
CPOutlineViewDelegate_selectionShouldChangeInOutlineView_ , @selector(selectionShouldChangeInOutlineView:),
CPOutlineViewDelegate_outlineView_menuForTableColumn_item_ , @selector(outlineView:menuForTableColumn:item:)
],
delegateCount = [delegateMethods count];
@@ -890,6 +952,17 @@ CPOutlineViewDropOnItemIndex = -1;
}
- (BOOL)_sendDelegateDeleteKeyPressed
{
if ([[self delegate] respondsToSelector: @selector(outlineViewDeleteKeyPressed:)])
{
[[self delegate] outlineViewDeleteKeyPressed:self];
return YES;
}
return NO;
}
/*!
Returns the delegate object for the outlineview.
*/
@@ -899,8 +972,9 @@ CPOutlineViewDropOnItemIndex = -1;
}
/*!
Sets the prototype of the disclosure control. This is used if you want to set a special type of button, instead of the default triangle.
The control must implement CPCoding.
Sets the prototype of the disclosure control. This is used if you want to
set a special type of button, instead of the default triangle. The control
must implement CPCoding.
@param aControl - the control to be used to expand and collapse items.
*/
@@ -910,7 +984,7 @@ CPOutlineViewDropOnItemIndex = -1;
_disclosureControlData = nil;
_disclosureControlQueue = [];
// fIXME: reall?
// fIXME: really?
[self reloadData];
}
@@ -922,9 +996,37 @@ CPOutlineViewDropOnItemIndex = -1;
[self reloadItem:nil reloadChildren:YES];
}
/*!
Adds a new table column to the receiver. If this is the first column added
it will automatically be set to the outline column.
Also see -setOutlineTableColumn:.
@note This behavior deviates from cocoa slightly.
@param CPTableColumn aTableColumn - The table column to add.
*/
- (void)addTableColumn:(CPTableColumn)aTableColumn
{
[super addTableColumn:aTableColumn];
if ([self numberOfColumns] === 1)
_outlineTableColumn = aTableColumn;
}
/*!
@ignore
We overide this because we need a special behaviour for the outline column
*/
- (void)removeTableColumn:(CPTableColumn)aTableColumn
{
if (aTableColumn === [self outlineTableColumn])
CPLog("CPOutlineView cannot remove outlineTableColumn with removeTableColumn:. User setOutlineTableColumn: instead.");
else
[super removeTableColumn:aTableColumn];
}
/*!
@ignore
We override this because we need a special behavior for the outline
column.
*/
- (CGRect)frameOfDataViewAtColumn:(CPInteger)aColumn row:(CPInteger)aRow
{
@@ -938,7 +1040,7 @@ CPOutlineViewDropOnItemIndex = -1;
/*!
@ignore
we need to offset the dataview and add the dislosure triangle
We need to offset the dataview and add the disclosure triangle.
*/
- (CPView)_dragViewForColumn:(int)theColumnIndex event:(CPEvent)theDragEvent offset:(CPPointPointer)theDragViewOffset
{
@@ -998,9 +1100,15 @@ CPOutlineViewDropOnItemIndex = -1;
/*!
Retargets the drop item for the outlineview.
To specify a drop on theItem, you specify item as theItem and index as CPOutlineViewDropOnItemIndex.
To specify a drop between child 1 and 2 of theItem, you specify item as theItem and index as 2.
To specify a drop on an item that can't be expanded theItem, you specify item as someOutlineItem and index as CPOutlineViewDropOnItemIndex.
To specify a drop on theItem, you specify item as theItem and index as
CPOutlineViewDropOnItemIndex.
To specify a drop between child 1 and 2 of theItem, you specify item as
theItem and index as 2.
To specify a drop on an item that can't be expanded theItem, you specify
item as someOutlineItem and index as CPOutlineViewDropOnItemIndex.
@param theItem - The item you want to retarget the drop on.
@param theIndex - The index of the child item you want to retarget the drop between. Pass CPOutlineViewDropOnItemIndex if you want to drop on theItem.
@@ -1110,7 +1218,7 @@ CPOutlineViewDropOnItemIndex = -1;
/*!
@ignore
We need to move the disclosure control too
We need to move the disclosure control too.
*/
- (void)_layoutDataViewsInRows:(CPIndexSet)rows columns:(CPIndexSet)columns
{
@@ -1277,10 +1385,16 @@ CPOutlineViewDropOnItemIndex = -1;
*/
- (void)_noteSelectionIsChanging
{
[[CPNotificationCenter defaultCenter]
postNotificationName:CPOutlineViewSelectionIsChangingNotification
object:self
userInfo:nil];
if (!_coalesceSelectionNotificationState || _coalesceSelectionNotificationState === CPOutlineViewCoalesceSelectionNotificationStateOn)
{
[[CPNotificationCenter defaultCenter]
postNotificationName:CPOutlineViewSelectionIsChangingNotification
object:self
userInfo:nil];
}
if (_coalesceSelectionNotificationState === CPOutlineViewCoalesceSelectionNotificationStateOn)
_coalesceSelectionNotificationState = CPOutlineViewCoalesceSelectionNotificationStateDid;
}
/*!
@@ -1288,10 +1402,16 @@ CPOutlineViewDropOnItemIndex = -1;
*/
- (void)_noteSelectionDidChange
{
[[CPNotificationCenter defaultCenter]
postNotificationName:CPOutlineViewSelectionDidChangeNotification
object:self
userInfo:nil];
if (!_coalesceSelectionNotificationState)
{
[[CPNotificationCenter defaultCenter]
postNotificationName:CPOutlineViewSelectionDidChangeNotification
object:self
userInfo:nil];
}
if (_coalesceSelectionNotificationState === CPOutlineViewCoalesceSelectionNotificationStateOn)
_coalesceSelectionNotificationState = CPOutlineViewCoalesceSelectionNotificationStateDid;
}
/*!
@@ -1521,14 +1641,14 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
if (!(_outlineView._implementedOutlineViewDataSourceMethods & CPOutlineViewDataSource_outlineView_writeItems_toPasteboard_))
return NO;
var rowIndexes = [];
[theIndexes getIndexes:rowIndexes maxCount:[theIndexes count] inIndexRange:nil];
var items = [],
index = [theIndexes firstIndex];
var rowIndex = [rowIndexes count],
items = [];
while (rowIndex--)
[items addObject:[_outlineView itemAtRow:[rowIndexes objectAtIndex:rowIndex]]];
while (index !== CPNotFound)
{
[items addObject:[_outlineView itemAtRow:index]]
index = [theIndexes indexGreaterThanIndex:index];
}
return [_outlineView._outlineViewDataSource outlineView:_outlineView writeItems:items toPasteboard:thePasteboard];
}
@@ -1603,6 +1723,15 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
return [_outlineView._outlineViewDataSource outlineView:_outlineView acceptDrop:theInfo item:parentItem childIndex:childIndex];
}
- (void)tableView:(CPTableView)aTableView sortDescriptorsDidChange:(CPArray)oldSortDescriptors
{
if ((_outlineView._implementedOutlineViewDataSourceMethods &
CPOutlineViewDataSource_outlineView_sortDescriptorsDidChange_))
{
[[_outlineView dataSource] outlineView:_outlineView sortDescriptorsDidChange:oldSortDescriptors];
}
}
@end
@implementation _CPOutlineViewTableViewDelegate : CPObject
@@ -1651,13 +1780,13 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
return NO;
}
/*- (float)tableView:(CPTableView)theTableView heightOfRow:(int)theRow
- (float)tableView:(CPTableView)theTableView heightOfRow:(int)theRow
{
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_heightOfRowByItem_))
return [_outlineView._outlineViewDelegate outlineView:_outlineView heightOfRowByItem:[_outlineView itemAtRow:theRow]];
return [theTableView rowHeight];
}*/
}
- (void)tableView:(CPTableView)aTableView willDisplayView:(id)aView forTableColumn:(CPTableColumn)aTableColumn row:(int)aRowIndex
{
@@ -1676,6 +1805,17 @@ var _loadItemInfoForItem = function(/*CPOutlineView*/ anOutlineView, /*id*/ anIt
return NO;
}
- (CPMenu)tableView:(CPTableView)aTableView menuForTableColumn:(CPTableColumn)aTableColumn row:(int)aRow
{
if ((_outlineView._implementedOutlineViewDelegateMethods & CPOutlineViewDelegate_outlineView_menuForTableColumn_item_))
{
var item = [_outlineView itemAtRow:aRow];
return [_outlineView._outlineViewDelegate outlineView:_outlineView menuForTableColumn:aTableColumn item:item]
}
return nil;
}
@end
@implementation CPDisclosureButton : CPButton
@@ -1787,7 +1927,14 @@ var CPOutlineViewIndentationPerLevelKey = @"CPOutlineViewIndentationPerLevelKey"
- (void)encodeWithCoder:(CPCoder)aCoder
{
// Make sure we don't encode our internal delegate and data source.
var internalDelegate = _delegate,
internalDataSource = _dataSource;
_delegate = nil;
_dataSource = nil;
[super encodeWithCoder:aCoder];
_delegate = internalDelegate;
_dataSource = internalDataSource;
[aCoder encodeObject:_outlineTableColumn forKey:CPOutlineViewOutlineTableColumnKey];
[aCoder encodeFloat:_indentationPerLevel forKey:CPOutlineViewIndentationPerLevelKey];
+1 -1
View File
@@ -26,7 +26,7 @@
CPOKButton = 1;
CPCancelButton = 0;
/*!
/*!
@ingroup appkit
@class CPPanel
+224 -202
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,9 +47,19 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
return "popup-button";
}
+ (CPSet)keyPathsForValuesAffectingSelectedIndex
{
return [CPSet setWithObject:@"objectValue"];
}
+ (CPSet)keyPathsForValuesAffectingSelectedTag
{
return [CPSet setWithObject:@"selectedIndex"];
return [CPSet setWithObject:@"objectValue"];
}
+ (CPSet)keyPathsForValuesAffectingSelectedItem
{
return [CPSet setWithObject:@"objectValue"];
}
/*!
@@ -66,7 +74,8 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
if (self)
{
_selectedIndex = CPNotFound;
[self selectItemAtIndex:CPNotFound];
_preferredEdge = CPMaxYEdge;
[self setValue:CPImageLeft forThemeAttribute:@"image-position"];
@@ -76,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;
@@ -90,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.
*/
@@ -103,7 +120,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
if (!changed)
return;
var items = [_menu itemArray];
var items = [[self menu] itemArray];
if ([items count] <= 0)
return;
@@ -128,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
{
@@ -155,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
@@ -167,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];
}
/*!
@@ -175,10 +192,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (void)removeAllItems
{
var count = [_menu numberOfItems];
while (count--)
[_menu removeItemAtIndex:0];
[[self menu] removeAllItems];
}
/*!
@@ -197,7 +211,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (void)removeItemAtIndex:(int)anIndex
{
[_menu removeItemAtIndex:anIndex];
[[self menu] removeItemAtIndex:anIndex];
[self synchronizeTitleAndSelectedItem];
}
@@ -207,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];
}
/*!
@@ -229,15 +245,6 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
return _selectedIndex;
}
// For us, CPNumber is toll-free bridged to Number, so just return the selected index.
/*!
Returns the selected item's index. If no item is selected, it returns CPNotFound.
*/
- (id)objectValue
{
return _selectedIndex;
}
/*!
@ignore
*/
@@ -268,24 +275,48 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
Selects the item at the specified index
@param anIndex the index of the item to select
*/
- (void)selectItemAtIndex:(int)anIndex
- (void)selectItemAtIndex:(CPUInteger)anIndex
{
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;
[self willChangeValueForKey:@"selectedIndex"];
if (_selectedIndex >= 0 && ![self pullsDown])
if (indexOfSelectedItem >= 0 && ![self pullsDown])
[[self selectedItem] setState:CPOffState];
_selectedIndex = anIndex;
if (_selectedIndex >= 0 && ![self pullsDown])
if (indexOfSelectedItem >= 0 && ![self pullsDown])
[[self selectedItem] setState:CPOnState];
[self synchronizeTitleAndSelectedItem];
}
[self didChangeValueForKey:@"selectedIndex"];
- (id)objectValue
{
return _selectedIndex;
}
/*!
@@ -306,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];
}
/*!
@@ -391,7 +352,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (CPArray)itemArray
{
return [_menu itemArray];
return [[self menu] itemArray];
}
/*!
@@ -400,7 +361,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (CPMenuItem)itemAtIndex:(unsigned)anIndex
{
return [_menu itemAtIndex:anIndex];
return [[self menu] itemAtIndex:anIndex];
}
/*!
@@ -409,7 +370,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (CPString)itemTitleAtIndex:(unsigned)anIndex
{
return [[_menu itemAtIndex:anIndex] title];
return [[[self menu] itemAtIndex:anIndex] title];
}
/*!
@@ -434,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];
}
/*!
@@ -442,7 +409,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (CPMenuItem)lastItem
{
return [[_menu itemArray] lastObject];
return [[[self menu] itemArray] lastObject];
}
// Getting the Indices of Menu Items
@@ -452,7 +419,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (int)indexOfItem:(CPMenuItem)aMenuItem
{
return [_menu indexOfItem:aMenuItem];
return [[self menu] indexOfItem:aMenuItem];
}
/*!
@@ -461,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];
}
/*!
@@ -481,7 +448,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (int)indexOfItemWithRepresentedObject:(id)anObject
{
return [_menu indexOfItemWithRepresentedObject:anObject];
return [[self menu] indexOfItemWithRepresentedObject:anObject];
}
/*!
@@ -493,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
@@ -508,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.
*/
@@ -529,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];
@@ -577,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];
@@ -589,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
@@ -727,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
@@ -735,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,
@@ -744,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)
/*!
@@ -772,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
+40 -2
View File
@@ -120,7 +120,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
CPProgressIndicatorStyleSizes = [];
// Bar Sttyle
// Bar Style
var prefixes = [
CPProgressIndicatorClassName + @"BezelBorder" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle],
CPProgressIndicatorClassName + @"Bar" + CPProgressIndicatorStyleIdentifiers[CPProgressIndicatorBarStyle],
@@ -290,7 +290,7 @@ var CPProgressIndicatorSpinningStyleColors = nil,
}
/*
Not yet impemented.
Not yet implemented.
*/
- (CPControlTint)controlTint
{
@@ -464,3 +464,41 @@ var CPProgressIndicatorSpinningStyleColors = nil,
}
@end
@implementation CPProgressIndicator (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
if (self = [super initWithCoder:aCoder])
{
_minValue = [aCoder decodeObjectForKey:@"_minValue"];
_maxValue = [aCoder decodeObjectForKey:@"_maxValue"];
_doubleValue = [aCoder decodeObjectForKey:@"_doubleValue"];
_controlSize = [aCoder decodeObjectForKey:@"_controlSize"];
_isIndeterminate = [aCoder decodeObjectForKey:@"_isIndeterminate"];
_style = [aCoder decodeObjectForKey:@"_style"];
_isAnimating = [aCoder decodeObjectForKey:@"_isAnimating"];
_isDisplayedWhenStoppedSet = [aCoder decodeObjectForKey:@"_isDisplayedWhenStoppedSet"];
_isDisplayedWhenStopped = [aCoder decodeObjectForKey:@"_isDisplayedWhenStopped"];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:_minValue forKey:@"_minValue"];
[aCoder encodeObject:_maxValue forKey:@"_maxValue"];
[aCoder encodeObject:_doubleValue forKey:@"_doubleValue"];
[aCoder encodeObject:_controlSize forKey:@"_controlSize"];
[aCoder encodeObject:_isIndeterminate forKey:@"_isIndeterminate"];
[aCoder encodeObject:_style forKey:@"_style"];
[aCoder encodeObject:_isAnimating forKey:@"_isAnimating"];
[aCoder encodeObject:_isDisplayedWhenStoppedSet forKey:@"_isDisplayedWhenStoppedSet"];
[aCoder encodeObject:_isDisplayedWhenStopped forKey:@"_isDisplayedWhenStopped"];
}
@end
+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
+11 -9
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]];
@@ -355,10 +356,11 @@
/*!
Sets the type of border to be drawn around the view.
Valid types are:
CPNoBorder
CPLineBorder
CPBezelBorder
CPGrooveBorder
<pre>
CPNoBorder
CPLineBorder
CPBezelBorder
CPGrooveBorder</pre>
*/
- (void)setBorderType:(CPBorderType)borderType
{
@@ -506,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.
*/
@@ -713,7 +715,7 @@
*/
- (void)setLineScroll:(float)aLineScroll
{
[self setHorizonalLineScroll:aLineScroll];
[self setHorizontalLineScroll:aLineScroll];
[self setVerticalLineScroll:aLineScroll];
}
@@ -796,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
{
@@ -1077,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);
}
}
}
+19 -7
View File
@@ -109,7 +109,6 @@ var RECENT_SEARCH_PREFIX = @" ";
[self setBezelStyle:CPTextFieldRoundedBezel];
[self setBordered:YES];
[self setEditable:YES];
[self setDelegate:self];
[self setContinuous:YES];
var bounds = [self bounds],
@@ -125,6 +124,18 @@ var RECENT_SEARCH_PREFIX = @" ";
_canResignFirstResponder = YES;
}
- (void)viewWillMoveToSuperview:(CPView)aView
{
[super viewWillMoveToSuperview:aView];
// First we remove any observer that may have been in place to avoid memory leakage.
[[CPNotificationCenter defaultCenter] removeObserver:self name:CPControlTextDidChangeNotification object:self];
// Register the observe here if we need to.
if (aView)
[[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(_searchFieldTextDidChange:) name:CPControlTextDidChangeNotification object:self];
}
// Managing Buttons
/*!
Sets the button used to display the search-button image
@@ -181,7 +192,7 @@ var RECENT_SEARCH_PREFIX = @" ";
[_cancelButton setFrame:[self cancelButtonRectForBounds:[self bounds]]];
[_cancelButton setAutoresizingMask:CPViewMinXMargin];
[_cancelButton setTarget:self];
[_cancelButton setAction:@selector(_searchFieldCancel:)];
[_cancelButton setAction:@selector(cancelOperation:)];
[self _updateCancelButtonVisibility];
[self addSubview:_cancelButton];
}
@@ -198,7 +209,7 @@ var RECENT_SEARCH_PREFIX = @" ";
/*!
Resets the cancel button to its default attributes.
This method resets the target, action, regular image, and pressed image. By default, when users click the cancel button, the delete: action message is sent up the responder chain. This method gives you a way to customize the cancel button for specific situations and then reset the button defaults without having to undo changes individually.
This method resets the target, action, regular image, and pressed image. This method gives you a way to customize the cancel button for specific situations and then reset the button defaults without having to undo changes individually.
*/
- (void)resetCancelButton
{
@@ -209,7 +220,7 @@ var RECENT_SEARCH_PREFIX = @" ";
[button setAlternateImage:CPSearchFieldCancelPressedImage];
[button setAutoresizingMask:CPViewMinXMargin];
[button setTarget:self];
[button setAction:@selector(_searchFieldCancel:)];
[button setAction:@selector(cancelOperation:)];
}
// Custom Layout
@@ -420,7 +431,7 @@ var RECENT_SEARCH_PREFIX = @" ";
[_cancelButton setHidden:([[self stringValue] length] === 0)];
}
- (void)controlTextDidChange:(CPNotification)aNotification
- (void)_searchFieldTextDidChange:(CPNotification)aNotification
{
if (![self sendsWholeSearchString])
{
@@ -677,10 +688,11 @@ var RECENT_SEARCH_PREFIX = @" ";
[_partialStringTimer invalidate];
}
- (void)_searchFieldCancel:(id)sender
- (void)cancelOperation:(id)sender
{
[self setObjectValue:@""];
[self _sendPartialString];
[self textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:self userInfo:nil]];
[self _updateCancelButtonVisibility];
}
+21
View File
@@ -1,3 +1,24 @@
/*
* CPSecureTextField.j
* AppKit
*
* Created by Francisco Tolmasky.
* Copyright 2008, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPTextField.j"
+2 -2
View File
@@ -361,9 +361,9 @@ CPSegmentSwitchTrackingMomentary = 2;
}
/*!
Enables/diables the specified segment.
Enables/disables the specified segment.
@param isEnabled \c YES enables the segment
@param aSegment the segment to enable/disble
@param aSegment the segment to enable/disable
@throws CPRangeException if \c aSegment is out of bounds
*/
- (void)setEnabled:(BOOL)isEnabled forSegment:(unsigned)aSegment
+6 -3
View File
@@ -382,9 +382,14 @@ CPCircularSlider = 1;
[self setNeedsDisplay:YES];
}
- (BOOL)isContinuous
{
return (_sendActionOn & CPLeftMouseDraggedMask) !== 0;
}
/*!
@ignore
shoudl we have _continuous?
should we have _continuous?
*/
- (void)setContinuous:(BOOL)flag
{
@@ -425,8 +430,6 @@ var CPSliderMinValueKey = "CPSliderMinValueKey",
{
_altIncrementValue = [aCoder decodeDoubleForKey:CPSliderAltIncrValueKey];
[self setContinuous:YES];
[self _recalculateIsVertical];
[self setNeedsLayout];
+20 -20
View File
@@ -65,7 +65,7 @@
- (id)initView
{
aFrame = CGRectMake(0, 0, CPColorPickerViewWidth, CPColorPickerViewHeight);
aFrame = CGRectMake(0, 0, CPColorPickerViewWidth, CPColorPickerViewHeight);
_contentView = [[CPView alloc] initWithFrame:aFrame];
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
@@ -74,7 +74,7 @@
[_rgbLabel setStringValue: "Red, Green, Blue"];
[_rgbLabel setTextColor:[CPColor blackColor]];
_redLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 35, 15, 20)];
_redLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 37, 15, 20)];
[_redLabel setStringValue: "R"];
[_redLabel setTextColor:[CPColor blackColor]];
@@ -86,18 +86,18 @@
[_redSlider setAutoresizingMask: CPViewWidthSizable];
// red value input box
_redValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 30, 45, 29)];
_redValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 30, 45, 28)];
[_redValue setAutoresizingMask: CPViewMinXMargin];
[_redValue setEditable: YES];
[_redValue setBezeled: YES];
[_redValue setDelegate: self];
[_contentView addSubview: _redValue];
_greenLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 58, 15, 20)];
_greenLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 63, 15, 20)];
[_greenLabel setStringValue: "G"];
[_greenLabel setTextColor:[CPColor blackColor]];
_greenSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 58, aFrame.size.width - 70, 20)];
_greenSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 61, aFrame.size.width - 70, 20)];
[_greenSlider setMaxValue: 1.0];
[_greenSlider setMinValue: 0.0];
[_greenSlider setTarget: self];
@@ -105,18 +105,18 @@
[_greenSlider setAutoresizingMask: CPViewWidthSizable];
// green value input box
_greenValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 53, 45, 29)];
_greenValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 56, 45, 28)];
[_greenValue setAutoresizingMask: CPViewMinXMargin];
[_greenValue setEditable: YES];
[_greenValue setBezeled: YES];
[_greenValue setDelegate: self];
[_contentView addSubview: _greenValue];
_blueLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 81, 15, 20)];
_blueLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 90, 15, 20)];
[_blueLabel setStringValue: "B"];
[_blueLabel setTextColor:[CPColor blackColor]];
_blueSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 81, aFrame.size.width - 70, 20)];
_blueSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 87, aFrame.size.width - 70, 20)];
[_blueSlider setMaxValue: 1.0];
[_blueSlider setMinValue: 0.0];
[_blueSlider setTarget: self];
@@ -124,7 +124,7 @@
[_blueSlider setAutoresizingMask: CPViewWidthSizable];
// blue value input box
_blueValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 76, 45, 29)];
_blueValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 82, 45, 28)];
[_blueValue setAutoresizingMask: CPViewMinXMargin];
[_blueValue setEditable: YES];
[_blueValue setBezeled: YES];
@@ -139,7 +139,7 @@
[_hueLabel setStringValue: "H"];
[_hueLabel setTextColor:[CPColor blackColor]];
_hueSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 145, aFrame.size.width - 70, 20)];
_hueSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 143, aFrame.size.width - 70, 20)];
[_hueSlider setMaxValue: 359.0];
[_hueSlider setMinValue: 0.0];
[_hueSlider setTarget: self];
@@ -147,14 +147,14 @@
[_hueSlider setAutoresizingMask: CPViewWidthSizable];
// hue value input box
_hueValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 140, 45, 29)];
_hueValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 138, 45, 28)];
[_hueValue setAutoresizingMask: CPViewMinXMargin];
[_hueValue setEditable: YES];
[_hueValue setBezeled: YES];
[_hueValue setDelegate: self];
[_contentView addSubview: _hueValue];
_saturationLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 168, 15, 20)];
_saturationLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 170, 15, 20)];
[_saturationLabel setStringValue: "S"];
[_saturationLabel setTextColor:[CPColor blackColor]];
@@ -166,18 +166,18 @@
[_saturationSlider setAutoresizingMask: CPViewWidthSizable];
// saturation value input box
_saturationValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 163, 45, 29)];
_saturationValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 164, 45, 28)];
[_saturationValue setAutoresizingMask: CPViewMinXMargin];
[_saturationValue setEditable: YES];
[_saturationValue setBezeled: YES];
[_saturationValue setDelegate: self];
[_contentView addSubview: _saturationValue];
_brightnessLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 191, 15, 20)];
_brightnessLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 196, 15, 20)];
[_brightnessLabel setStringValue: "B"];
[_brightnessLabel setTextColor:[CPColor blackColor]];
_brightnessSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 191, aFrame.size.width - 70, 20)];
_brightnessSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 194, aFrame.size.width - 70, 20)];
[_brightnessSlider setMaxValue: 100.0];
[_brightnessSlider setMinValue: 0.0];
[_brightnessSlider setTarget: self];
@@ -185,7 +185,7 @@
[_brightnessSlider setAutoresizingMask: CPViewWidthSizable];
// brightness value input box
_brightnessValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 186, 45, 29)];
_brightnessValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 190, 45, 28)];
[_brightnessValue setAutoresizingMask: CPViewMinXMargin];
[_brightnessValue setEditable: YES];
[_brightnessValue setBezeled: YES];
@@ -197,7 +197,7 @@
[_hexLabel setTextColor:[CPColor blackColor]];
//hex input box
_hexValue = [[CPTextField alloc] initWithFrame: CGRectMake(32, 225, 80, 29)];
_hexValue = [[CPTextField alloc] initWithFrame: CGRectMake(32, 225, 80, 28)];
[_hexValue setEditable: YES];
[_hexValue setBezeled: YES];
[_hexValue setDelegate: self];
@@ -240,7 +240,7 @@
return (mode == CPSliderColorPickerMode) ? YES : NO;
}
-(void)sliderChanged:(id)sender
- (void)sliderChanged:(id)sender
{
var newColor,
colorPanel = [self colorPanel],
@@ -274,7 +274,7 @@
[colorPanel setColor: newColor];
}
-(void)setColor:(CPColor)aColor
- (void)setColor:(CPColor)aColor
{
[self updateRGBSliders: aColor];
[self updateHSBSliders: aColor];
@@ -282,7 +282,7 @@
[self updateLabels];
}
-(void)updateHSBSliders:(CPColor)aColor
- (void)updateHSBSliders:(CPColor)aColor
{
var hsb = [aColor hsbComponents];
+48 -13
View File
@@ -25,6 +25,7 @@
CPSoundLoadStateEmpty = 0;
CPSoundLoadStateLoading = 1;
CPSoundLoadStateCanBePlayed = 2;
CPSoundLoadStateError = 3;
CPSoundPlayBackStatePlay = 0;
CPSoundPlayBackStateStop = 1;
@@ -60,14 +61,24 @@ CPSoundPlayBackStatePause = 2;
_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;
@@ -77,7 +88,7 @@ CPSoundPlayBackStatePause = 2;
Initialize with the sound contents of the URL represented by aFile.
@param aFile CPString the path of the sound
@param byRef ignored (Cocoa compatibibility)
@param byRef ignored (Cocoa compatibility)
*/
- (id)initWithContentsOfFile:(CPString)aFile byReference:(BOOL)byRef
{
@@ -94,7 +105,7 @@ CPSoundPlayBackStatePause = 2;
Initialize with the sound contents of the file located at aURL.
@param aURL CPURL containing the URL of the sound
@param byRef ignored (Cocoa compatibibility)
@param byRef ignored (Cocoa compatibility)
*/
- (id)initWithContentsOfURL:(CPURL)aURL byReference:(BOOL)byRef
{
@@ -105,7 +116,7 @@ CPSoundPlayBackStatePause = 2;
Initialize with the sound contents of someData.
@param someData CPData containing the sound
@param byRef ignored (Cocoa compatibibility)
@param byRef ignored (Cocoa compatibility)
*/
- (id)initWithData:(CPData)someData
{
@@ -137,31 +148,45 @@ CPSoundPlayBackStatePause = 2;
[self stop];
}
/*! @ignore
*/
- (void)_soundError
{
_loadStatus = CPSoundLoadStateError;
CPLog.error("Cannot load sound. Maybe the format of your sound is not compatible with your browser.");
}
#pragma mark -
#pragma mark Media controls
/*!
Play the sound.
@return YES when the receiver is playing its audio data, NO otherwise.
*/
- (void)play
- (BOOL)play
{
if ((_loadStatus !== CPSoundLoadStateCanBePlayed)
|| (_playBackStatus === CPSoundPlayBackStatePlay))
return;
return NO;
_audioTag.play();
_playBackStatus = CPSoundPlayBackStatePlay;
return YES;
}
/*!
Stop the sound.
@return YES when the receiver is playing its audio data, NO otherwise.
*/
- (void)stop
- (BOOL)stop
{
if ((_loadStatus !== CPSoundLoadStateCanBePlayed)
|| (_playBackStatus === CPSoundPlayBackStateStop))
return;
return NO;
_audioTag.pause();
_audioTag.currentTime = 0.0;
@@ -169,32 +194,42 @@ CPSoundPlayBackStatePause = 2;
if (_delegate && [_delegate respondsToSelector:@selector(sound:didFinishPlaying:)])
[_delegate sound:self didFinishPlaying:YES];
return YES;
}
/*!
Pause the sound.
@return YES when the receiver is playing its audio data, NO otherwise.
*/
- (void)pause
- (BOOL)pause
{
if ((_loadStatus !== CPSoundLoadStateCanBePlayed)
|| (_playBackStatus === CPSoundPlayBackStatePause))
return;
return NO;
_audioTag.pause();
_playBackStatus = CPSoundPlayBackStatePause;
return YES;
}
/*!
Resume playback of a paused sound.
@return YES when the receiver is playing its audio data, NO otherwise.
*/
- (void)resume
- (BOOL)resume
{
if ((_loadStatus !== CPSoundLoadStateCanBePlayed)
|| (_playBackStatus !== CPSoundPlayBackStatePause))
return;
return NO;
_audioTag.play();
_playBackStatus = CPSoundPlayBackStatePlay;
return YES;
}
/*!
+160 -6
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];
@@ -644,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:)])
@@ -676,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
{
@@ -741,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]];
+5 -103
View File
@@ -38,8 +38,8 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
int _maxValue @accessors(property=maxValue);
int _minValue @accessors(property=minValue);
_CPContinuousButton _buttonDown;
_CPContinuousButton _buttonUp;
CPButton _buttonDown;
CPButton _buttonUp;
}
#pragma mark -
@@ -87,14 +87,14 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
[self setDoubleValue:0.0];
_buttonUp = [[_CPContinuousButton alloc] initWithFrame:CPRectMake(aFrame.size.width - CPStepperButtonsSize.width, 0, CPStepperButtonsSize.width, CPStepperButtonsSize.height)];
_buttonUp = [[CPButton alloc] initWithFrame: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 = [[_CPContinuousButton alloc] initWithFrame:CPRectMake(aFrame.size.width - CPStepperButtonsSize.width, CPStepperButtonsSize.height, CPStepperButtonsSize.width, CPStepperButtonsSize.height - 1)];
_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:)];
@@ -152,7 +152,7 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
}
/*! set the current value of the stepper
@param aValue a float contaning the value
@param aValue a float containing the value
*/
- (void)setDoubleValue:(float)aValue
{
@@ -244,101 +244,3 @@ var CPStepperButtonsSize = CPSizeMake(19, 13);
}
@end
/*! This is a subclass of CPButton that allows to send continuous action.
This may should be include in CPButton..
*/
@implementation _CPContinuousButton : CPButton
{
CPTimer _continuousDelayTimer;
CPTimer _continuousTimer;
float _periodicDelay;
float _periodicInterval;
}
- (void)initWithFrame:(CGRect)aFrame
{
if (self = [super initWithFrame:aFrame])
{
_periodicInterval = 0.05;
_periodicDelay = 0.5;
}
return self;
}
- (void)setPeriodicDelay:(float)aDelay interval:(float)anInterval
{
_periodicDelay = aDelay;
_periodicInterval = anInterval;
}
- (void)mouseDown:(CPEvent)anEvent
{
if ([self isContinuous])
{
_continuousDelayTimer = [CPTimer scheduledTimerWithTimeInterval:_periodicDelay callback: function()
{
if (!_continuousTimer)
_continuousTimer = [CPTimer scheduledTimerWithTimeInterval:_periodicInterval target:self selector:@selector(onContinousEvent:) userInfo:anEvent repeats:YES];
}
repeats:NO];
}
[super mouseDown:anEvent];
}
- (void)onContinousEvent:(CPTimer)aTimer
{
if (_target && _action && [_target respondsToSelector:_action])
[_target performSelector:_action withObject:self];
}
- (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp
{
[self invalidateTimers];
[super stopTracking:lastPoint at:aPoint mouseIsUp:mouseIsUp];
}
- (void)invalidateTimers
{
if (_continuousTimer)
{
[_continuousTimer invalidate];
_continuousTimer = nil;
}
if (_continuousDelayTimer)
{
[_continuousDelayTimer invalidate];
_continuousDelayTimer = nil;
}
}
@end
@implementation _CPContinuousButton (CPCodingCompliance)
- (id)initWithCoder:(CPCoder)aCoder
{
if (self = [super initWithCoder:aCoder])
{
_periodicDelay = [aCoder decodeObjectForKey:@"_periodicDelay"];
_periodicInterval = [aCoder decodeObjectForKey:@"_periodicInterval"];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[self invalidateTimers];
[aCoder encodeObject:_periodicDelay forKey:@"_periodicDelay"];
[aCoder encodeObject:_periodicInterval forKey:@"_periodicInterval"];
}
@end
+72
View File
@@ -0,0 +1,72 @@
/*
* CPString+Additions.j
* AppKit
*
* Created by Randy Luecke
* Copyright 2011, RCLConcepts, LLC.
*
* 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
*/
/*
AppKit adds two methods to the CPString class to support drawing string directly in an CPView.
AppKit also adds similar methods to CPAttributedString.
The two drawing methods draw a string object with a single set of attributes that apply to the entire string.
To draw a string with multiple attributes, such as multiple text fonts, you must use an attributed string.
*/
@implementation CPString (AppKitAdditions)
/*!
Draws a string in the current graphics context.
This method applies the attributes to the entier string
and displays it on a single "infinately long" line.
@param aPoint - The starting point to draw the string
@param attributes - the dictionary of attributes to apply to the string
*/
- (void)drawAtPoint:(CGPoint)aPoint withAttributes:(CPDictionary)attributes
{
var context = [[CPGraphicsContext currentContext] graphicsPort],
run = _CTRunCreate([self copy], attributes);
CGContextSetTextPosition(context, aPoint.x, aPoint.y);
CTRunDraw(run, context, nil);
}
/*!
Draws a string in the current graphics context.
This method applies the attributes to the entier string
and displays it within the given rect.
@param aRect - The rect for which the string should be drawn into
@param attributes - the dictionary of attributes to apply to the string
*/
- (void)drawInRect:(CGRect)aRect withAttributes:(CPDictionary)attributes
{
var context = [[CPGraphicsContext currentContext] graphicsPort],
string = [[CPAttributedString alloc] initWithString:self attributes:attributes];
frameSetter = CTFramesetterCreateWithAttributedString(string),
path = CGPathCreateMutable();
CGPathAddRect(path, nil, aRect);
var frame = CTFramesetterCreateFrame(frameSetter, CPMakeRange(0, [string length]), path, nil);
CTFrameDraw(frame, context);
}
@end
+49 -4
View File
@@ -16,6 +16,14 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
CPTabViewWillSelectTabViewItemSelector = 4,
CPTabViewDidChangeNumberOfTabViewItemsSelector = 8;
/*!
@ingroup appkit
@class CPTabView
A CPTabView object presents a tabbed interface where each page is one a
complete view hiearchy of its own. The user can navigate between various
pages by clicking on the tab headers.
*/
@implementation CPTabView : CPView
{
CPArray _items;
@@ -26,6 +34,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
CPNumber _selectedIndex;
CPTabViewType _type;
CPFont _font;
id _delegate;
unsigned _delegateSelectors;
@@ -74,8 +83,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
}
/*!
Inserts a CPTabViewItem into the tab view
at the specified index.
Inserts a CPTabViewItem into the tab view at the specified index.
@param aTabViewItem the item to insert
@param anIndex the index for the item
*/
@@ -85,7 +93,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
[self _updateItems];
[self _repositionTabs];
[aTabViewItem _setTabView:self];
if (_delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
@@ -110,7 +118,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
[self _updateItems];
[self _repositionTabs];
[aTabViewItem _setTabView:nil];
if (_delegateSelectors & CPTabViewDidChangeNumberOfTabViewItemsSelector)
@@ -121,6 +129,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
/*!
Returns the index of the specified item
@param aTabViewItem the item to find the index for
@return the index of aTabViewItem or CPNotFound
*/
- (int)indexOfTabViewItem:(CPTabViewItem)aTabViewItem
{
@@ -130,6 +139,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
/*!
Returns the index of the CPTabViewItem with the specified identifier.
@param anIdentifier the identifier of the item
@return the index of the tab view item identified by anIdentifier, or CPNotFound
*/
- (int)indexOfTabViewItemWithIdentifier:(CPString)anIdentifier
{
@@ -142,6 +152,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
/*!
Returns the number of items in the tab view.
@return the number of tab view items in the receiver
*/
- (unsigned)numberOfTabViewItems
{
@@ -150,6 +161,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
/*!
Returns the CPTabViewItem at the specified index.
@return a tab view item, or nil
*/
- (CPTabViewItem)tabViewItemAtIndex:(unsigned)anIndex
{
@@ -158,6 +170,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
/*!
Returns the array of items that backs this tab view.
@return a copy of the array of items in the receiver
*/
- (CPArray)tabViewItems
{
@@ -261,12 +274,36 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
/*!
Returns the current item being displayed.
@return the tab view item currenly being displayed by the receiver
*/
- (CPTabViewItem)selectedTabViewItem
{
return [_items objectAtIndex:_selectedIndex];
}
// Modifying the font
/*!
Returns the font for tab label text.
@return the font for tab label text
*/
- (CPFont)font
{
return _font;
}
/*!
Sets the font for tab label text to font.
@param font the font the receiver should use for tab label text
*/
- (void)setFont:(CPFont)font
{
if ([_font isEqual:font])
return;
_font = font;
[_tabs setFont:_font];
}
//
/*!
Sets the tab view type.
@@ -314,6 +351,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
/*!
Returns the tab view type.
@return the tab view type of the receiver
*/
- (CPTabViewType)tabViewType
{
@@ -322,6 +360,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
/*!
Returns the receiver's delegate.
@return the receiver's delegate
*/
- (id)delegate
{
@@ -415,6 +454,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
var CPTabViewItemsKey = "CPTabViewItemsKey",
CPTabViewSelectedItemKey = "CPTabViewSelectedItemKey",
CPTabViewTypeKey = "CPTabViewTypeKey",
CPTabViewFontKey = "CPTabViewFontKey",
CPTabViewDelegateKey = "CPTabViewDelegateKey";
@implementation CPTabView (CPCoding)
@@ -425,12 +465,16 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
{
[self _init];
_font = [aCoder decodeObjectForKey:CPTabViewFontKey];
[_tabs setFont:_font];
_items = [aCoder decodeObjectForKey:CPTabViewItemsKey];
[self _updateItems];
[self _repositionTabs];
var selected = [aCoder decodeObjectForKey:CPTabViewSelectedItemKey];
if (selected)
[self selectTabViewItem:selected];
@@ -450,6 +494,7 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
[aCoder encodeObject:[self selectedTabViewItem] forKey:CPTabViewSelectedItemKey];
[aCoder encodeInt:_type forKey:CPTabViewTypeKey];
[aCoder encodeObject:_font forKey:CPTabViewFontKey];
[aCoder encodeConditionalObject:_delegate forKey:CPTabViewDelegateKey];
}
+3 -3
View File
@@ -145,8 +145,8 @@ CPPressedTab = 2;
// Assigning an Auxiliary View
/*!
Sets the tab's auxillary view.
@param anAuxillaryView the new auxillary view
Sets the tab's auxiliary view.
@param anAuxiliaryView the new auxiliary view
*/
- (void)setAuxiliaryView:(CPView)anAuxiliaryView
{
@@ -154,7 +154,7 @@ CPPressedTab = 2;
}
/*!
Returns the tab's auxillary view
Returns the tab's auxiliary view
*/
- (CPView)auxiliaryView
{
+177 -37
View File
@@ -37,9 +37,12 @@ CPTableColumnUserResizingMask = 1 << 1;
@class CPTableColumn
A CPTableColumn contains a dataview to display for its column of the CPTableView.
A CPTableColumn determines its own size constrains and resizing behaviour.
A CPTableColumn determines its own size constrains and resizing behavior.
The default dataview is a CPTextField but you can set it to any view you'd like. See -setDataView:
The default dataview is a CPTextField but you can set it to any view you'd like. See -setDataView: for documentation including theme states.
To customize the text of the column header you can simply call setStringValue: on the headerview of a table column.
For example: [[myTableColumn headerView] setStringValue:"My Title"];
*/
@implementation CPTableColumn : CPObject
{
@@ -62,11 +65,6 @@ CPTableColumnUserResizingMask = 1 << 1;
BOOL _disableResizingPosting @accessors(property=disableResizingPosting);
}
+ (Class)_binderClassForBinding:(CPString)theBinding
{
return [CPBinder class];
}
/*!
@ignore
*/
@@ -197,7 +195,7 @@ CPTableColumnUserResizingMask = 1 << 1;
}
/*!
Sets the minimum width of the column.
Sets the minimum width of the column.
Default value is 10.
*/
- (void)setMinWidth:(float)aMinWidth
@@ -225,7 +223,7 @@ CPTableColumnUserResizingMask = 1 << 1;
}
/*!
Sets the maximum width of the table column.
Sets the maximum width of the table column.
Default value is: 1000000
*/
- (void)setMaxWidth:(float)aMaxWidth
@@ -253,13 +251,15 @@ CPTableColumnUserResizingMask = 1 << 1;
}
/*!
Set the resizing mask of the column.
By default the column can be resized automatically with the tableview and manaully by the user
<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
{
@@ -276,7 +276,7 @@ CPTableColumnUserResizingMask = 1 << 1;
}
/*!
Sizes the column to fix the column header text.
Sizes the column to fix the column header text.
*/
- (void)sizeToFit
{
@@ -294,7 +294,12 @@ CPTableColumnUserResizingMask = 1 << 1;
/*!
Sets the header view for the column.
The headerview handles the display of sort indicators, text, etc
The headerview handles the display of sort indicators, text, etc.
If you do not want a headerview for you table you should call setHeaderView: on your CPTableView instance.
Passing nil here will throw an exception.
In order to customize the text of the column header see - (CPView)headerView;
*/
- (void)setHeaderView:(CPView)aView
{
@@ -310,7 +315,10 @@ CPTableColumnUserResizingMask = 1 << 1;
}
/*!
Returns the headerview for the column
Returns the headerview for the column.
In order to change the text of the headerview for a column you should call setStringValue: on the headerview.
For example: [[myTableColumn headerView] setStringValue:"My Column"];
*/
- (CPView)headerView
{
@@ -324,16 +332,62 @@ CPTableColumnUserResizingMask = 1 << 1;
individual cell that is shown. As a result, changes made after calling this method won't be reflected.
Example:
@code
[tableColumn setDataView:someView]; // snapshot taken
[[tableColumn dataView] setSomething:x]; //won't work
@endcode
This doesn't work because the snapshot is taken before the new property is applied. Instead, do:
@code
[someView setSomething:x];
[tableColumn setDataView:someView];
@endcode
REMEMBER: you should implement CPKeyedArchiving otherwise you might see unexpected results
@note you should implement CPKeyedArchiving otherwise you might see unexpected results.
This is done by adding the following methods to your class:
@endnote
@code
- (id)initWithCoder(CPCoder)aCoder;
- (void)encodeWithCoder:(CPCoder)aCoder;
@endcode
Example:
Say you have two instance variables in your object that need to be set up each time an object is create.
We will call these instance variables "image" and "text".
Your CPCoding methods will look like the following:
@code
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
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 Themeing
When you set a dataview and it is added to the tableview the theme state will be set to \c CPThemeStateTableDataView
When the dataview becomes selected the theme state will be set to \c CPThemeStateSelectedDataView.
If the dataview shows up in a group row of the tableview the theme state will be set to \c CPThemeStateGroupRow.
You should overide \c setThemeState: and \c unsetThemeState: to handle these theme state changes in your dataview.
*/
- (void)setDataView:(CPView)aView
{
@@ -355,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.
*/
@@ -374,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])
@@ -392,7 +446,7 @@ CPTableColumnUserResizingMask = 1 << 1;
//Setting the Identifier
/*
/*!
Sets the receiver identifier to anIdentifier.
*/
- (void)setIdentifier:(id)anIdentifier
@@ -400,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
@@ -410,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
@@ -418,9 +472,9 @@ 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
{
@@ -428,7 +482,7 @@ CPTableColumnUserResizingMask = 1 << 1;
}
/*!
Sets the sort descriptor prototype for the column.
Sets the sort descriptor prototype for the column.
*/
- (void)setSortDescriptorPrototype:(CPSortDescriptor)aSortDescriptor
{
@@ -444,7 +498,7 @@ CPTableColumnUserResizingMask = 1 << 1;
}
/*!
If NO the tablecolumn will no longer be visisble in the tableview
If NO the tablecolumn will no longer be visible in the tableview
If YES the tablecolumn will be visible in the tableview.
*/
- (void)setHidden:(BOOL)shouldBeHidden
@@ -469,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.
*/
@@ -501,7 +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];
@@ -510,7 +597,10 @@ CPTableColumnUserResizingMask = 1 << 1;
[[self tableView] _establishBindingsIfUnbound:anObject];
}
- (void)prepareDataView:(CPView)aDataView forRow:(unsigned)aRow
/*!
@ignore
*/
- (void)_prepareDataView:(CPView)aDataView forRow:(unsigned)aRow
{
var bindingsDictionary = [CPBinder allBindingsForObject:self],
keys = [bindingsDictionary allKeys];
@@ -556,16 +646,46 @@ CPTableColumnUserResizingMask = 1 << 1;
}
}
/*!
@ignore
*/
- (void)_reverseSetDataView:(CPView)aDataView forRow:(unsigned)aRow
{
var bindingsDictionary = [CPBinder allBindingsForObject:self],
keys = [bindingsDictionary allKeys],
newValue = [aDataView valueForKey:@"objectValue"];
for (var i = 0, count = [keys count]; i < count; i++)
{
var bindingName = keys[i],
bindingPath = [aDataView _replacementKeyPathForBinding:bindingName],
binding = [bindingsDictionary objectForKey:bindingName],
bindingInfo = binding._info,
destination = [bindingInfo objectForKey:CPObservedObjectKey],
keyPath = [bindingInfo objectForKey:CPObservedKeyPathKey],
dotIndex = keyPath.lastIndexOf(".");
if (dotIndex === CPNotFound)
[[destination valueForKeyPath:keyPath] replaceObjectAtIndex:aRow withObject:newValue];
else
{
var firstPart = keyPath.substring(0, dotIndex),
secondPart = keyPath.substring(dotIndex + 1),
firstValue = [destination valueForKeyPath:firstPart];
if ([firstValue isKindOfClass:CPArray])
[[firstValue objectAtIndex:aRow] setValue:newValue forKeyPath:secondPart];
else
[[firstValue valueForKeyPath:secondPart] replaceObjectAtIndex:aRow withObject:newValue];
}
}
}
//- (void)objectValue
//{
// return nil;
//}
- (void)setValue:(CPArray)content
{
[[self tableView] reloadData];
}
@end
var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
@@ -581,6 +701,9 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
@implementation CPTableColumn (CPCoding)
/*!
@ignore
*/
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
@@ -608,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];
@@ -629,31 +755,45 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
@end
@implementation CPTableColumn (NSInCompatibility)
/*!
@ignore
*/
- (void)setHeaderCell:(CPView)aView
{
[CPException raise:CPUnsupportedMethodException
reason:@"setHeaderCell: is not supported. Use -setHeaderView:aView instead."];
}
/*!
@ignore
*/
- (CPView)headerCell
{
[CPException raise:CPUnsupportedMethodException
reason:@"headCell is not supported. Use -headerView instead."];
}
/*!
@ignore
*/
- (void)setDataCell:(CPView)aView
{
[CPException raise:CPUnsupportedMethodException
reason:@"setDataCell: is not supported. Use -setDataView:aView instead."];
}
/*!
@ignore
*/
- (CPView)dataCell
{
[CPException raise:CPUnsupportedMethodException
reason:@"dataCell is not supported. Use -dataView instead."];
}
/*!
@ignore
*/
- (id)dataCellForRow:(int)row
{
[CPException raise:CPUnsupportedMethodException
+11 -12
View File
@@ -212,7 +212,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
- (CGRect)headerRectOfColumn:(int)aColumnIndex
{
var headerRect = [self bounds],
var headerRect = CGRectMakeCopy([self bounds]),
columnRect = [_tableView rectOfColumn:aColumnIndex];
headerRect.origin.x = _CGRectGetMinX(columnRect);
@@ -592,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];
}
@@ -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);
+466 -262
View File
File diff suppressed because it is too large Load Diff
+135 -30
View File
@@ -84,7 +84,6 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
CPColor _textFieldBackgroundColor;
id _placeholderString;
BOOL _currentValueIsPlaceholder;
id _delegate;
@@ -486,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])
@@ -502,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);
@@ -561,7 +584,9 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
[self _setStringValue:element.value];
CPTextFieldInputResigning = YES;
element.blur();
if (CPTextFieldInputIsActive)
element.blur();
if (!CPTextFieldInputDidBlur)
CPTextFieldBlurFunction();
@@ -679,30 +704,87 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
- (void)keyDown:(CPEvent)anEvent
{
var characters = [anEvent characters];
// Treat \r and \n the same. See issue #710.
if (characters === CPNewlineCharacter || characters === CPCarriageReturnCharacter)
{
// selectText: has a side effect - it can change first responder of the window
// we have to prevent such behaviour inside this method because target should be able to change first responder after receiving action.
[self selectText:nil];
if ([anEvent _couldBeKeyEquivalent] && [self performKeyEquivalent:anEvent])
return;
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 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
@@ -721,11 +803,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];
}
@@ -919,6 +1009,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
@@ -940,6 +1032,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
@@ -1018,8 +1112,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];
@@ -1313,6 +1414,10 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
newValue = [options objectForKey:CPNotApplicablePlaceholderBindingOption] || @"Not Applicable";
break;
case CPNullMarker:
newValue = [options objectForKey:CPNullPlaceholderBindingOption] || @"";
break;
}
[_source setPlaceholderString:newValue];
+6 -6
View File
@@ -179,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)
@@ -198,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];
@@ -455,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];
}
@@ -633,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)
@@ -665,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)
@@ -1129,7 +1129,7 @@ var CPThemeStateAutoCompleting = @"CPThemeStateAutoCompleting",
return [];
}
// // Alows the delegate to provide a string to be displayed as a proxy for the given represented object.
// // Allows the delegate to provide a string to be displayed as a proxy for the given represented object.
// // If you return nil or do not implement this method, then representedObject is displayed as the string.
- (CPString)tokenField:(CPTokenField)tokenField displayStringForRepresentedObject:(id)representedObject
{
+8 -4
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?
@@ -849,6 +849,10 @@ var _CPToolbarItemInfoMake = function(anIndex, aView, aLabel, aMinWidth)
view = [[_CPToolbarItemView alloc] initWithToolbarItem:item toolbar:self];
_viewsForToolbarItems[[item UID]] = view;
if ([item toolTip] && [view respondsToSelector:@selector(setToolTip:)])
[view setToolTip:[item toolTip]];
[self addSubview:view];
_minWidth += [view minSize].width + TOOLBAR_ITEM_MARGIN;
@@ -1011,7 +1015,7 @@ var TOP_MARGIN = 5.0,
_labelSize = [_labelField frame].size;
_minSize = CGSizeMake(MAX(_labelSize.width, minSize.width), _labelSize.height + minSize.height + LABEL_MARGIN + TOP_MARGIN);
_maxSize = CGSizeMake(MAX(_labelSize.width, minSize.width), 100000000.0);
_maxSize = CGSizeMake(MIN(_labelSize.width, maxSize.width), 100000000.0);
[_toolbar tile];
}
+267
View File
@@ -0,0 +1,267 @@
/*
* CPUserDefaultsController.j
* AppKit
*
* Portions based on NSUserDefaultsController.m (2009-06-04) in Cocotron (http://www.cocotron.org/)
* Copyright (c) 2006-2007 Christopher J. W. Lloyd
*
* Created by Alexander Ljungberg.
* Copyright 2011, WireLoad Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPString.j>
@import <AppKit/CPController.j>
var SharedUserDefaultsController = nil;
@implementation CPUserDefaultsController : CPController
{
CPUserDefaults _defaults @accessors(readonly, property=defaults);
CPDictionary _initialValues @accessors(property=initialValues);
BOOL _appliesImmediately @accessors(property=appliesImmediately);
}
+ (id)sharedUserDefaultsController
{
if (!SharedUserDefaultsController)
SharedUserDefaultsController = [[CPUserDefaultsController alloc] initWithDefaults:nil initialValues:nil];
return SharedUserDefaultsController;
}
- (id)initWithDefaults:(CPUserDefaults)someDefaults initialValues:(CPDictionary)initialValues
{
if (self = [super init])
{
if (!someDefaults)
someDefaults = [CPUserDefaults standardUserDefaults];
_defaults = someDefaults;
_initialValues = [initialValues copy];
_appliesImmediately = YES;
_valueProxy = [[_CPUserDefaultsControllerProxy alloc] initWithController:self];
}
return self;
}
- (id)values
{
return _valueProxy;
}
- (BOOL)hasUnappliedChanges
{
return [_valueProxy hasUnappliedChanges];
}
- (void)save:(id)sender
{
[_valueProxy save];
}
- (void)revert:(id)sender
{
[_valueProxy revert];
}
- (void)revertToInitialValues:(id)sender
{
[_valueProxy revertToInitialValues];
}
@end
var CPUserDefaultsControllerSharedKey = "CPUserDefaultsControllerSharedKey";
@implementation CPUserDefaultsController (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
if ([aCoder decodeBoolForKey:CPUserDefaultsControllerSharedKey])
return [CPUserDefaultsController sharedUserDefaultsController];
self = [super initWithCoder:aCoder];
if (self)
{
[CPException raise:CPUnsupportedMethodException reason:@"decoding of non-shared CPUserDefaultsController not implemented"];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
if (self === SharedUserDefaultsController)
{
[aCoder encodeBool:YES forKey:CPUserDefaultsControllerSharedKey];
return;
}
[CPException raise:CPUnsupportedMethodException reason:@"encoding of non-shared CPUserDefaultsController not implemented"];
}
@end
@implementation _CPUserDefaultsControllerProxy : CPObject
{
CPUserDefaultsController _controller;
// TODO Could be optimised with a JS dict.
CPMutableDictionary _cachedValues;
}
- (id)initWithController:(CPUserDefaultsController)aController
{
if (self = [super init])
{
_controller = aController;
_cachedValues = [CPMutableDictionary dictionary];
[[CPNotificationCenter defaultCenter] addObserver:self selector:@selector(userDefaultsDidChange:) name:CPUserDefaultsDidChangeNotification object:[_controller defaults]];
}
return self;
}
- (void)dealloc
{
// FIXME No dealloc in Cappuccino.
[[CPNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
- (id)valueForKey:(CPString)aKey
{
var value = [_cachedValues objectForKey:aKey];
if (value === nil)
{
value = [[_controller defaults] objectForKey:aKey];
if (value === nil)
value = [[_controller initialValues] objectForKey:aKey];
if (value !== nil)
[_cachedValues setObject:value forKey:aKey];
}
return value;
}
- (void)setValue:(id)aValue forKey:(CPString)aKey
{
[self willChangeValueForKey:aKey];
[_cachedValues setObject:aValue forKey:aKey];
if ([_controller appliesImmediately])
[[_controller defaults] setObject:aValue forKey:aKey];
[self didChangeValueForKey:aKey];
}
- (void)revert
{
var keys = [_cachedValues allKeys],
keysCount = [keys count];
while(keysCount--)
{
var key = keys[keysCount];
[self willChangeValueForKey:key];
[_cachedValues removeObjectForKey:key];
[self didChangeValueForKey:key];
}
}
- (void)save
{
var keys = [_cachedValues allKeys],
keysCount = [keys count];
while(keysCount--)
{
var key = keys[keysCount];
[[_controller defaults] setObject:[_cachedValues objectForKey:key] forKey:key];
}
}
- (void)revertToInitialValues
{
var initial = [_controller initialValues],
keys = [_cachedValues allKeys],
keysCount = [keys count];
while(keysCount--)
{
var key = keys[keysCount];
[self willChangeValueForKey:key];
var initialValue = [initial objectForKey:key];
if (initialValue !== nil)
[_cachedValues setObject:initialValue forKey:key];
else
[_cachedValues removeObjectForKey:key];
[self didChangeValueForKey:key];
}
}
- (void)userDefaultsDidChange:(CPNotification)aNotification
{
var defaults = [_controller defaults],
keys = [_cachedValues allKeys],
keysCount = [keys count];
while(keysCount--)
{
var key = keys[keysCount],
value = [_cachedValues objectForKey:key],
newValue = [defaults objectForKey:key];
if (![value isEqual:newValue])
{
[self willChangeValueForKey:key];
[_cachedValues setObject:newValue forKey:key];
[self didChangeValueForKey:key];
}
}
}
- (BOOL)hasUnappliedChanges
{
var defaults = [_controller defaults],
keys = [_cachedValues allKeys],
keysCount = [keys count];
while(keysCount--)
{
var key = keys[keysCount],
value = [_cachedValues objectForKey:key],
newValue = [defaults objectForKey:key];
if (![value isEqual:newValue])
return YES;
}
return NO;
}
@end
+60 -11
View File
@@ -186,6 +186,9 @@ var CPViewFlags = { },
CPView _previousKeyView;
unsigned _viewClassFlags;
// ToolTips
CPString _toolTip @accessors(property=toolTip);
}
/*
@@ -705,7 +708,7 @@ var CPViewFlags = { },
Sets the frame size of the receiver to the dimensions and origin of the provided rectangle in the coordinate system
of the superview. The method also posts an CPViewFrameDidChangeNotification to the notification
center if the receiver is configured to do so. If the frame is the same as the current frame, the method simply
returns (and no notificaion is posted).
returns (and no notification is posted).
@param aFrame the rectangle specifying the new origin and size of the receiver
*/
- (void)setFrame:(CGRect)aFrame
@@ -1284,6 +1287,14 @@ var CPViewFlags = { },
return view !== nil;
}
/*!
Returns YES if the view is not hidden, has no hidden ancestor and doesn't belong to a hidden window.
*/
- (BOOL)_isVisible
{
return ![self isHiddenOrHasHiddenAncestor] && [[self window] isVisible];
}
/*!
Called when the return value of isHiddenOrHasHiddenAncestor becomes YES,
e.g. when this view becomes hidden due to a setHidden:YES message to
@@ -1735,7 +1746,7 @@ setBoundsOrigin:
@param aLocation the lower-left corner coordinate of \c anImage
@param mouseOffset the distance from the \c -mouseDown: location and the current location
@param anEvent the \c -mouseDown: that triggered the drag
@param aPastebaord the pasteboard that holds the drag data
@param aPasteboard the pasteboard that holds the drag data
@param aSourceObject the drag operation controller
@param slideBack Whether the image should 'slide back' if the drag is rejected
*/
@@ -1750,7 +1761,7 @@ setBoundsOrigin:
@param aLocation the top-left corner coordinate of \c aView
@param mouseOffset the distance from the \c -mouseDown: location and the current location
@param anEvent the \c -mouseDown: that triggered the drag
@param aPastebaord the pasteboard that holds the drag data
@param aPasteboard the pasteboard that holds the drag data
@param aSourceObject the drag operation controller
@param slideBack Whether the view should 'slide back' if the drag is rejected
*/
@@ -2100,7 +2111,7 @@ setBoundsOrigin:
/*!
Scrolls the clip view to a specified point
@param the clip view to scoll
@param the clip view to scroll
@param the point to scroll to
*/
- (void)scrollClipView:(CPClipView)aClipView toPoint:(CGPoint)aPoint
@@ -2121,6 +2132,20 @@ setBoundsOrigin:
@implementation CPView (KeyView)
/*!
Overridden by subclasses to handle a key equivalent.
If the receivers key equivalent is the same as the characters of the key-down event theEvent,
as returned by \ref CPEvent::charactersIgnoringModifiers "[anEvent charactersIgnoringModifiers]",
the receiver should take the appropriate action and return \c YES. Otherwise, it should return
the result of invoking supers implementation. The default implementation of this method simply
passes the message down the view hierarchy (from superviews to subviews)
and returns \c NO if none of the receivers subviews responds \c YES.
@param anEvent An event object that represents the key equivalent pressed
@return \c YES if theEvent is a key equivalent that the receiver handled,
\c NO if it is not a key equivalent that it should handle.
*/
- (BOOL)performKeyEquivalent:(CPEvent)anEvent
{
var count = [_subviews count];
@@ -2167,23 +2192,38 @@ setBoundsOrigin:
- (CPView)previousValidKeyView
{
var result = [self previousKeyView];
var result = [self previousKeyView],
firstResult = result;
while (result && ![result canBecomeKeyView])
{
result = [result previousKeyView];
// Cycled.
if (result === firstResult)
return nil;
}
return result;
}
- (void)_setPreviousKeyView:(CPView)previous
{
_previousKeyView = previous;
if ([previous isEqual:self])
_previousKeyView = nil;
else
_previousKeyView = previous;
}
- (void)setNextKeyView:(CPView)next
{
_nextKeyView = next;
[_nextKeyView _setPreviousKeyView:self];
if ([next isEqual:self])
_nextKeyView = nil;
else
{
_nextKeyView = next;
[_nextKeyView _setPreviousKeyView:self];
}
}
@end
@@ -2498,6 +2538,11 @@ setBoundsOrigin:
return [_themeAttributes[aName] valueForState:_themeState];
}
- (BOOL)hasThemeAttribute:(CPString)aName
{
return (_themeAttributes && _themeAttributes[aName] !== undefined);
}
- (CPView)createEphemeralSubviewNamed:(CPString)aViewName
{
return nil;
@@ -2609,7 +2654,11 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
_registeredDraggedTypes = [CPSet set];
_registeredDraggedTypesArray = [];
_autoresizingMask = [aCoder decodeIntForKey:CPViewAutoresizingMaskKey] || CPViewNotSizable;
// Other views (CPBox) might set an autoresizes mask on their subviews before it is actually decoded.
// We make sure we don't override the value by checking if it was already set.
if (_autoresizingMask === nil)
_autoresizingMask = [aCoder decodeIntForKey:CPViewAutoresizingMaskKey] || CPViewNotSizable;
_autoresizesSubviews = ![aCoder containsValueForKey:CPViewAutoresizesSubviewsKey] || [aCoder decodeBoolForKey:CPViewAutoresizesSubviewsKey];
_hitTests = ![aCoder containsValueForKey:CPViewHitTestsKey] || [aCoder decodeObjectForKey:CPViewHitTestsKey];
@@ -2727,12 +2776,12 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
var nextKeyView = [self nextKeyView];
if (nextKeyView !== nil)
if (nextKeyView !== nil && ![nextKeyView isEqual:self])
[aCoder encodeConditionalObject:nextKeyView forKey:CPViewNextKeyViewKey];
var previousKeyView = [self previousKeyView];
if (previousKeyView !== nil)
if (previousKeyView !== nil && ![previousKeyView isEqual:self])
[aCoder encodeConditionalObject:previousKeyView forKey:CPViewPreviousKeyViewKey];
[aCoder encodeObject:[self themeClass] forKey:CPViewThemeClassKey];
+35
View File
@@ -31,11 +31,41 @@ CPViewAnimationEffectKey = @"CPViewAnimationEffectKey";
CPViewAnimationFadeInEffect = @"CPViewAnimationFadeInEffect";
CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOutEffect";
/*!
@class CPViewAnimation
CPViewAnimation is a subclass of CPAnimation that makes it easy to do
basic animations on views.
*/
@implementation CPViewAnimation : CPAnimation
{
CPArray _viewAnimations;
}
/*!
Designated initializer.
This method takes an array of CPDictionaries. Each dictionary should
contain values for the following keys:
<pre>
CPViewAnimationTargetKey - (Required) The view to animate.
CPViewAnimationStartFrameKey - (Optional) The start frame of the target.
CPViewAnimationEndFrameKey - (Optional) The end frame of the target.
CPViewAnimationEffectKey - (Optional) a fade effect to use for the animation.
</pre>
For example:
<pre>
var animation = [CPDictionary dictionaryWithObjects:[myViewToAnimate, aStartFrame, anEndFrame, CPViewAnimationFadeInEffect]
forKeys:[CPViewAnimationTargetKey, CPViewAnimationStartFrameKey, CPViewAnimationEndFrameKey, CPViewAnimationEffectKey]];
</pre>
If you pass nil instead of an array of dictionaries you should later call setViewAnimations:.
@param viewAnimations - An array of CPDictionaries for each animation.
*/
- (id)initWithViewAnimations:(CPArray)viewAnimations
{
if (self = [super initWithDuration:0.5 animationCurve:CPAnimationLinear])
@@ -181,6 +211,11 @@ CPViewAnimationFadeOutEffect = @"CPViewAnimationFadeOutEffect";
return _viewAnimations;
}
/*!
Takes an array of CPDictionaries as documented in initWithViewAnimations:.
@param viewAnimations - An array of dictionaries describing the animation.
*/
- (void)setViewAnimations:(CPArray)viewAnimations
{
if (viewAnimations != _viewAnimations)
+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.
*/
+463 -88
View File
@@ -36,45 +36,94 @@ CPWebViewProgressEstimateChangedNotification = "CPWebViewProgressEstimateChan
CPWebViewProgressStartedNotification = "CPWebViewProgressStartedNotification";
CPWebViewProgressFinishedNotification = "CPWebViewProgressFinishedNotification";
/*!
Automatically choose between AppKit (Cappuccino style) scrollbars and
native scrollbars. In this mode AppKit scrollbars are always used except
when the web view is loaded with a URL which does not appear to pass the
same origin policy.
*/
CPWebViewScrollAuto = 0;
/*!
Always use AppKit scrollbars. If a URL is loaded whcih does not appear to
pass the same origin policy, native scrollbars will be used but a warnning
will be logged.
*/
CPWebViewScrollAppKit = 1;
/*!
Always use native (platform dependent) scrollbars.
*/
CPWebViewScrollNative = 2;
/*!
Never display scrollbars.
*/
CPWebViewScrollNone = 3;
// FIXME: somehow make CPWebView work with CPScrollView instead of native scrollbars (is this even possible?)
/*!
How frequently the size of the document will be checked at page load time
when AppKit scrollbars are used.
*/
CPWebViewAppKitScrollPollInterval = 1.0;
/*!
How many times the size of the size of the document will be checked at
page load time when AppKit scrollbars are used.
AppKit scrollbars must check the size of the document to display the
correct size of scrollbars. To improve performance the checks are only
performed a limited number of times per reload.
*/
CPWebViewAppKitScrollMaxPollCount = 3;
/*!
@ingroup appkit
*/
@class CPWebView
CPWebView allows you to display arbitrary HTML or embed a
webpage inside your application.
It's important to note that the same origin policy applies to this view.
That is, if the web page being displayed is not located in the same origin
(protocol, domain, and port) as the application, you will have limited
control over the view and no access to its contents. Furthermore,
Cappuccino style scrollbars can't be used to scroll it.
*/
@implementation CPWebView : CPView
{
CPScrollView _scrollView;
CPView _frameView;
CPScrollView _scrollView;
CPView _frameView;
IFrame _iframe;
CPString _mainFrameURL;
CPArray _backwardStack;
CPArray _forwardStack;
IFrame _iframe;
CPString _mainFrameURL;
CPArray _backwardStack;
CPArray _forwardStack;
BOOL _ignoreLoadStart;
BOOL _ignoreLoadEnd;
BOOL _ignoreLoadStart;
BOOL _ignoreLoadEnd;
BOOL _isLoading;
id _downloadDelegate;
id _frameLoadDelegate;
id _policyDelegate;
id _resourceLoadDelegate;
id _UIDelegate;
id _downloadDelegate;
id _frameLoadDelegate;
id _policyDelegate;
id _resourceLoadDelegate;
id _UIDelegate;
CPWebScriptObject _wso;
CPWebScriptObject _wso;
CPString _url;
CPString _html;
CPString _url;
CPString _html;
Function _loadCallback;
Function _loadCallback;
int _scrollMode;
CGSize _scrollSize;
int _scrollMode;
int _effectiveScrollMode;
BOOL _contentIsAccessible;
CPTimer _contentSizeCheckTimer;
int _contentSizePollCount;
int _loadHTMLStringTimer;
int _loadHTMLStringTimer;
BOOL _drawsBackground;
}
- (id)initWithFrame:(CPRect)frameRect frameName:(CPString)frameName groupName:(CPString)groupName
@@ -83,17 +132,24 @@ CPWebViewScrollNative = 2;
{
_iframe.name = frameName;
}
return self
return self;
}
- (id)initWithFrame:(CPRect)aFrame
{
if (self = [super initWithFrame:aFrame])
{
_mainFrameURL = nil;
_backwardStack = [];
_forwardStack = [];
_scrollMode = CPWebViewScrollNative;
_mainFrameURL = nil;
_backwardStack = [];
_forwardStack = [];
_scrollMode = CPWebViewScrollAuto;
_contentIsAccessible = YES;
_isLoading = NO;
_drawsBackground = YES;
[self setBackgroundColor:[CPColor whiteColor]];
[self _initDOMWithFrame:aFrame];
}
@@ -113,9 +169,10 @@ CPWebViewScrollNative = 2;
_iframe.style.borderWidth = "0px";
_iframe.frameBorder = "0";
[self setDrawsBackground:YES];
[self _applyBackgroundColor];
_loadCallback = function() {
_loadCallback = function()
{
// HACK: this block handles the case where we don't know about loads initiated by the user clicking a link
if (!_ignoreLoadStart)
{
@@ -127,7 +184,6 @@ CPWebViewScrollNative = 2;
// FIXME: this doesn't actually get the right URL for different domains. Not possible due to browser security restrictions.
_mainFrameURL = _iframe.src;
_mainFrameURL = _iframe.src;
// clear the forward
[_forwardStack removeAllObjects];
@@ -160,21 +216,29 @@ CPWebViewScrollNative = 2;
_frameView._DOMElement.appendChild(_iframe);
[self _setScrollMode:_scrollMode];
[self _updateEffectiveScrollMode];
[self addSubview:_scrollView];
}
- (void)setFrameSize:(CPSize)aSize
{
[super setFrameSize:aSize];
[self _resizeWebFrame];
}
- (void)viewDidUnhide
{
// Sizing cannot properly happen while we're hidden because the iframe is inaccessible.
// So now that it is accessible again, make sure to catch up.
[_frameView setFrameSize:[_scrollView contentSize]];
[self _resizeWebFrame];
[self _scheduleContentSizeCheck];
}
- (void)_attachScrollEventIfNecessary
{
if (_scrollMode !== CPWebViewScrollAppKit)
if (_effectiveScrollMode !== CPWebViewScrollAppKit)
return;
var win = null;
@@ -199,71 +263,130 @@ CPWebViewScrollNative = 2;
- (void)_resizeWebFrame
{
if (_scrollMode === CPWebViewScrollAppKit)
// When a webview is not in the DOM we can't inspect its contents for sizing information.
// If we try, we might end up setting the fallback frame size which will then become
// somewhat sticky.
if (![self _isVisible])
{
if (_scrollSize)
return;
}
if (_effectiveScrollMode === CPWebViewScrollAppKit)
{
var visibleRect = [_frameView visibleRect];
[_frameView setFrameSize:CGSizeMake(CGRectGetMaxX(visibleRect), CGRectGetMaxY(visibleRect))];
// try to get the document size so we can correctly set the frame
var win = null;
try { win = [self DOMWindow]; } catch (e) {}
if (win && win.document && win.document.body)
{
[_frameView setFrameSize:_scrollSize];
var width = win.document.body.scrollWidth,
height = win.document.body.scrollHeight;
_iframe.setAttribute("width", width);
_iframe.setAttribute("height", height);
[_frameView setFrameSize:CGSizeMake(width, height)];
}
else
{
var visibleRect = [_frameView visibleRect];
[_frameView setFrameSize:CGSizeMake(CGRectGetMaxX(visibleRect), CGRectGetMaxY(visibleRect))];
// try to get the document size so we can correctly set the frame
var win = null;
try { win = [self DOMWindow]; } catch (e) {}
if (win && win.document && win.document.body)
{
var width = win.document.body.scrollWidth,
height = win.document.body.scrollHeight;
_iframe.setAttribute("width", width);
_iframe.setAttribute("height", height);
[_frameView setFrameSize:CGSizeMake(width, height)];
}
else
// If we do have access to the content, it might be that the 'body' element simply hasn't loaded yet.
// The size will be updated by the content size timer in this case.
if (!win || !win.document)
{
CPLog.warn("using default size 800*1600");
[_frameView setFrameSize:CGSizeMake(800, 1600)];
}
[_frameView scrollRectToVisible:visibleRect];
}
[_frameView scrollRectToVisible:visibleRect];
}
}
/*!
Sets the scroll mode of the receiver.
Valid values are:
CPWebViewScrollAuto
CPWebViewScrollAppKit
CPWebViewScrollNative
CPWebViewScrollNone
CPWebViewScrollAuto
*/
- (void)setScrollMode:(int)aScrollMode
{
if (_scrollMode == aScrollMode)
return;
[self _setScrollMode:aScrollMode];
_scrollMode = aScrollMode;
[self _updateEffectiveScrollMode];
}
- (void)_setScrollMode:(int)aScrollMode
/*!
Returns the effective scroll mode of the receiver.
Valied values are:
CPWebViewScrollAuto
CPWebViewScrollAppKit
CPWebViewScrollNative
CPWebViewScrollNone
*/
- (int)effectiveScrollMode
{
if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
_scrollMode = CPWebViewScrollNative;
else
_scrollMode = aScrollMode;
return _effectiveScrollMode;
}
- (void)_updateEffectiveScrollMode
{
var _newScrollMode = CPWebViewScrollAppKit;
if (_scrollMode == CPWebViewScrollNative
|| (_scrollMode == CPWebViewScrollAuto && !_contentIsAccessible)
|| CPBrowserIsEngine(CPInternetExplorerBrowserEngine))
{
_newScrollMode = CPWebViewScrollNative;
}
else if (_scrollMode == CPWebViewScrollAppKit && !_contentIsAccessible)
{
// Same behaviour as the previous case except that a warning is logged when AppKit
// scrollers can't be used.
CPLog.warn(self + " unable to use CPWebViewScrollAppKit scroll mode due to same origin policy.");
_newScrollMode = CPWebViewScrollNative;
}
if (_newScrollMode !== _effectiveScrollMode)
[self _setEffectiveScrollMode:_newScrollMode];
}
- (void)_setEffectiveScrollMode:(int)aScrollMode
{
_effectiveScrollMode = aScrollMode;
_ignoreLoadStart = YES;
_ignoreLoadEnd = YES;
var parent = _iframe.parentNode;
// FIXME "scrolling" can't be changed without readding the iframe. Unfortunately this causes a reload.
parent.removeChild(_iframe);
if (_scrollMode === CPWebViewScrollAppKit)
if (_effectiveScrollMode === CPWebViewScrollAppKit)
{
[_scrollView setHasHorizontalScroller:YES];
[_scrollView setHasVerticalScroller:YES];
_iframe.setAttribute("scrolling", "no");
}
else if (_effectiveScrollMode === CPWebViewScrollNone)
{
[_scrollView setHasHorizontalScroller:NO];
[_scrollView setHasVerticalScroller:NO];
_iframe.setAttribute("scrolling", "no");
}
else
{
[_scrollView setHasHorizontalScroller:NO];
@@ -275,27 +398,45 @@ CPWebViewScrollNative = 2;
}
parent.appendChild(_iframe);
[self _applyBackgroundColor];
[self _resizeWebFrame];
}
- (void)_maybePollWebFrameSize
{
if (CPWebViewAppKitScrollMaxPollCount == 0 || _contentSizePollCount++ < CPWebViewAppKitScrollMaxPollCount)
[self _resizeWebFrame];
else
[_contentSizeCheckTimer invalidate];
}
/*!
Loads a string of HTML into the receiver.
@param CPString - The string to load.
*/
- (void)loadHTMLString:(CPString)aString
{
[self loadHTMLString:aString baseURL:nil];
}
/*!
Loads a string of HTML into the receiver.
@param CPString - The string to load.
@param CPURL - The base url of the string. (not implemented)
*/
- (void)loadHTMLString:(CPString)aString baseURL:(CPURL)URL
{
// FIXME: do something with baseURL?
[self _setScrollMode:CPWebViewScrollAppKit];
[_frameView setFrameSize:[_scrollView contentSize]];
[self _startedLoading];
_ignoreLoadStart = YES;
_ignoreLoadEnd = NO;
_url = null;
_url = nil;
_html = aString;
[self _load];
@@ -303,15 +444,12 @@ CPWebViewScrollNative = 2;
- (void)_loadMainFrameURL
{
[self _setScrollMode:CPWebViewScrollNative];
[self _startedLoading];
_ignoreLoadStart = YES;
_ignoreLoadEnd = NO;
_url = _mainFrameURL;
_html = null;
_html = nil;
[self _load];
}
@@ -320,13 +458,26 @@ CPWebViewScrollNative = 2;
{
if (_url)
{
// Try to figure out if this URL will pass the same origin policy and hence allow us to potentially
// use appkit scrollbars.
var cpurl = [CPURL URLWithString:_url];
_contentIsAccessible = [cpurl _passesSameOriginPolicy];
[self _updateEffectiveScrollMode];
_ignoreLoadEnd = NO;
_iframe.src = _url;
}
else if (_html)
else if (_html !== nil)
{
// clear the iframe
_iframe.src = "";
_contentIsAccessible = YES;
[self _updateEffectiveScrollMode];
_ignoreLoadEnd = NO;
if (_loadHTMLStringTimer !== nil)
{
window.clearTimeout(_loadHTMLStringTimer);
@@ -338,8 +489,11 @@ CPWebViewScrollNative = 2;
{
var win = [self DOMWindow];
/*
If _html is the empty string, subtitute in an empty HTML structure. Just leaving the contents entirely empty prompts the browser to subtitute in a white page which would interfere with any custom background colours in use by this web view.
*/
if (win)
win.document.write(_html);
win.document.write(_html || "<html><body></body></html>");
window.setTimeout(_loadCallback, 1);
}, 0);
@@ -348,6 +502,8 @@ CPWebViewScrollNative = 2;
- (void)_startedLoading
{
_isLoading = YES;
[[CPNotificationCenter defaultCenter] postNotificationName:CPWebViewProgressStartedNotification object:self];
if ([_frameLoadDelegate respondsToSelector:@selector(webView:didStartProvisionalLoadForFrame:)])
@@ -356,20 +512,69 @@ CPWebViewScrollNative = 2;
- (void)_finishedLoading
{
_isLoading = NO;
[self _resizeWebFrame];
[self _attachScrollEventIfNecessary];
[self _scheduleContentSizeCheck];
[[CPNotificationCenter defaultCenter] postNotificationName:CPWebViewProgressFinishedNotification object:self];
if ([_frameLoadDelegate respondsToSelector:@selector(webView:didFinishLoadForFrame:)])
[_frameLoadDelegate webView:self didFinishLoadForFrame:nil]; // FIXME: give this a frame somehow?
}
- (void)_scheduleContentSizeCheck
{
[_contentSizeCheckTimer invalidate];
if (_effectiveScrollMode == CPWebViewScrollAppKit)
{
/*
FIXME Need better method.
We don't know when the content of the iframe changes size (e.g. a
picture finishes loading, dynamic content is loaded). Often when a
page has initially 'loaded', it does not yet have its final size. In
lieu of any resize events we will simply check back in a few times
some time after loading.
We run these checks only a limited number of times as to not deplete
battery life and slow down the software needlessly. This does mean
there are situations where the content changes size and the AppKit
scrollbars will be out of sync. Users who have dynamic content
in their web view will, for now, have to implement domain specific
fixes.
*/
_contentSizePollCount = 0;
_contentSizeCheckTimer = [CPTimer scheduledTimerWithTimeInterval:CPWebViewAppKitScrollPollInterval target:self selector:@selector(_maybePollWebFrameSize) userInfo:nil repeats:YES];
}
}
/*!
Returns whether the web view is loading. Note: due to browser limitations
this value is not particularly reliable.
*/
- (BOOL)isLoading
{
return _isLoading;
}
/*!
Returns the URL of the main frame.
@return CPString - The URL of the main frame.
*/
- (CPString)mainFrameURL
{
return _mainFrameURL;
}
/*!
Sets the URL of the main frame.
@param CPString - the url to set.
*/
- (void)setMainFrameURL:(CPString)URLString
{
if (_mainFrameURL)
@@ -380,6 +585,11 @@ CPWebViewScrollNative = 2;
[self _loadMainFrameURL];
}
/*!
Tells the webview to navigate to the previous page.
@return BOOL - YES if the receiver was able to go back, otherwise NO.
*/
- (BOOL)goBack
{
if (_backwardStack.length > 0)
@@ -396,6 +606,11 @@ CPWebViewScrollNative = 2;
return NO;
}
/*!
Tells the receiver to go forward in page history.
@return - YES if the receiver was able to go forward, otherwise NO.
*/
- (BOOL)goForward
{
if (_forwardStack.length > 0)
@@ -412,11 +627,23 @@ CPWebViewScrollNative = 2;
return NO;
}
/*!
Checks to see if the webview has a history stack you can navigate back
through.
@return BOOL - YES if the receiver can navigate backward through history, otherwise NO.
*/
- (BOOL)canGoBack
{
return (_backwardStack.length > 0);
}
/*!
Checks to see if the webview has a history stack you can navigate forward
through.
@return BOOL - YES if the receiver can navigate forward through history, otherwise NO.
*/
- (BOOL)canGoForward
{
return (_forwardStack.length > 0);
@@ -428,16 +655,30 @@ CPWebViewScrollNative = 2;
return { back: _backwardStack, forward: _forwardStack };
}
/*!
Closes the webview by unloading the webpage. The webview will no longer
respond to load requests or delegate methods once this is called.
*/
- (void)close
{
_iframe.parentNode.removeChild(_iframe);
}
/*!
Returns the window object of the webview.
@return DOMWindow - The window object.
*/
- (DOMWindow)DOMWindow
{
return (_iframe.contentDocument && _iframe.contentDocument.defaultView) || _iframe.contentWindow;
}
/*!
Returns the root Object of the webview as a CPWebScriptObject.
@return CPWebScriptObject - the Object of the webview.
*/
- (CPWebScriptObject)windowScriptObject
{
var win = [self DOMWindow];
@@ -451,17 +692,37 @@ CPWebViewScrollNative = 2;
return _wso;
}
/*!
Evaluates a javascript string in the webview and returns the result of
that evaluation as a string.
@param script - A string of javascript.
@return CPString - The result of the evaluation.
*/
- (CPString)stringByEvaluatingJavaScriptFromString:(CPString)script
{
var result = [self objectByEvaluatingJavaScriptFromString:script];
return result ? String(result) : nil;
}
/*!
Evaluates a string of javascript in the webview and returns the result.
@param script - A string of javascript.
@return JSObject - A JSObject resulting from the evaluation.
*/
- (JSObject)objectByEvaluatingJavaScriptFromString:(CPString)script
{
return [[self windowScriptObject] evaluateWebScript:script];
}
/*!
Gets the computed style for an element.
@param DOMElement - An Element.
@param pseudoElement - A pseudoElement.
@return DOMCSSStyleDeclaration - The computed style for an element.
*/
- (DOMCSSStyleDeclaration)computedStyleForElement:(DOMElement)element pseudoElement:(CPString)pseudoElement
{
var win = [[self windowScriptObject] window];
@@ -474,47 +735,114 @@ CPWebViewScrollNative = 2;
}
/*!
@return BOOL - YES if the webview draws its own background, otherwise NO.
*/
- (BOOL)drawsBackground
{
return _iframe.style.backgroundColor != "";
return _drawsBackground;
}
- (void)setDrawsBackground:(BOOL)drawsBackround
/*!
Sets whether the webview draws its own background when the displayed contents do not.
If you are trying to create a transparent iframe:
A) call this method with NO
A) call setBackground:[CPColor transparent]
B) ensure the content does not draw a background, e.g. it has <body style="background-color: transparent;">
@param BOOL - YES if the webview should draw its background, otherwise NO.
*/
- (void)setDrawsBackground:(BOOL)drawsBackground
{
_iframe.style.backgroundColor = drawsBackround ? "white" : "";
if (drawsBackground == _drawsBackground)
return;
_drawsBackground = drawsBackground;
[self _applyBackgroundColor];
}
- (void)setBackgroundColor:(CPColor)aColor
{
[super setBackgroundColor:aColor];
[self _applyBackgroundColor];
}
- (void)_applyBackgroundColor
{
if (_iframe)
{
var bgColor = [self backgroundColor] || [CPColor whiteColor];
_iframe.allowtransparency = !_drawsBackground;
_iframe.style.backgroundColor = _drawsBackground ? [bgColor cssString] : "transparent";
}
}
// IBActions
- (IBAction)takeStringURLFrom:(id)sender
/*!
Used with the target/action mechanism to automatically set the webviews
mainFrameURL to the senders stringValue.
@param sender - the sender of the action. Should respond to -stringValue.
*/
- (@action)takeStringURLFrom:(id)sender
{
[self setMainFrameURL:[sender stringValue]];
}
- (IBAction)goBack:(id)sender
/*!
Same as -goBack but takes a sender as a param.
@param sender - the sender of the action.
*/
- (@action)goBack:(id)sender
{
[self goBack];
}
- (IBAction)goForward:(id)sender
/*!
Same as -goForward but takes a sender as a param.
@param sender - the sender of the action.
*/
- (@action)goForward:(id)sender
{
[self goForward];
}
- (IBAction)stopLoading:(id)sender
/*!
Stops loading the webview. (not yet implemented)
@param sender - the sender of the action.
*/
- (@action)stopLoading:(id)sender
{
// FIXME: what to do?
}
- (IBAction)reload:(id)sender
/*!
Reloads the webview.
@param sender - the sender of the action.
*/
- (@action)reload:(id)sender
{
[self _loadMainFrameURL];
// If we're displaying pure HTML, redisplay it.
if(!_url && (_html !== nil))
[self loadHTMLString:_html];
else
[self _loadMainFrameURL];
}
- (IBAction)print:(id)sender
/*!
Tells the webview to print. If the webview is unable to print due to
browser restrictions the user is alerted to print from the file menu.
@param sender - the sender of the receiver.
*/
- (@action)print:(id)sender
{
try
{
@@ -574,12 +902,19 @@ CPWebViewScrollNative = 2;
@end
/*!
@class CPWebScriptObject
A CPWebScriptObject is an Objective-J wrapper around a scripting object.
*/
@implementation CPWebScriptObject : CPObject
{
Window _window;
}
/*!
Initializes the scripting object with the scripting Window object.
*/
- (id)initWithWindow:(Window)aWindow
{
if (self = [super init])
@@ -589,6 +924,12 @@ CPWebViewScrollNative = 2;
return self;
}
/*!
Call a method with arguments on the receiver.
@param methodName - The method that should be called.
@param args - An array of arguments to pass to the method call.
*/
- (id)callWebScriptMethod:(CPString)methodName withArguments:(CPArray)args
{
// Would using "with" be better here?
@@ -602,15 +943,25 @@ CPWebViewScrollNative = 2;
return undefined;
}
/*!
Evaluates a string of javascript and returns the result.
@param script - The script to run.
@return - The result of the evaluation, which may be 'undefined'.
*/
- (id)evaluateWebScript:(CPString)script
{
try {
return _window.eval(script);
} catch (e) {
// FIX ME: if we fail inside here, shouldn't we return an exception?
}
return undefined;
}
/*!
Returns the receivers Window object.
*/
- (Window)window
{
return _window;
@@ -623,6 +974,7 @@ CPWebViewScrollNative = 2;
/*!
Initializes the web view from the data in a coder.
@param aCoder the coder from which to read the data
@return the initialized web view
*/
@@ -636,13 +988,16 @@ CPWebViewScrollNative = 2;
_mainFrameURL = nil;
_backwardStack = [];
_forwardStack = [];
_scrollMode = CPWebViewScrollNative;
_scrollMode = CPWebViewScrollAuto;
#if PLATFORM(DOM)
[self _initDOMWithFrame:[self frame]];
#endif
[self setBackgroundColor:[CPColor whiteColor]];
if (![self backgroundColor])
[self setBackgroundColor:[CPColor whiteColor]];
[self _updateEffectiveScrollMode];
}
return self;
@@ -650,6 +1005,7 @@ CPWebViewScrollNative = 2;
/*!
Writes out the web view's instance information to a coder.
@param aCoder the coder to which to write the data
*/
- (void)encodeWithCoder:(CPCoder)aCoder
@@ -661,3 +1017,22 @@ CPWebViewScrollNative = 2;
}
@end
@implementation CPURL(SOP)
/*!
Private API.
Returns YES if the receiver URL would pass the same origin policy if loaded by the current runtime environment.
Since Cappuccino runs in the browser, it is often restricted from accessing URLs from outside of its own origin (protocol, domain, port). This method tries to determine if the URL represented by the receiver is of the same origin, or if other circumstances will allow the content at the URL to be interacted with.
*/
- (BOOL)_passesSameOriginPolicy
{
var documentURL = [CPURL URLWithString:window.location.href];
if ([documentURL isFileURL] && CPFeatureIsCompatible(CPSOPDisabledFromFileURLs))
return YES;
return ([documentURL scheme] == [self scheme] && [documentURL host] == [self host] && [documentURL port] == [self port]);
}
@end
+134 -19
View File
@@ -193,24 +193,24 @@ var SHADOW_MARGIN_LEFT = 20.0,
_CPWindowShadowColor = nil;
var CPWindowSaveImage = nil,
CPWindowSavingImage = nil;
CPWindowSavingImage = nil,
var CPWindowResizeTime = 0.2;
CPWindowResizeTime = 0.2;
/*
Keys for which action messages will be sent by default when unhandled, e.g. complete:.
*/
var CPWindowActionMessageKeys = [
CPLeftArrowFunctionKey,
CPRightArrowFunctionKey,
CPUpArrowFunctionKey,
CPDownArrowFunctionKey,
CPPageUpFunctionKey,
CPPageDownFunctionKey,
CPHomeFunctionKey,
CPEndFunctionKey,
CPEscapeFunctionKey
];
CPLeftArrowFunctionKey,
CPRightArrowFunctionKey,
CPUpArrowFunctionKey,
CPDownArrowFunctionKey,
CPPageUpFunctionKey,
CPPageDownFunctionKey,
CPHomeFunctionKey,
CPEndFunctionKey,
CPEscapeFunctionKey
];
/*!
@ingroup appkit
@@ -466,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
*/
@@ -539,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])
@@ -579,6 +599,9 @@ CPTexturedBackgroundWindowMask
}
}
/*!
@return BOOL - YES if the CPWindow fills the browser window, otherwise NO.
*/
- (BOOL)isFullPlatformWindow
{
return _isFullPlatformWindow;
@@ -594,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
@@ -635,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
{
@@ -644,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);
@@ -721,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];
@@ -728,6 +775,7 @@ CPTexturedBackgroundWindowMask
/*!
Sets the window's frame rectangle
@param aFrame - The CGRect of the windows new frame
*/
- (void)setFrame:(CGRect)aFrame
{
@@ -1111,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;
@@ -1631,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
*/
@@ -1668,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
*/
@@ -1819,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
{
@@ -2332,7 +2391,9 @@ CPTexturedBackgroundWindowMask
// an event going of the responder chain is passed to the input system as a last resort.
// However, the only methods I could get Cocoa to call automatically are
// moveUp: moveDown: moveLeft: moveRight: pageUp: pageDown: and complete:
[self _processKeyboardUIKey:anEvent];
// Unhandled events just travel further up the responder chain _past_ the window.
if (![self _processKeyboardUIKey:anEvent])
[super keyDown:anEvent];
}
/*
@@ -2367,6 +2428,8 @@ CPTexturedBackgroundWindowMask
// The difference is that doCommandBySelector: will also send the action to the window and application delegates.
[[self firstResponder] doCommandBySelector:@selector(complete:)];
}
return NO;
}
- (void)_dirtyKeyViewLoop
@@ -2448,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)
@@ -2472,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];
@@ -2603,16 +2698,25 @@ var keyViewComparator = function(lhs, rhs, context)
return _autoresizingMask;
}
/*!
Converts aPoint from the window coordinate system to the global coordinate system.
*/
- (CGPoint)convertBaseToGlobal:(CGPoint)aPoint
{
return [CPPlatform isBrowser] ? [self convertBaseToPlatformWindow:aPoint] : [self convertBaseToScreen:aPoint];
}
/*!
Converts aPoint from the global coordinate system to the window coordinate system.
*/
- (CGPoint)convertGlobalToBase:(CGPoint)aPoint
{
return [CPPlatform isBrowser] ? [self convertPlatformWindowToBase:aPoint] : [self convertScreenToBase:aPoint];
}
/*!
Converts aPoint from the window coordinate system to the coordinate system of the parent platform window.
*/
- (CGPoint)convertBaseToPlatformWindow:(CGPoint)aPoint
{
if ([self _sharesChromeWithPlatformWindow])
@@ -2623,6 +2727,9 @@ var keyViewComparator = function(lhs, rhs, context)
return _CGPointMake(aPoint.x + origin.x, aPoint.y + origin.y);
}
/*!
Converts aPoint from the parent platform window coordinate system to the windows coordinate system.
*/
- (CGPoint)convertPlatformWindowToBase:(CGPoint)aPoint
{
if ([self _sharesChromeWithPlatformWindow])
@@ -2712,12 +2819,19 @@ var keyViewComparator = function(lhs, rhs, context)
@end
@implementation CPWindow (Deprecated)
/*!
Sets the CPWindow to fill the whole browser window.
NOTE: this method has been deprecated in favor of setFullPlatformWindow:
*/
- (void)setFullBridge:(BOOL)shouldBeFullBridge
{
[self setFullPlatformWindow:shouldBeFullBridge];
}
/*!
Returns YES if the window fills the full browser window, otherwise NO.
NOTE: this method has been deprecated in favor of isFullPlatformWindow.
*/
- (BOOL)isFullBridge
{
return [self isFullPlatformWindow];
@@ -2810,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];
+7 -7
View File
@@ -13,25 +13,25 @@ var _CPStandardWindowViewBodyBackgroundColor = nil;
{
if (!_CPStandardWindowViewBodyBackgroundColor)
_CPStandardWindowViewBodyBackgroundColor = [CPColor colorWithWhite:0.96 alpha:0.9];
return _CPStandardWindowViewBodyBackgroundColor;
return _CPStandardWindowViewBodyBackgroundColor;
}
- (id)initWithFrame:(CPRect)aFrame styleMask:(unsigned)aStyleMask
{
self = [super initWithFrame:aFrame styleMask:aStyleMask];
if (self)
{
var theClass = [self class],
bounds = [self bounds];
_bodyView = [[CPView alloc] initWithFrame:_CGRectMake(0.0, 0.0, _CGRectGetWidth(bounds), _CGRectGetHeight(bounds))];
[_bodyView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
[_bodyView setBackgroundColor:[theClass bodyBackgroundColor]];
[_bodyView setHitTests:NO];
[self addSubview:_bodyView];
var bundle = [CPBundle bundleForClass:[CPWindow class]];
@@ -41,7 +41,7 @@ var _CPStandardWindowViewBodyBackgroundColor = nil;
[self addSubview:_shadowView];
}
return self;
return self;
}
- (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
+2 -2
View File
@@ -106,7 +106,7 @@ var _CPStandardWindowViewBodyBackgroundColor = nil,
_CPStandardWindowViewMinimizeButtonImage = nil,
_CPStandardWindowViewMinimizeButtonHighlightedImage = nil;
var STANDARD_GRADIENT_HEIGHT = 41.0;
var STANDARD_GRADIENT_HEIGHT = 41.0,
STANDARD_TITLEBAR_HEIGHT = 25.0;
@implementation _CPStandardWindowView : _CPWindowView
@@ -342,7 +342,7 @@ var STANDARD_GRADIENT_HEIGHT = 41.0;
if (_minimizeButton)
leftOffset += 19.0;
[_titleField setFrame:CGRectMake(leftOffset, 5.0, width - leftOffset*2.0, CGRectGetHeight([_titleField frame]))];
[_titleField setFrame:CGRectMake(leftOffset, 5.0, width - leftOffset * 2.0, CGRectGetHeight([_titleField frame]))];
[[theWindow contentView] setFrameOrigin:CGPointMake(0.0, CGRectGetMaxY([_dividerView frame]))];
}
+114
View File
@@ -0,0 +1,114 @@
/*
* _CPToolTipWindowView.j
* AppKit
*
* Created by Antoine Mercadal
* Copyright 2011 <primalmotion@archipelproject.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "_CPWindowView.j"
@implementation _CPToolTipWindowView : _CPWindowView
{
BOOL _mouseDownPressed @accessors(getter=isMouseDownPressed, setter=setMouseDownPressed:);
unsigned _gravity @accessors(property=gravity);
CPColor _backgroundColor;
CPColor _strokeColor;
}
#pragma mark -
#pragma mark Class methods
/*! compute the contentView frame from a given window frame
@param aFrameRect the window frame
*/
+ (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
{
var contentRect = CGRectMakeCopy(aFrameRect);
contentRect.origin.x += 3;
contentRect.origin.y += 3;
contentRect.size.width -= 6;
contentRect.size.height -= 6;
return contentRect;
}
/*! compute the window frame from a given contentView frame
@param aContentRect the contentView frame
*/
+ (CGRect)frameRectForContentRect:(CGRect)aContentRect
{
var aFrameRect = CGRectMakeCopy(aContentRect);
aFrameRect.origin.x -= 3;
aFrameRect.origin.y -= 3;
aFrameRect.size.width += 6;
aFrameRect.size.height += 6;
return aFrameRect;
}
#pragma mark -
#pragma mark Initialization
- (id)initWithFrame:(CPRect)aFrame styleMask:(unsigned)aStyleMask
{
if (self = [super initWithFrame:aFrame styleMask:aStyleMask])
{
_strokeColor = [CPColor colorWithHexString:@"E3E3E3"];
_backgroundColor = [CPColor colorWithHexString:@"FFFFCA"];
}
return self;
}
#pragma mark -
#pragma mark drawing
- (void)drawRect:(CGRect)aRect
{
[super drawRect:aRect];
var context = [[CPGraphicsContext currentContext] graphicsPort],
radius = 2,
strokeWidth = 1;
CGContextSetStrokeColor(context, _strokeColor);
CGContextSetFillColor(context, _backgroundColor);
CGContextSetLineWidth(context, strokeWidth);
CGContextBeginPath(context);
aRect.origin.x += strokeWidth;
aRect.origin.y += strokeWidth;
aRect.size.width -= strokeWidth * 2;
aRect.size.height -= strokeWidth * 2;
CGContextAddPath(context, CGPathWithRoundedRectangleInRect(aRect, radius, radius, YES, YES, YES, YES));
CGContextClosePath(context);
//Draw it
CGContextStrokePath(context);
CGContextFillPath(context);
}
@end
+1 -1
View File
@@ -161,7 +161,7 @@ var _CPWindowViewResizeIndicatorImage = nil;
var minPointY = 0;
if([CPMenu menuBarVisible])
if ([CPMenu menuBarVisible])
minPointY = [[CPApp mainMenu] menuBarHeight];
var restrictedPoint = CGPointMake(0, 0);
+16 -9
View File
@@ -32,10 +32,15 @@
@ingroup appkit
@class CPWindowController
An instance of a CPWindowController manages a CPWindow. It has methods
that get called when the window is loading, and after the window has loaded. In the
Model-View-Controller method of program design, the CPWindowController would be
considered the 'Controller' and the CPWindow the 'Model.'
An instance of a CPWindowController manages a CPWindow. Windows are typically loaded via a cib,
but they can also manage windows created in code. A CPWindowController can manage a window by
itself or work with AppKits's document-based architecture.
In a Document based app, a CPWindowController instance is created and managed by a CPDocument subclass.
If the CPWindowController is managing a CPWindow created in a cib the \c owner of the CPWindow is this controller.
@note When creating the window programatically (instead of a cib) you should override the \c loadWindow method.\c loadWindow is called the first time the window object is needed. @endnote
*/
@implementation CPWindowController : CPResponder
{
@@ -62,7 +67,7 @@
/*!
Initializes the controller with a window.
@param aWindow the window to control
@return the initialzed window controller
@return the initialized window controller
*/
- (id)initWithWindow:(CPWindow)aWindow
{
@@ -82,7 +87,7 @@
}
/*!
Initializes the controller with a Capppuccino Interface Builder name.
Initializes the controller with a Cappuccino Interface Builder name.
@param aWindowCibName the cib name of the window to control
@return the initialized window controller
*/
@@ -124,7 +129,8 @@
}
/*!
Loads the window
Loads the window. This method should never be called directly. Instead call \c window which will in turn call windowWillLoad and windowDidLoad.
This method should be overwritten if you are creating the view programatically.
*/
- (void)loadWindow
{
@@ -158,7 +164,8 @@
}
/*!
Returns the window this object controls.
Returns the CPWindow the reciever controls.
This will cause \c loadWindow to be called if no window object exists yet.
*/
- (CPWindow)window
{
@@ -377,7 +384,7 @@
}
/*!
Returns the document in the controlled window.
Returns the CPDocument in the controlled window.
*/
- (CPDocument)document
{
+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]];
+2 -2
View File
@@ -64,14 +64,14 @@ var _CPCibConnectorSourceKey = @"_CPCibConnectorSourceKey",
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
if (self)
{
_source = [aCoder decodeObjectForKey:_CPCibConnectorSourceKey];
_destination = [aCoder decodeObjectForKey:_CPCibConnectorDestinationKey];
_label = [aCoder decodeObjectForKey:_CPCibConnectorLabelKey];
}
return self;
}
-4
View File
@@ -47,12 +47,8 @@
// If the destination doesn't respond to this selector, warn but don't die.
if (_destination && ![_destination respondsToSelector:selector])
{
CPLog.warn(@"Could not connect the action " + selector + @" to target of class " + [_destination className]);
return;
}
// Not being able to set the action is a fatal error.
if ([_source respondsToSelector:@selector(setAction:)])
objj_msgSend(_source, @selector(setAction:), selector);
+1 -1
View File
@@ -76,7 +76,7 @@ var CPCibOwner = @"CPCibOwner";
// Path is based solely on anOwner:
var bundle = anOwner ? [CPBundle bundleForClass:[anOwner class]] : [CPBundle mainBundle],
path = [bundle pathForResource:aName];
return [self loadCibFile:path externalNameTable:[CPDictionary dictionaryWithObject:anOwner forKey:CPCibOwner] loadDelegate:aDelegate];
}
+7
View File
@@ -83,7 +83,14 @@ var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey",
if ([aCoder respondsToSelector:@selector(bundle)] &&
(![aCoder respondsToSelector:@selector(awakenCustomResources)] || [aCoder awakenCustomResources]))
if (_className === @"CPImage")
{
if (_resourceName == "CPAddTemplate")
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPButtonBar class]] pathForResource:@"plus_button.png"] size:CGSizeMake(11, 12)];
else if (_resourceName == "CPRemoveTemplate")
return [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPButtonBar class]] pathForResource:@"minus_button.png"] size:CGSizeMake(11, 4)];
return [[CPImage alloc] initWithContentsOfFile:[[aCoder bundle] pathForResource:_resourceName] size:_properties.valueForKey(@"size")];
}
return self;
}
+5 -5
View File
@@ -84,7 +84,7 @@ var _CPCibCustomViewClassNameKey = @"_CPCibCustomViewClassNameKey";
{
#if DEBUG
CPLog("Unknown class \"" + _className + "\" in cib file, using CPView instead.");
#endif
#endif
theClass = [CPView class];
}
@@ -97,16 +97,16 @@ var _CPCibCustomViewClassNameKey = @"_CPCibCustomViewClassNameKey";
}
var view = [[theClass alloc] initWithFrame:[self frame]];
if (view)
{
[view setBounds:[self bounds]];
// Since the object replacement logic hasn't had a chance to kick in yet, we need to do it manually:
var subviews = [self subviews],
index = 0,
count = subviews.length;
for (; index < count; ++index)
[view addSubview:subviews[index]];
@@ -116,7 +116,7 @@ var _CPCibCustomViewClassNameKey = @"_CPCibCustomViewClassNameKey";
[view setHitTests:[self hitTests]];
[view setHidden:[self isHidden]];
[view setAlphaValue:[self alphaValue]];
[_superview replaceSubview:self with:view];
[view setBackgroundColor:[self backgroundColor]];
+3 -3
View File
@@ -12,15 +12,15 @@
- (id)initForReadingWithData:(CPData)data bundle:(CPBundle)aBundle awakenCustomResources:(BOOL)shouldAwakenCustomResources
{
self = [super initForReadingWithData:data];
if (self)
{
_bundle = aBundle;
_awakenCustomResources = shouldAwakenCustomResources;
[self setDelegate:self];
}
return self;
}
+24 -24
View File
@@ -5,19 +5,19 @@
@import "CPWindow.j"
var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinSizeKey",
_CPCibWindowTemplateMaxSizeKey = @"_CPCibWindowTemplateMaxSizeKey",
_CPCibWindowTemplateViewClassKey = @"_CPCibWindowTemplateViewClassKey",
_CPCibWindowTemplateWindowClassKey = @"_CPCibWindowTemplateWindowClassKey",
_CPCibWindowTemplateWindowRectKey = @"_CPCibWindowTemplateWindowRectKey",
_CPCibWindowTemplateWindowStyleMaskKey = @"_CPCibWindowTempatStyleMaskKey",
_CPCibWindowTemplateWindowTitleKey = @"_CPCibWindowTemplateWindowTitleKey",
_CPCibWindowTemplateWindowViewKey = @"_CPCibWindowTemplateWindowViewKey",
var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinSizeKey",
_CPCibWindowTemplateMaxSizeKey = @"_CPCibWindowTemplateMaxSizeKey",
_CPCibWindowTemplateWindowAutorecalculatesKeyViewLoop = @"_CPCibWindowTemplateWindowAutorecalculatesKeyViewLoop";
_CPCibWindowTemplateWindowIsFullPlatformWindowKey = @"_CPCibWindowTemplateWindowIsFullPlatformWindowKey";
_CPCibWindowTemplateViewClassKey = @"_CPCibWindowTemplateViewClassKey",
_CPCibWindowTemplateWindowClassKey = @"_CPCibWindowTemplateWindowClassKey",
_CPCibWindowTemplateWindowRectKey = @"_CPCibWindowTemplateWindowRectKey",
_CPCibWindowTemplateWindowStyleMaskKey = @"_CPCibWindowTempatStyleMaskKey",
_CPCibWindowTemplateWindowTitleKey = @"_CPCibWindowTemplateWindowTitleKey",
_CPCibWindowTemplateWindowViewKey = @"_CPCibWindowTemplateWindowViewKey",
_CPCibWindowTemplateWindowAutorecalculatesKeyViewLoop = @"_CPCibWindowTemplateWindowAutorecalculatesKeyViewLoop",
_CPCibWindowTemplateWindowIsFullPlatformWindowKey = @"_CPCibWindowTemplateWindowIsFullPlatformWindowKey";
@implementation _CPCibWindowTemplate : CPObject
{
@@ -60,27 +60,27 @@ var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinS
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
if (self)
{
if ([aCoder containsValueForKey:_CPCibWindowTemplateMinSizeKey])
_minSize = [aCoder decodeSizeForKey:_CPCibWindowTemplateMinSizeKey];
if ([aCoder containsValueForKey:_CPCibWindowTemplateMaxSizeKey])
_maxSize = [aCoder decodeSizeForKey:_CPCibWindowTemplateMaxSizeKey];
_viewClass = [aCoder decodeObjectForKey:_CPCibWindowTemplateViewClassKey];
_windowClass = [aCoder decodeObjectForKey:_CPCibWindowTemplateWindowClassKey];
_windowRect = [aCoder decodeRectForKey:_CPCibWindowTemplateWindowRectKey];
_windowStyleMask = [aCoder decodeIntForKey:_CPCibWindowTemplateWindowStyleMaskKey];
_windowTitle = [aCoder decodeObjectForKey:_CPCibWindowTemplateWindowTitleKey];
_windowView = [aCoder decodeObjectForKey:_CPCibWindowTemplateWindowViewKey];
_windowAutorecalculatesKeyViewLoop = !![aCoder decodeObjectForKey:_CPCibWindowTemplateWindowAutorecalculatesKeyViewLoop];
_windowIsFullPlatformWindow = !![aCoder decodeObjectForKey:_CPCibWindowTemplateWindowIsFullPlatformWindowKey];
}
return self;
}
@@ -90,13 +90,13 @@ var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinS
[aCoder encodeSize:_minSize forKey:_CPCibWindowTemplateMinSizeKey];
if (_maxSize)
[aCoder encodeSize:_maxSize forKey:_CPCibWindowTemplateMaxSizeKey];
[aCoder encodeObject:_viewClass forKey:_CPCibWindowTemplateViewClassKey];
[aCoder encodeObject:_windowClass forKey:_CPCibWindowTemplateWindowClassKey];
[aCoder encodeRect:_windowRect forKey:_CPCibWindowTemplateWindowRectKey];
[aCoder encodeInt:_windowStyleMask forKey:_CPCibWindowTemplateWindowStyleMaskKey];
[aCoder encodeObject:_windowTitle forKey:_CPCibWindowTemplateWindowTitleKey];
[aCoder encodeObject:_windowView forKey:_CPCibWindowTemplateWindowViewKey];
@@ -126,13 +126,13 @@ var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinS
- (id)_cibInstantiate
{
var windowClass = CPClassFromString([self windowClass]);
/* if (!windowClass)
[NSException raise:NSInvalidArgumentException format:@"Unable to locate NSWindow class %@, using NSWindow",_windowClass];
class=[NSWindow class];*/
var theWindow = [[windowClass alloc] initWithContentRect:_windowRect styleMask:_windowStyleMask];
if (_minSize)
[theWindow setMinSize:_minSize];
if (_maxSize)
@@ -147,7 +147,7 @@ var _CPCibWindowTemplateMinSizeKey = @"_CPCibWindowTemplateMinS
[theWindow setContentView:_windowView];
[_windowView setAutoresizesSubviews:YES];
if ([_viewClass isKindOfClass:[CPToolbar class]])
{
[theWindow setToolbar:_viewClass];
+6 -6
View File
@@ -46,10 +46,10 @@
- (id)init
{
self = [super init];
if (self)
_isRemovedOnCompletion = YES;
return self;
}
@@ -130,12 +130,12 @@
@end
/*
*/
@implementation CAPropertyAnimation : CAAnimation
{
CPString _keyPath;
BOOL _isCumulative;
BOOL _isAdditive;
}
@@ -143,9 +143,9 @@
+ (id)animationWithKeyPath:(CPString)aKeyPath
{
var animation = [self animation];
[animation setKeyPath:aKeyPath];
return animation;
}
+5 -5
View File
@@ -37,9 +37,9 @@ if (CPFeatureIsCompatible(CPHTMLCanvasFeature))
CABackingStoreCreate = function()
{
var DOMElement = document.createElement("canvas");
DOMElement.style.position = "absolute";
// FIXME: Consolidate drawImage to support this.
return { context:DOMElement.getContext("2d"), buffer:DOMElement, _image:DOMElement };
}
@@ -47,7 +47,7 @@ CABackingStoreCreate = function()
CABackingStoreSetSize = function(aBackingStore, aSize)
{
var buffer = aBackingStore.buffer;
buffer.width = aSize.width;
buffer.height = aSize.height;
buffer.style.width = PIXEL(aSize.width);
@@ -60,9 +60,9 @@ else
CABackingStoreCreate = function()
{
var context = CGBitmapGraphicsContextCreate();
context.buffer = "";
return { context:context };
}
+4 -4
View File
@@ -33,12 +33,12 @@
{
if (_flashMovie == aFlashMovie)
return;
_flashMovie = aFlashMovie;
_DOMElement.innerHTML = "<object width = \"100%\" height = \"100%\"><param name = \"movie\" value = \"" +
aFlashMovie._fileName +
"\"></param><param name = \"wmode\" value = \"transparent\"></param><embed src = \"" +
aFlashMovie._fileName +
"\"></param><param name = \"wmode\" value = \"transparent\"></param><embed src = \"" +
aFlashMovie._fileName + "\" type = \"application/x-shockwave-flash\" wmode = \"transparent\" width = \"100%\" height = \"100%\"></embed></object>";
}
+156 -151
View File
@@ -64,54 +64,54 @@ var CALayerRegisteredRunLoopUpdates = nil;
@implementation CALayer : CPObject
{
// Modifying the Layer Geometry
CGRect _frame;
CGRect _bounds;
CGPoint _position;
unsigned _zPosition;
CGPoint _anchorPoint;
CGAffineTransform _affineTransform;
CGAffineTransform _sublayerTransform;
CGAffineTransform _sublayerTransformForSublayers;
CGRect _backingStoreFrame;
CGRect _standardBackingStoreFrame;
BOOL _hasSublayerTransform;
BOOL _hasCustomBackingStoreFrame;
// Style Attributes
float _opacity;
BOOL _isHidden;
CPColor _backgroundColor;
// Managing Layer Hierarchy
CALayer _superlayer;
CPMutableArray _sublayers;
// Updating Layer Display
unsigned _runLoopUpdateMask;
BOOL _needsDisplayOnBoundsChange;
// Modifying the Delegate
id _delegate;
BOOL _delegateRespondsToDisplayLayerSelector;
BOOL _delegateRespondsToDrawLayerInContextSelector;
// DOM Implementation
DOMElement _DOMElement;
DOMElement _DOMContentsElement;
id _contents;
CGContext _context;
CPView _owningView;
CGAffineTransform _transformToLayer;
CGAffineTransform _transformFromLayer;
}
@@ -130,14 +130,14 @@ var CALayerRegisteredRunLoopUpdates = nil;
- (id)init
{
self = [super init];
if (self)
{
_frame = CGRectMakeZero();
_backingStoreFrame = CGRectMakeZero();
_standardBackingStoreFrame = CGRectMakeZero();
_bounds = CGRectMakeZero();
_position = CGPointMakeZero();
_zPosition = 0.0;
@@ -147,15 +147,15 @@ var CALayerRegisteredRunLoopUpdates = nil;
_transformToLayer = CGAffineTransformMakeIdentity(); // FIXME? does it matter?
_transformFromLayer = CGAffineTransformMakeIdentity();
_opacity = 1.0;
_isHidden = NO;
_masksToBounds = NO;
_sublayers = [];
_DOMElement = document.createElement("div");
_DOMElement.style.overflow = "visible";
_DOMElement.style.position = "absolute";
_DOMElement.style.visibility = "visible";
@@ -165,7 +165,7 @@ var CALayerRegisteredRunLoopUpdates = nil;
_DOMElement.style.width = "0px";
_DOMElement.style.height = "0px";
}
return self;
}
@@ -182,20 +182,20 @@ var CALayerRegisteredRunLoopUpdates = nil;
var oldOrigin = _bounds.origin;
_bounds = _CGRectMakeCopy(aBounds);
if (_hasSublayerTransform)
_CALayerUpdateSublayerTransformForSublayers(self);
// _hasSublayerTransform == true will handle this for us.
/*else if (!CGPointEqualToPoint(_bounds.origin, oldOrigin))
{
var index = _sublayers.length;
// FIXME: This should climb the layer tree down.
while (index--)
_CALayerRecalculateGeometry(_sublayers[index], CALayerGeometryPositionMask);
}*/
_CALayerRecalculateGeometry(self, CALayerGeometryBoundsMask);
}
@@ -215,9 +215,9 @@ var CALayerRegisteredRunLoopUpdates = nil;
{
if (CGPointEqualToPoint(_position, aPosition))
return;
_position = _CGPointMakeCopy(aPosition);
_CALayerRecalculateGeometry(self, CALayerGeometryPositionMask);
}
@@ -237,9 +237,9 @@ var CALayerRegisteredRunLoopUpdates = nil;
{
if (_zPosition == aZPosition)
return;
_zPosition = aZPosition;
[self registerRunLoopUpdateWithMask:CALayerZPositionUpdateMask];
}
@@ -252,18 +252,18 @@ var CALayerRegisteredRunLoopUpdates = nil;
anAnchorPoint = _CGPointMakeCopy(anAnchorPoint);
anAnchorPoint.x = MIN(1.0, MAX(0.0, anAnchorPoint.x));
anAnchorPoint.y = MIN(1.0, MAX(0.0, anAnchorPoint.y));
if (CGPointEqualToPoint(_anchorPoint, anAnchorPoint))
return;
_anchorPoint = anAnchorPoint;
if (_hasSublayerTransform)
_CALayerUpdateSublayerTransformForSublayers(self);
if (_owningView)
_position = CGPointMake(_CGRectGetWidth(_bounds) * _anchorPoint.x, _CGRectGetHeight(_bounds) * _anchorPoint.y);
_CALayerRecalculateGeometry(self, CALayerGeometryAnchorPointMask);
}
@@ -283,9 +283,9 @@ var CALayerRegisteredRunLoopUpdates = nil;
{
if (CGAffineTransformEqualToTransform(_affineTransform, anAffineTransform))
return;
_affineTransform = _CGAffineTransformMakeCopy(anAffineTransform);
_CALayerRecalculateGeometry(self, CALayerGeometryAffineTransformMask);
}
@@ -307,16 +307,16 @@ var CALayerRegisteredRunLoopUpdates = nil;
return;
var hadSublayerTransform = _hasSublayerTransform;
_sublayerTransform = _CGAffineTransformMakeCopy(anAffineTransform);
_hasSublayerTransform = !_CGAffineTransformIsIdentity(_sublayerTransform);
if (_hasSublayerTransform)
{
_CALayerUpdateSublayerTransformForSublayers(self);
var index = _sublayers.length;
// FIXME: This should climb the layer tree down.
while (index--)
_CALayerRecalculateGeometry(_sublayers[index], CALayerGeometryParentSublayerTransformMask);
@@ -353,23 +353,23 @@ var CALayerRegisteredRunLoopUpdates = nil;
/*!
Returns the layer's frame.
The frame defines the bounding box of the layer: the smallest
possible rectangle that could fit this layer after transform
The frame defines the bounding box of the layer: the smallest
possible rectangle that could fit this layer after transform
properties are applied in superlayer coordinates.
*/
- (CGRect)frame
{
if (!_frame)
_frame = [self convertRect:_bounds toLayer:_superlayer];
return _frame;
}
/*!
The Backing Store Frame specifies the frame of the actual backing
store used to contain this layer. Naturally, by default it is the
same as the frame, however, users can specify their own custom
Backing Store Frame in order to speed up certain operations, such as
store used to contain this layer. Naturally, by default it is the
same as the frame, however, users can specify their own custom
Backing Store Frame in order to speed up certain operations, such as
live transformation.
@return the backing store frame
*/
@@ -385,7 +385,7 @@ var CALayerRegisteredRunLoopUpdates = nil;
- (void)setBackingStoreFrame:(CGRect)aFrame
{
_hasCustomBackingStoreFrame = (aFrame != nil);
if (aFrame == nil)
aFrame = CGRectMakeCopy(_standardBackingStoreFrame);
else
@@ -393,23 +393,23 @@ var CALayerRegisteredRunLoopUpdates = nil;
if (_superlayer)
{
aFrame = [_superlayer convertRect:aFrame toLayer:nil];
var bounds = [_superlayer bounds],
frame = [_superlayer convertRect:bounds toLayer:nil];
aFrame.origin.x -= _CGRectGetMinX(frame);
aFrame.origin.y -= _CGRectGetMinY(frame);
}
else
aFrame = CGRectMakeCopy(aFrame);
}
if (!CGPointEqualToPoint(_backingStoreFrame.origin, aFrame.origin))
[self registerRunLoopUpdateWithMask:CALayerFrameOriginUpdateMask];
if (!CGSizeEqualToSize(_backingStoreFrame.size, aFrame.size))
[self registerRunLoopUpdateWithMask:CALayerFrameSizeUpdateMask];
_backingStoreFrame = aFrame;
}
@@ -431,9 +431,9 @@ var CALayerRegisteredRunLoopUpdates = nil;
{
if (_contents == contents)
return;
_contents = contents;
[self composite];
}
@@ -445,27 +445,32 @@ var CALayerRegisteredRunLoopUpdates = nil;
{
if (USE_BUFFER && !_contents || !_context)
return;
CGContextClearRect(_context, _CGRectMake(0.0, 0.0, _CGRectGetWidth(_backingStoreFrame), _CGRectGetHeight(_backingStoreFrame)));
// Recomposite
var transform = _transformFromLayer;
var transform;
if (_superlayer)
{
var superlayerTransform = _CALayerGetTransform(_superlayer, nil),
superlayerOrigin = CGPointApplyAffineTransform(_superlayer._bounds.origin, superlayerTransform);
transform = CGAffineTransformConcat(transform, superlayerTransform);
transform = CGAffineTransformConcat(_transformFromLayer, superlayerTransform);
transform.tx -= superlayerOrigin.x;
transform.ty -= superlayerOrigin.y;
}
else
// Copy so we don't affect the original.
transform = CGAffineTransformCreateCopy(_transformFromLayer);
transform.tx -= _CGRectGetMinX(_backingStoreFrame);
transform.ty -= _CGRectGetMinY(_backingStoreFrame);
CGContextSaveGState(_context);
CGContextConcatCTM(_context, transform);//_transformFromView);
if (USE_BUFFER)
{
@@ -485,18 +490,18 @@ var CALayerRegisteredRunLoopUpdates = nil;
if (!_context)
{
_context = CGBitmapGraphicsContextCreate();
_DOMContentsElement = _context.DOMElement;
_DOMContentsElement.style.zIndex = -100;
_DOMContentsElement.style.overflow = "hidden";
_DOMContentsElement.style.position = "absolute";
_DOMContentsElement.style.visibility = "visible";
_DOMContentsElement.width = ROUND(_CGRectGetWidth(_backingStoreFrame));
_DOMContentsElement.height = ROUND(_CGRectGetHeight(_backingStoreFrame));
_DOMContentsElement.style.top = "0px";
_DOMContentsElement.style.left = "0px";
_DOMContentsElement.style.width = ROUND(_CGRectGetWidth(_backingStoreFrame)) + "px";
@@ -504,23 +509,23 @@ var CALayerRegisteredRunLoopUpdates = nil;
_DOMElement.appendChild(_DOMContentsElement);
}
if (USE_BUFFER)
{
if (_delegateRespondsToDisplayLayerSelector)
return [_delegate displayInLayer:self];
if (_CGRectGetWidth(_backingStoreFrame) == 0.0 || _CGRectGetHeight(_backingStoreFrame) == 0.0)
return;
if (!_contents)
_contents = CABackingStoreCreate();
CABackingStoreSetSize(_contents, _bounds.size);
[self drawInContext:CABackingStoreGetContext(_contents)];
}
[self composite];
}
@@ -535,7 +540,7 @@ var CALayerRegisteredRunLoopUpdates = nil;
CGContextSetFillColor(aContext, _backgroundColor);
CGContextFillRect(aContext, _bounds);
}
if (_delegateRespondsToDrawLayerInContextSelector)
[_delegate drawLayer:self inContext:aContext];
}
@@ -559,9 +564,9 @@ var CALayerRegisteredRunLoopUpdates = nil;
{
if (_opacity == anOpacity)
return;
_opacity = anOpacity;
_DOMElement.style.opacity = anOpacity;
_DOMElement.style.filter = "alpha(opacity=" + anOpacity * 100 + ")";
}
@@ -600,7 +605,7 @@ var CALayerRegisteredRunLoopUpdates = nil;
{
if (_masksToBounds == masksToBounds)
return;
_masksToBounds = masksToBounds;
_DOMElement.style.overflow = _masksToBounds ? "hidden" : "visible";
}
@@ -612,7 +617,7 @@ var CALayerRegisteredRunLoopUpdates = nil;
- (void)setBackgroundColor:(CPColor)aColor
{
_backgroundColor = aColor;
[self setNeedsDisplay];
}
@@ -665,10 +670,10 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
{
if (_owningView)
[_owningView setLayer:nil];
if (!_superlayer)
return;
_superlayer._DOMElement.removeChild(_DOMElement);
[_superlayer._sublayers removeObject:self];
@@ -684,24 +689,24 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
{
if (!aLayer)
return;
var superlayer = [aLayer superlayer];
if (superlayer == self)
{
var index = [_sublayers indexOfObjectIdenticalTo:aLayer];
if (index == anIndex)
return;
[_sublayers removeObjectAtIndex:index];
if (index < anIndex)
--anIndex;
}
else if (superlayer != nil)
[aLayer removeFromSuperlayer];
ADJUST_CONTENTS_ZINDEX(aLayer);
[_sublayers insertObject:aLayer atIndex:anIndex];
@@ -710,9 +715,9 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
_DOMElement.appendChild(DOM(aLayer));
else
_DOMElement.insertBefore(DOM(aLayer), _sublayers[anIndex + 1]._DOMElement);
aLayer._superlayer = self;
if (self != superlayer)
_CALayerRecalculateGeometry(aLayer, 0xFFFFFFF);
}
@@ -726,7 +731,7 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
- (void)insertSublayer:(CALayer)aLayer below:(CALayer)aSublayer
{
var index = aSublayer ? [_sublayers indexOfObjectIdenticalTo:aSublayer] : 0;
[self insertSublayer:aLayer atIndex:index == CPNotFound ? _sublayers.length : index];
}
@@ -754,16 +759,16 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
{
if (aSublayer == aLayer)
return;
// FIXME: EXCEPTION
if (aSublayer._superlayer != self)
{
alert("EXCEPTION");
return;
}
ADJUST_CONTENTS_ZINDEX(aLayer);
[_sublayers replaceObjectAtIndex:[_sublayers indexOfObjectIdenticalTo:aSublayer] withObject:aLayer];
_DOMElement.replaceChild(DOM(aSublayer), DOM(aLayer));
}
@@ -782,16 +787,16 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
if (mask & CALayerDOMUpdateMask)
_CALayerUpdateDOM(layer, mask);
if (mask & CALayerDisplayUpdateMask)
[layer display];
else if (mask & CALayerFrameSizeUpdateMask || mask & CALayerCompositeUpdateMask)
[layer composite];
layer._runLoopUpdateMask = 0;
}
window.loop= false;
window.loop = false;
CALayerRegisteredRunLoopUpdates = nil;
}
@@ -803,11 +808,11 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
if (CALayerRegisteredRunLoopUpdates == nil)
{
CALayerRegisteredRunLoopUpdates = {};
[[CPRunLoop currentRunLoop] performSelector:@selector(runLoopUpdateLayers)
target:CALayer argument:nil order:0 modes:[CPDefaultRunLoopMode]];
}
_runLoopUpdateMask |= anUpdateMask;
CALayerRegisteredRunLoopUpdates[[self UID]] = self;
}
@@ -846,7 +851,7 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
}
/*!
Marks the specified rectange as needing to be redrawn.
Marks the specified rectangle as needing to be redrawn.
@param aRect the area that needs to be redrawn.
*/
- (void)setNeedsDisplayInRect:(CGRect)aRect
@@ -890,8 +895,8 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
}
/*!
Converts the rectangle from the receier's coordinate system to the specified layer's coordinate system.
@param aRect the rectange to convert
Converts the rectangle from the receiver's coordinate system to the specified layer's coordinate system.
@param aRect the rectangle to convert
@param aLayer the layer coordinate system to convert to
@return the converted rectangle
*/
@@ -919,21 +924,21 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
{
if (_isHidden)
return nil;
var point = CGPointApplyAffineTransform(aPoint, _transformToLayer);
//alert(point.x + " " + point.y);
if (!_CGRectContainsPoint(_bounds, point))
return nil;
var layer = nil,
index = _sublayers.length;
// FIXME: this should take into account zPosition.
while (index--)
if (layer = [_sublayers[index] hitTest:point])
return layer;
return self;
}
@@ -946,12 +951,12 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
{
if (_delegate == aDelegate)
return;
_delegate = aDelegate;
_delegateRespondsToDisplayLayerSelector = [_delegate respondsToSelector:@selector(displayLayer:)];
_delegateRespondsToDrawLayerInContextSelector = [_delegate respondsToSelector:@selector(drawLayer:inContext:)];
if (_delegateRespondsToDisplayLayerSelector || _delegateRespondsToDrawLayerInContextSelector)
[self setNeedsDisplay];
}
@@ -968,15 +973,15 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
- (void)_setOwningView:(CPView)anOwningView
{
_owningView = anOwningView;
if (_owningView)
{
_owningView = anOwningView;
_bounds.size = CGSizeMakeCopy([_owningView bounds].size);
_position = CGPointMake(_CGRectGetWidth(_bounds) * _anchorPoint.x, _CGRectGetHeight(_bounds) * _anchorPoint.y);
}
_CALayerRecalculateGeometry(self, CALayerGeometryPositionMask | CALayerGeometryBoundsMask);
}
@@ -985,7 +990,7 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
{
_bounds.size = CGSizeMakeCopy([_owningView bounds].size);
_position = CGPointMake(_CGRectGetWidth(_bounds) * _anchorPoint.x, _CGRectGetHeight(_bounds) * _anchorPoint.y);
_CALayerRecalculateGeometry(self, CALayerGeometryPositionMask | CALayerGeometryBoundsMask);
}
@@ -993,20 +998,20 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
- (void)_update
{
window.loop = true;
var mask = _runLoopUpdateMask;
if (mask & CALayerDOMUpdateMask)
_CALayerUpdateDOM(self, mask);
if (mask & CALayerDisplayUpdateMask)
[self display];
else if (mask & CALayerFrameSizeUpdateMask || mask & CALayerCompositeUpdateMask)
[self composite];
_runLoopUpdateMask = 0;
window.loop = false;
}
@@ -1018,7 +1023,7 @@ function _CALayerUpdateSublayerTransformForSublayers(aLayer)
anchorPoint = aLayer._anchorPoint,
translateX = _CGRectGetWidth(bounds) * anchorPoint.x,
translateY = _CGRectGetHeight(bounds) * anchorPoint.y;
aLayer._sublayerTransformForSublayers = CGAffineTransformConcat(
CGAffineTransformMakeTranslation(-translateX, -translateY),
CGAffineTransformConcat(aLayer._sublayerTransform,
@@ -1028,27 +1033,27 @@ function _CALayerUpdateSublayerTransformForSublayers(aLayer)
function _CALayerUpdateDOM(aLayer, aMask)
{
var DOMElementStyle = aLayer._DOMElement.style;
if (aMask & CALayerZPositionUpdateMask)
DOMElementStyle.zIndex = aLayer._zPosition;
var frame = aLayer._backingStoreFrame;
if (aMask & CALayerFrameOriginUpdateMask)
{
DOMElementStyle.top = ROUND(_CGRectGetMinY(frame)) + "px";
DOMElementStyle.left = ROUND(_CGRectGetMinX(frame)) + "px";
}
if (aMask & CALayerFrameSizeUpdateMask)
{
var width = MAX(0.0, ROUND(_CGRectGetWidth(frame))),
height = MAX(0.0, ROUND(_CGRectGetHeight(frame))),
DOMContentsElement = aLayer._DOMContentsElement;
DOMElementStyle.width = width + "px";
DOMElementStyle.height = height + "px";
if (DOMContentsElement)
{
DOMContentsElement.width = width;
@@ -1070,7 +1075,7 @@ function _CALayerRecalculateGeometry(aLayer, aGeometryChange)
affineTransform = aLayer._affineTransform,
backingStoreFrameSize = _CGSizeMakeCopy(aLayer._backingStoreFrame),
hasCustomBackingStoreFrame = aLayer._hasCustomBackingStoreFrame;
// Go to anchor, transform, go back to bounds.
aLayer._transformFromLayer = CGAffineTransformConcat(
CGAffineTransformMakeTranslation(-width * anchorPoint.x - _CGRectGetMinX(aLayer._bounds), -height * anchorPoint.y - _CGRectGetMinY(aLayer._bounds)),
@@ -1082,68 +1087,68 @@ function _CALayerRecalculateGeometry(aLayer, aGeometryChange)
// aLayer._transformFromLayer = CGAffineTransformConcat(aLayer._transformFromLayer, superlayer._sublayerTransformForSublayers);
_CGAffineTransformConcatTo(aLayer._transformFromLayer, superlayer._sublayerTransformForSublayers, aLayer._transformFromLayer);
}
aLayer._transformToLayer = CGAffineTransformInvert(aLayer._transformFromLayer);
//aLayer._transformFromLayer.tx = ROUND(aLayer._transformFromLayer.tx);
//aLayer._transformFromLayer.ty = ROUND(aLayer._transformFromLayer.ty);
aLayer._frame = nil;
aLayer._standardBackingStoreFrame = [aLayer convertRect:bounds toLayer:nil];
if (superlayer)
{
var bounds = [superlayer bounds],
frame = [superlayer convertRect:bounds toLayer:nil];
aLayer._standardBackingStoreFrame.origin.x -= _CGRectGetMinX(frame);
aLayer._standardBackingStoreFrame.origin.y -= _CGRectGetMinY(frame);
}
// We used to use CGRectIntegral here, but what we actually want, is the largest integral
// rect that would ever contain this box, since for any width/height, there are 2 (4)
// rect that would ever contain this box, since for any width/height, there are 2 (4)
// possible integral rects for it depending on it's position. It's OK that this is sometimes
// bigger than the "optimal" bounding integral rect since that doesn't change drawing.
var origin = aLayer._standardBackingStoreFrame.origin,
size = aLayer._standardBackingStoreFrame.size;
origin.x = FLOOR(origin.x);
origin.y = FLOOR(origin.y);
size.width = CEIL(size.width) + 1.0;
size.height = CEIL(size.height) + 1.0;
// FIXME: This avoids the central issue that a position change is sometimes a display and sometimes
// a div move, and sometimes both.
// Only use this frame if we don't currently have a custom backing store frame.
if (!hasCustomBackingStoreFrame)
{
var backingStoreFrame = CGRectMakeCopy(aLayer._standardBackingStoreFrame);
// These values get rounded in the DOM, so don't both updating them if they're
// These values get rounded in the DOM, so don't both updating them if they're
// not going to be different after rounding.
if (ROUND(_CGRectGetMinX(backingStoreFrame)) != ROUND(_CGRectGetMinX(aLayer._backingStoreFrame)) ||
ROUND(_CGRectGetMinY(backingStoreFrame)) != ROUND(_CGRectGetMinY(aLayer._backingStoreFrame)))
[aLayer registerRunLoopUpdateWithMask:CALayerFrameOriginUpdateMask];
// Any change in size due to a geometry change is purely due to rounding error.
if ((_CGRectGetWidth(backingStoreFrame) != ROUND(_CGRectGetWidth(aLayer._backingStoreFrame)) ||
_CGRectGetHeight(backingStoreFrame) != ROUND(_CGRectGetHeight(aLayer._backingStoreFrame))))
[aLayer registerRunLoopUpdateWithMask:CALayerFrameSizeUpdateMask];
aLayer._backingStoreFrame = backingStoreFrame;
}
if (aGeometryChange & CALayerGeometryBoundsMask && aLayer._needsDisplayOnBoundsChange)
[aLayer setNeedsDisplay];
// We need to recomposite if we have a custom backing store frame, OR
// We need to recompose if we have a custom backing store frame, OR
// If the change is not solely composed of position and anchor points changes.
// Anchor point and position changes simply move the object, requiring
// Anchor point and position changes simply move the object, requiring
// no re-rendering.
else if (hasCustomBackingStoreFrame || (aGeometryChange & ~(CALayerGeometryPositionMask | CALayerGeometryAnchorPointMask)))
[aLayer setNeedsComposite];
var sublayers = aLayer._sublayers,
index = 0,
count = sublayers.length;
@@ -1155,45 +1160,45 @@ function _CALayerRecalculateGeometry(aLayer, aGeometryChange)
function _CALayerGetTransform(fromLayer, toLayer)
{
var transform = CGAffineTransformMakeIdentity();
if (fromLayer)
{
var layer = fromLayer;
// If we have a fromLayer, "climb up" the layer tree until
// If we have a fromLayer, "climb up" the layer tree until
// we hit the root node or we hit the toLayer.
while (layer && layer != toLayer)
{
var transformFromLayer = layer._transformFromLayer;
//transform = CGAffineTransformConcat(transform, layer._transformFromLayer);
_CGAffineTransformConcatTo(transform, transformFromLayer, transform);
layer = layer._superlayer;
}
// If we hit toLayer, then we're done.
if (layer == toLayer)
return transform;
}
var layers = [],
layer = toLayer;
while (layer)
{
layers.push(layer);
layer = layer._superlayer;
}
var index = layers.length;
while (index--)
{
var transformToLayer = layers[index]._transformToLayer;
_CGAffineTransformConcatTo(transform, transformToLayer, transform);
}
return transform;
}
+4 -4
View File
@@ -45,13 +45,13 @@ var CAMediaNamedTimingFunctions = nil;
if (!CAMediaNamedTimingFunctions)
{
CAMediaNamedTimingFunctions = [CPDictionary dictionary];
[CAMediaNamedTimingFunctions setObject:[CAMediaTimingFunction functionWithControlPoints:0.0 :0.0 :1.0 :1.0] forKey:kCAMediaTimingFunctionLinear];
[CAMediaNamedTimingFunctions setObject:[CAMediaTimingFunction functionWithControlPoints:0.42 :0.0 :1.0 :1.0] forKey:kCAMediaTimingFunctionEaseIn];
[CAMediaNamedTimingFunctions setObject:[CAMediaTimingFunction functionWithControlPoints:0.0 :0.0 :0.58 :1.0] forKey:kCAMediaTimingFunctionEaseOut];
[CAMediaNamedTimingFunctions setObject:[CAMediaTimingFunction functionWithControlPoints:0.42 :0.0 :0.58 :1.0] forKey:kCAMediaTimingFunctionEaseInEaseOut];
}
return [CAMediaNamedTimingFunctions objectForKey:aName];
}
@@ -63,7 +63,7 @@ var CAMediaNamedTimingFunctions = nil;
- (id)initWithControlPoints:(float)c1x :(float)c1y :(float)c2x :(float)c2y
{
self = [super init];
if (self)
{
_c1x = c1x;
@@ -71,7 +71,7 @@ var CAMediaNamedTimingFunctions = nil;
_c2x = c2x;
_c2y = c2y;
}
return self;
}
+2 -2
View File
@@ -65,7 +65,7 @@ function CGAffineTransformMakeRotation(anAngle)
{
var sin = SIN(anAngle),
cos = COS(anAngle);
return _CGAffineTransformMake(cos, sin, -sin, cos, 0.0, 0.0);
}
@@ -133,7 +133,7 @@ function CGRectApplyAffineTransform(aRect, anAffineTransform)
maxX = MAX(topLeft.x, topRight.x, bottomLeft.x, bottomRight.x),
minY = MIN(topLeft.y, topRight.y, bottomLeft.y, bottomRight.y),
maxY = MAX(topLeft.y, topRight.y, bottomLeft.y, bottomRight.y);
return _CGRectMake(minX, minY, (maxX - minX), (maxY - minY));
}
+16 -13
View File
@@ -47,7 +47,7 @@ function CGColorGetConstantColor(aColorName)
}
/*!
This function is for source compatability.
This function is for source compatibility.
*/
function CGColorRetain(aColor)
{
@@ -55,7 +55,7 @@ function CGColorRetain(aColor)
}
/*!
This function is for source compatability.
This function is for source compatibility.
*/
function CGColorRelease()
{
@@ -108,7 +108,7 @@ function CGColorCreateCopy(aColor)
*/
function CGColorCreateGenericGray(gray, alpha)
{
return CGColorCreate(0, [gray, alpha]);
return CGColorCreate(CGColorSpaceCreateDeviceRGB(), [gray,gray,gray, alpha]);
}
/*!
@@ -122,7 +122,7 @@ function CGColorCreateGenericGray(gray, alpha)
*/
function CGColorCreateGenericRGB(red, green, blue, alpha)
{
return CGColorCreate(0, [red, green, blue, alpha]);
return CGColorCreate(CGColorSpaceCreateDeviceRGB(), [red, green, blue, alpha]);
}
/*!
@@ -137,7 +137,8 @@ function CGColorCreateGenericRGB(red, green, blue, alpha)
*/
function CGColorCreateGenericCMYK(cyan, magenta, yellow, black, alpha)
{
return CGColorCreate(0, [cyan, magenta, yellow, black, alpha]);
return CGColorCreate(CGColorSpaceCreateDeviceCMYK(),
[cyan, magenta, yellow, black, alpha]);
}
/*!
@@ -149,19 +150,21 @@ function CGColorCreateGenericCMYK(cyan, magenta, yellow, black, alpha)
*/
function CGColorCreateCopyWithAlpha(aColor, anAlpha)
{
var components = aColor.components;
if ( !aColor ) return aColor; // Avoid error null pointer in next line
if (!aColor || anAlpha == components[components.length - 1])
var components = aColor.components.slice();
if (anAlpha == components[components.length - 1])
return aColor;
// set new alpha value now so that a potentially a new cache entry is made and
// not that an existing cache entry is mutated.
components[components.length - 1] = anAlpha;
if (aColor.pattern)
var copy = CGColorCreateWithPattern(aColor.colorspace, aColor.pattern, components);
return CGColorCreateWithPattern(aColor.colorspace, aColor.pattern, components);
else
var copy = CGColorCreate(aColor.colorspace, components);
copy.components[components.length - 1] = anAlpha;
return copy;
return CGColorCreate(aColor.colorspace, components);
}
/*!

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