Compare commits

...
557 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
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
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
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
Derek Hammer 85f51d7a66 Extend selection in a meaningful way when using keys. 2011-01-27 21:50:36 -08:00
Antoine Mercadal 3a6f2c4d5b make CPSound handling error + More Cocoa compliant 2011-01-26 11:06:10 +01:00
Antoine Mercadal f39441e101 avoid error in FF 2011-01-25 21:24:36 +01: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
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
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
493 changed files with 66471 additions and 12298 deletions
+4
View File
@@ -5,3 +5,7 @@ Demos
./Aristo
WebSite
.push-package
*.xcodeproj/*.pbxuser
*.xcodeproj/*.perspectivev3
xcuserdata/
!*.xcodeproj/project.pbxproj
+8
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,7 +93,9 @@
@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"
+220 -27
View File
@@ -50,6 +50,8 @@
CPArray _sortDescriptors;
CPPredicate _filterPredicate;
CPArray _arrangedObjects;
BOOL _disableSetContent;
}
+ (void)initialize
@@ -68,7 +70,8 @@
+ (CPSet)keyPathsForValuesAffectingArrangedObjects
{
return [CPSet setWithObjects:"content", "filterPredicate", "sortDescriptors"];
// Also depends on "filterPredicate" but we'll handle that manually.
return [CPSet setWithObjects:"content", "sortDescriptors"];
}
+ (CPSet)keyPathsForValuesAffectingSelection
@@ -136,7 +139,7 @@
_sortDescriptors = [CPArray array];
_filterPredicate = nil;
_selectionIndexes = [CPIndexSet indexSet];
_arrangedObjects = nil;
[self __setArrangedObjects:[CPArray array]];
}
- (void)prepareContent
@@ -273,6 +276,12 @@
*/
- (void)setContent:(id)value
{
// This is used to ignore expected setContent: calls caused by a binding to our content
// object when we are the ones modifying the content object and can deal with the update
// faster directly in the code in charge of the modification.
if (_disableSetContent)
return;
if (value === nil)
value = [];
@@ -304,6 +313,8 @@
// 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 && _filterPredicate != nil)
@@ -480,7 +491,14 @@
*/
- (void)setFilterPredicate:(CPPredicate)value
{
if (_filterPredicate === value)
return;
// __setFilterPredicate will call _rearrangeObjects without
// sending notifications, so we must send them instead.
[self willChangeValueForKey:@"arrangedObjects"];
[self __setFilterPredicate:value];
[self didChangeValueForKey:@"arrangedObjects"];
}
/*
@@ -493,8 +511,7 @@
return;
_filterPredicate = value;
// Use the non-notification version since arrangedObjects already depends
// on filterPredicate.
// Use the non-notification version.
[self _rearrangeObjects];
}
@@ -704,17 +721,39 @@
if (![self canAdd])
return;
if (_clearsFilterPredicateOnInsertion)
var willClearPredicate = NO;
if (_clearsFilterPredicateOnInsertion && _filterPredicate)
{
[self willChangeValueForKey:@"filterPredicate"];
willClearPredicate = YES;
}
[self willChangeValueForKey:@"content"];
/*
If the content array is bound then our addObject: message below will cause the observed
array to change. The binding will call setContent:_contentObject on this array
controller to let it know about the change. We want to ignore that message since we
A) already have the right _contentObject and B) properly update _arrangedObjects
by hand below.
*/
_disableSetContent = YES;
[_contentObject addObject:object];
if (_clearsFilterPredicateOnInsertion)
[self __setFilterPredicate:nil];
// Allow handlesContentAsCompoundValue reverse sets to trigger.
[[CPBinder getBinding:@"contentArray" forObject:self] _contentArrayDidChange];
if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:object])
_disableSetContent = NO;
if (willClearPredicate)
{
// Full rearrange needed due to changed filter.
_filterPredicate = nil;
[self _rearrangeObjects];
}
else if (_filterPredicate === nil || [_filterPredicate evaluateWithObject:object])
{
// Insert directly into the array.
var pos = [_arrangedObjects insertObject:object inArraySortedByDescriptors:_sortDescriptors];
// selectionIndexes change notification will be fired as a result of the
@@ -724,16 +763,22 @@
else
[_selectionIndexes shiftIndexesStartingAtIndex:pos by:1];
}
else
[self _rearrangeObjects];
/*
else if (_filterPredicate !== nil)
...
// Implies _filterPredicate && ![_filterPredicate evaluateWithObject:object], so the new object does
// not appear in arrangedObjects and we do not have to update at all.
*/
// This will also send notificaitons for arrangedObjects.
[self didChangeValueForKey:@"content"];
if (_clearsFilterPredicateOnInsertion)
if (willClearPredicate)
[self didChangeValueForKey:@"filterPredicate"];
}
/*!
Adds an object at a given index to the receiver's collection.
Adds an object at a given index in the receiver's arrangedObjects. Also add the object
to the content collection (although at the end rather than the given index).
@param id anObject - The object to add to the collection.
@param int anIndex - The index to insert the object at.
@@ -743,13 +788,30 @@
if (![self canAdd])
return;
if (_clearsFilterPredicateOnInsertion)
var willClearPredicate = NO;
if (_clearsFilterPredicateOnInsertion && _filterPredicate)
{
[self willChangeValueForKey:@"filterPredicate"];
willClearPredicate = YES;
}
[self willChangeValueForKey:@"content"];
[_contentObject insertObject:anObject atIndex:anIndex];
if (_clearsFilterPredicateOnInsertion)
/*
See _disableSetContent explanation in addObject:.
*/
_disableSetContent = YES;
// The atArrangedObjectIndex: part of this method's name only refers to where the
// object goes in arrangedObjects, not in the content array. So use addObject:,
// not insertObject:atIndex: here for speed.
[_contentObject addObject:anObject];
// Allow handlesContentAsCompoundValue reverse sets to trigger.
[[CPBinder getBinding:@"contentArray" forObject:self] _contentArrayDidChange];
_disableSetContent = NO;
if (willClearPredicate)
[self __setFilterPredicate:nil];
[[self arrangedObjects] insertObject:anObject atIndex:anIndex];
@@ -765,7 +827,7 @@
[self __setSelectionIndexes:[CPIndexSet indexSetWithIndex:0]];
[self didChangeValueForKey:@"content"];
if (_clearsFilterPredicateOnInsertion)
if (willClearPredicate)
[self didChangeValueForKey:@"filterPredicate"];
}
@@ -776,20 +838,28 @@
*/
- (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"];
}
/*!
@@ -825,16 +895,61 @@
*/
- (void)remove:(id)sender
{
[self removeObjects:[[self arrangedObjects] objectsAtIndexes:[self selectionIndexes]]];
[self removeObjectsAtArrangedObjectIndexes:_selectionIndexes];
}
/*!
Removes the objects at the specified indexes in the controller's arranged objects from the content array.
@param CPIndexSet indexes - indexes of the objects to remove.
*/
- (void)removeObjectsAtArrangedObjectIndexes:(CPIndexSet)indexes
- (void)removeObjectsAtArrangedObjectIndexes:(CPIndexSet)anIndexSet
{
[self _removeObjects:[[self arrangedObjects] objectsAtIndexes:indexes]];
[self willChangeValueForKey:@"content"];
/*
See _disableSetContent explanation in addObject:.
*/
_disableSetContent = YES;
var arrangedObjects = [self arrangedObjects],
index = [anIndexSet lastIndex],
position = CPNotFound,
newSelectionIndexes = [_selectionIndexes copy];
while (index !== CPNotFound)
{
var object = [arrangedObjects objectAtIndex:index];
// First try the simple case which should work if there are no sort descriptors.
if ([_contentObject objectAtIndex:index] === object)
[_contentObject removeObjectAtIndex:index];
else
{
// Since we don't have a reverse mapping between the sorted order and the
// unsorted one, we'll just simply have to remove an arbitrary pointer. It might
// be the 'wrong' one - as in not the one the user selected - but the wrong
// one is still just another pointer to the same object, so the user will not
// be able to see any difference.
contentIndex = [_contentObject indexOfObjectIdenticalTo:object];
[_contentObject removeObjectAtIndex:contentIndex];
}
[arrangedObjects removeObjectAtIndex:index];
// Deselect this row if it was selected, and either way shift all selection indexes
// following it up by 1.
[newSelectionIndexes removeIndex:index];
[newSelectionIndexes shiftIndexesStartingAtIndex:index by:-1];
index = [anIndexSet indexLessThanIndex:index];
}
// Allow handlesContentAsCompoundValue reverse sets to trigger.
[[CPBinder getBinding:@"contentArray" forObject:self] _contentArrayDidChange];
_disableSetContent = NO;
// This will automatically handle the avoidsEmptySelection case.
[self __setSelectionIndexes:newSelectionIndexes];
[self didChangeValueForKey:@"content"];
}
/*!
@@ -854,6 +969,8 @@
[contentArray addObject:[objects objectAtIndex:i]];
[self setContent:contentArray];
// Allow handlesContentAsCompoundValue reverse sets to trigger.
[[CPBinder getBinding:@"contentArray" forObject:self] _contentArrayDidChange];
}
/*!
@@ -871,7 +988,15 @@
- (void)_removeObjects:(CPArray)objects
{
[self willChangeValueForKey:@"content"];
// See _disableSetContent explanation in addObject:.
_disableSetContent = YES;
[_contentObject removeObjectsInArray:objects];
// Allow handlesContentAsCompoundValue reverse sets to trigger.
[[CPBinder getBinding:@"contentArray" forObject:self] _contentArrayDidChange];
_disableSetContent = NO;
var arrangedObjects = [self arrangedObjects],
position = [arrangedObjects indexOfObject:[objects objectAtIndex:0]];
@@ -910,6 +1035,74 @@
@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",
+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
+66
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)
+5 -3
View File
@@ -304,7 +304,7 @@
tableHeight = CGRectGetHeight([tableView bounds]);
[[tableView tableColumnWithIdentifier:"Image"] setWidth:_imageWidth];
[[tableView tableColumnWithIdentifier:"Content"] setWidth:width - (_leafWidth + _delegateSupportsImages ? _imageWidth : 0) - scrollerWidth - scrollerWidth];
[[tableView tableColumnWithIdentifier:"Content"] setWidth:[self columnContentWidthForColumnWidth:width]];
[[tableView tableColumnWithIdentifier:"Leaf"] setWidth:_leafWidth];
[tableView setRowHeight:_rowHeight];
@@ -436,12 +436,14 @@
- (float)columnContentWidthForColumnWidth:(float)aWidth
{
return aWidth - (_leafWidth + _delegateSupportsImages ? _imageWidth : 0) - [CPScroller scrollerWidth];
var columnSpacing = [_tableViews[0] intercellSpacing].width;
return aWidth - (_leafWidth + columnSpacing + (_delegateSupportsImages ? _imageWidth + columnSpacing : 0)) - columnSpacing - [CPScroller scrollerWidth];
}
- (float)columnWidthForColumnContentWidth:(float)aWidth
{
return aWidth + (_leafWidth + _delegateSupportsImages ? _imageWidth : 0) + [CPScroller scrollerWidth];
var columnSpacing = [_tableViews[0] intercellSpacing].width;
return aWidth + (_leafWidth + columnSpacing + (_delegateSupportsImages ? _imageWidth + columnSpacing: 0)) + columnSpacing + [CPScroller scrollerWidth];
}
- (void)setImageWidth:(float)aWidth
+91 -16
View File
@@ -106,6 +106,11 @@ CPButtonImageOffset = 3.0;
CPString _keyEquivalent;
unsigned _keyEquivalentModifierMask;
CPTimer _continuousDelayTimer;
CPTimer _continuousTimer;
float _periodicDelay;
float _periodicInterval;
}
+ (id)buttonWithTitle:(CPString)aTitle
@@ -152,18 +157,27 @@ CPButtonImageOffset = 3.0;
[self setValue:CPImageLeft forThemeAttribute:@"image-position"];
[self setValue:CPScaleNone forThemeAttribute:@"image-scaling"];
_controlSize = CPRegularControlSize;
_keyEquivalent = @"";
_keyEquivalentModifierMask = 0;
[self setBezelStyle:CPRoundRectBezelStyle];
[self setBordered:YES];
[self _init];
}
return self;
}
- (void)_init
{
_controlSize = CPRegularControlSize;
_keyEquivalent = @"";
_keyEquivalentModifierMask = 0;
// Continuous button defaults.
_periodicInterval = 0.05;
_periodicDelay = 0.5;
}
// Setting the state
/*!
Returns a Boolean value indicating whether the button allows a mixed state.
@@ -450,6 +464,34 @@ CPButtonImageOffset = 3.0;
return _imageDimsWhenDisabled;
}
- (void)setPeriodicDelay:(float)aDelay interval:(float)anInterval
{
_periodicDelay = aDelay;
_periodicInterval = anInterval;
}
- (void)mouseDown:(CPEvent)anEvent
{
if ([self isContinuous])
{
_continuousDelayTimer = [CPTimer scheduledTimerWithTimeInterval:_periodicDelay callback: function()
{
if (!_continuousTimer)
_continuousTimer = [CPTimer scheduledTimerWithTimeInterval:_periodicInterval target:self selector:@selector(onContinousEvent:) userInfo:anEvent repeats:YES];
}
repeats:NO];
}
[super mouseDown:anEvent];
}
- (void)onContinousEvent:(CPTimer)aTimer
{
if (_target && _action && [_target respondsToSelector:_action])
[_target performSelector:_action withObject:self];
}
- (BOOL)startTrackingAt:(CGPoint)aPoint
{
[self highlight:YES];
@@ -460,6 +502,7 @@ CPButtonImageOffset = 3.0;
- (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp
{
[self highlight:NO];
[self invalidateTimers];
[super stopTracking:lastPoint at:aPoint mouseIsUp:mouseIsUp];
@@ -467,6 +510,21 @@ CPButtonImageOffset = 3.0;
[self setNextState];
}
- (void)invalidateTimers
{
if (_continuousTimer)
{
[_continuousTimer invalidate];
_continuousTimer = nil;
}
if (_continuousDelayTimer)
{
[_continuousDelayTimer invalidate];
_continuousDelayTimer = nil;
}
}
- (CGRect)contentRectForBounds:(CGRect)bounds
{
var contentInset = [self currentValueForThemeAttribute:@"content-inset"];
@@ -502,14 +560,9 @@ CPButtonImageOffset = 3.0;
return bounds;
}
/*!
Adjust the size of the button to fit the title and surrounding button image.
*/
- (void)sizeToFit
- (CGSize)_minimumFrameSize
{
[self layoutSubviews];
var size,
var size = CGSizeMakeZero(),
contentView = [self ephemeralSubviewNamed:@"content-view"];
if (contentView)
@@ -533,9 +586,19 @@ CPButtonImageOffset = 3.0;
if (maxSize.height >= 0.0)
size.height = MIN(size.height, maxSize.height);
[self setFrameSize:size];
return size;
}
if (contentView)
/*!
Adjust the size of the button to fit the title and surrounding button image.
*/
- (void)sizeToFit
{
[self layoutSubviews];
[self setFrameSize:[self _minimumFrameSize]];
if ([self ephemeralSubviewNamed:@"content-view"])
[self layoutSubviews];
}
@@ -719,7 +782,9 @@ var CPButtonImageKey = @"CPButtonImageKey",
CPButtonImageDimsWhenDisabledKey = @"CPButtonImageDimsWhenDisabledKey",
CPButtonImagePositionKey = @"CPButtonImagePositionKey",
CPButtonKeyEquivalentKey = @"CPButtonKeyEquivalentKey",
CPButtonKeyEquivalentMaskKey = @"CPButtonKeyEquivalentMaskKey";
CPButtonKeyEquivalentMaskKey = @"CPButtonKeyEquivalentMaskKey",
CPButtonPeriodicDelayKey = @"CPButtonPeriodicDelayKey",
CPButtonPeriodicIntervalKey = @"CPButtonPeriodicIntervalKey";
@implementation CPButton (CPCoding)
@@ -733,7 +798,7 @@ var CPButtonImageKey = @"CPButtonImageKey",
if (self)
{
_controlSize = CPRegularControlSize;
[self _init];
_title = [aCoder decodeObjectForKey:CPButtonTitleKey];
_alternateTitle = [aCoder decodeObjectForKey:CPButtonAlternateTitleKey];
@@ -749,6 +814,12 @@ var CPButtonImageKey = @"CPButtonImageKey",
if ([aCoder containsValueForKey:CPButtonKeyEquivalentKey])
[self setKeyEquivalent:CFData.decodeBase64ToUtf16String([aCoder decodeObjectForKey:CPButtonKeyEquivalentKey])];
if ([aCoder containsValueForKey:CPButtonPeriodicDelayKey])
_periodicDelay = [aCoder decodeObjectForKey:CPButtonPeriodicDelayKey];
if ([aCoder containsValueForKey:CPButtonPeriodicIntervalKey])
_periodicInterval = [aCoder decodeObjectForKey:CPButtonPeriodicIntervalKey];
_keyEquivalentModifierMask = [aCoder decodeIntForKey:CPButtonKeyEquivalentMaskKey];
[self setNeedsLayout];
@@ -765,6 +836,7 @@ var CPButtonImageKey = @"CPButtonImageKey",
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[self invalidateTimers];
[aCoder encodeObject:_title forKey:CPButtonTitleKey];
[aCoder encodeObject:_alternateTitle forKey:CPButtonAlternateTitleKey];
@@ -778,6 +850,9 @@ var CPButtonImageKey = @"CPButtonImageKey",
[aCoder encodeObject:CFData.encodeBase64Utf16String(_keyEquivalent) forKey:CPButtonKeyEquivalentKey];
[aCoder encodeInt:_keyEquivalentModifierMask forKey:CPButtonKeyEquivalentMaskKey];
[aCoder encodeObject:_periodicDelay forKey:CPButtonPeriodicDelayKey];
[aCoder encodeObject:_periodicInterval forKey:CPButtonPeriodicIntervalKey];
}
@end
+83 -5
View File
@@ -131,6 +131,49 @@
/*!
Sets the item prototype to \c anItem
The item prototype should implement the CPCoding protocol
because the item is copied by archiving and unarchiving the
prototypal view.
Example:
<pre>
@implement MyCustomView : CPCollectionViewItem
{
CPArray items @accessors;
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
items = [];
}
return self;
}
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
items = [aCoder decodeObjectForKey:@"KEY"];
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[aCoder encodeObject:items forKey:@"KEY"];
[super encodeWithCoder:aCoder];
}
@end
</pre>
This will allow the collection view to create multiple 'clean' copies
of the item prototype which will maintain the original values for item
and all of the properties archived by the super class.
@param anItem the new item prototype
*/
- (void)setItemPrototype:(CPCollectionViewItem)anItem
@@ -343,7 +386,7 @@
_items = [];
if (!_itemPrototype || !_content)
if (!_itemPrototype)
return;
var index = 0;
@@ -369,7 +412,7 @@
{
var width = CGRectGetWidth([self bounds]);
if (![_content count] || width == _tileWidth)
if (width == _tileWidth)
return;
// We try to fit as many views per row as possible. Any remaining space is then
@@ -589,9 +632,7 @@
_mouseDownEvent = anEvent;
var location = [self convertPoint:[anEvent locationInWindow] fromView:nil],
row = FLOOR(location.y / (_itemSize.height + _verticalMargin)),
column = FLOOR(location.x / (_itemSize.width + _horizontalMargin)),
index = row * _numberOfColumns + column;
index = [self _indexAtPoint:location];
if (index >= 0 && index < _items.length)
{
@@ -727,6 +768,28 @@
return _delegate;
}
/*!
@ignore
*/
- (CPMenu)menuForEvent:(CPEvent)theEvent
{
if (![[self delegate] respondsToSelector:@selector(collectionView:menuForItemAtIndex:)])
return [super menuForEvent:theEvent];
var location = [self convertPoint:[theEvent locationInWindow] fromView:nil],
index = [self _indexAtPoint:location];
return [_delegate collectionView:self menuForItemAtIndex:index];
}
- (int)_indexAtPoint:(CGPoint)thePoint
{
var row = FLOOR(thePoint.y / (_itemSize.height + _verticalMargin)),
column = FLOOR(thePoint.x / (_itemSize.width + _horizontalMargin));
return row * _numberOfColumns + column;
}
- (CPCollectionViewItem)itemAtIndex:(unsigned)anIndex
{
return [_items objectAtIndex:anIndex];
@@ -898,6 +961,21 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeK
@implementation CPCollectionView (CPCoding)
- (void)awakeFromCib
{
[super awakeFromCib];
if (CGSizeEqualToSize(_minItemSize, CGSizeMakeZero()) || CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero()))
{
var item = _itemPrototype;
if (CGSizeEqualToSize(_minItemSize, CGSizeMakeZero()))
_minItemSize = [[item view] frameSize];
else if (CGSizeEqualToSize(_maxItemSize, CGSizeMakeZero()))
_maxItemSize = [[item view] frameSize];
}
}
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
+15 -3
View File
@@ -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:)];
+16 -12
View File
@@ -44,16 +44,16 @@ 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;
@@ -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)
+12 -31
View File
@@ -25,7 +25,6 @@
@import "CPView.j"
@import "CPKeyValueBinding.j"
CPLeftTextAlignment = 0;
CPRightTextAlignment = 1;
CPCenterTextAlignment = 2;
@@ -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],
@@ -227,34 +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.
*/
+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
+16 -12
View File
@@ -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];
}
}
}
+18 -12
View File
@@ -281,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;
@@ -309,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;
@@ -333,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;
+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;
};
+1 -1
View File
@@ -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
+51 -13
View File
@@ -195,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"];
@@ -337,6 +337,25 @@ var _CPMenuBarVisible = NO,
[self removeObjectFromItemsAtIndex:anIndex];
}
/*!
Removes all the menu items in the receiver.
This method is more efficient than removing menu items individually.
Unlike the other remove methods, this method does not post CPMenuDidChangeItemNotification notifications.
*/
- (void)removeAllItems
{
var count = [_items count];
// Remove the connection to this menu in case
// someone else has a reference to the menu item.
while (count--)
[_items[count] setMenu:nil];
_items = [CPMutableArray array];
_highlightedIndex = CPNotFound;
}
/*!
Called when a menu item has visually changed.
@param aMenuItem the item that changed
@@ -536,7 +555,6 @@ var _CPMenuBarVisible = NO,
*/
- (void)submenuAction:(id)aSender
{
}
/*!
@@ -584,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
@@ -851,7 +892,7 @@ var _CPMenuBarVisible = NO,
// Handling Tracking
/*!
Cancels tracking.
Cancels tracking.
*/
- (void)cancelTracking
{
@@ -911,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];
@@ -948,14 +989,6 @@ var _CPMenuBarVisible = NO,
}
//
/*
@ignore
*/
- (BOOL)_itemIsHighlighted:(CPMenuItem)aMenuItem
{
return _items[_highlightedIndex] == aMenuItem;
}
/*
@ignore
*/
@@ -971,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
@@ -1097,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];
+40 -6
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
@@ -133,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];
}
@@ -599,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
{
@@ -851,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",
+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 -17
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 = [];
@@ -42,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;
@@ -72,12 +72,12 @@ var _CPMenuItemSelectionColor = nil,
_menuItem = aMenuItem;
_showsStateColumn = YES;
_isDirty = YES;
[self setAutoresizingMask:CPViewWidthSizable];
[self synchronizeWithMenuItem];
}
return self;
}
@@ -111,7 +111,7 @@ var _CPMenuItemSelectionColor = nil,
_view = menuItemView;
}
}
else if ([_menuItem menu] == [CPApp mainMenu])
{
if (![_view isKindOfClass:[_CPMenuItemMenuBarView class]])
@@ -129,7 +129,7 @@ var _CPMenuItemSelectionColor = nil,
[_view removeFromSuperview];
_view = [_CPMenuItemStandardView view];
}
[_view setMenuItem:_menuItem];
}
@@ -160,7 +160,7 @@ var _CPMenuItemSelectionColor = nil,
{
if (![_menuItem hasSubmenu])
return NO;
return CGRectContainsPoint([_submenuView frame], [self convertPoint:[anEvent locationInWindow] fromView:nil]);
}
@@ -191,7 +191,7 @@ var _CPMenuItemSelectionColor = nil,
{
if (_textColor == aColor)
return;
_textColor = aColor;
[_imageAndTextView setTextColor:[self textColor]];
@@ -207,7 +207,7 @@ var _CPMenuItemSelectionColor = nil,
{
if (_textShadowColor == aColor)
return;
_textShadowColor = aColor;
[_imageAndTextView setTextShadowColor:[self textShadowColor]];
@@ -232,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);
}
+43 -2
View File
@@ -1,3 +1,24 @@
/*
* CPObjectController.j
* AppKit
*
* Created by Ross Boucher.
* Copyright 2009, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPDictionary.j>
@import <Foundation/CPCountedSet.j>
@@ -372,6 +393,12 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
[aCoder encodeBool:[self automaticallyPreparesContent] forKey:CPObjectControllerAutomaticallyPreparesContentKey];
}
- (void)awakeFromCib
{
if (![self content] && [self automaticallyPreparesContent])
[self prepareContent];
}
@end
@implementation _CPObservationProxy : CPObject
@@ -471,7 +498,7 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
- (CPString)description
{
return "<_CPObservableArray: "+[super description]+" >";
return "<_CPObservableArray: " + [super description] + " >";
}
- (id)initWithArray:(CPArray)anArray
@@ -636,7 +663,7 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
- (id)_controllerMarkerForValues:(CPArray)theValues
{
var count = [theValues count];
var count = [theValues count];
if (!count)
value = CPNoSelectionMarker;
@@ -658,6 +685,9 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
}
}
if (value === nil || value.isa && [value isEqual:[CPNull null]])
value = CPNullMarker;
return value;
}
@@ -680,6 +710,17 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
{
[[_controller selectedObjects] setValue:theValue forKeyPath:theKeyPath];
[_cachedValues removeObjectForKey:theKeyPath];
// Allow handlesContentAsCompoundValue to work, based on observation of Cocoa's
// NSArrayController - when handlesContentAsCompoundValue and setValue:forKey:@"selection.X"
// is called, the array controller causes the compound value to be rewritten if
// handlesContentAsCompoundValue == YES. Note that
// A) this doesn't use observation (observe: X is not visible in backtraces)
// B) it only happens through the selection proxy and not on arrangedObject.X, content.X
// or even selectedObjects.X.
// FIXME The main code for this should somehow be in CPArrayController and also work
// for table based row edits.
[[CPBinder getBinding:@"contentArray" forObject:_controller] _contentArrayDidChange];
}
- (void)setValue:(id)theValue forKey:(CPString)theKeyPath
+21
View File
@@ -1,3 +1,24 @@
/*
* CPOpenPanel.j
* AppKit
*
* Created by Ross Boucher.
* Copyright 2009, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPPanel.j"
+148 -109
View File
@@ -71,7 +71,8 @@ var CPOutlineViewDelegate_outlineView_dataViewForTableColumn_item_
CPOutlineViewDelegate_outlineView_typeSelectStringForTableColumn_item_ = 1 << 21,
CPOutlineViewDelegate_outlineView_willDisplayOutlineView_forTableColumn_item_ = 1 << 22,
CPOutlineViewDelegate_outlineView_willDisplayView_forTableColumn_item_ = 1 << 23,
CPOutlineViewDelegate_selectionShouldChangeInOutlineView_ = 1 << 24;
CPOutlineViewDelegate_selectionShouldChangeInOutlineView_ = 1 << 24,
CPOutlineViewDelegate_outlineView_menuForTableColumn_item_ = 1 << 25;
CPOutlineViewDropOnItemIndex = -1;
@@ -160,55 +161,55 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
return self;
}
/*!
<pre>
In addition to standard delegation, the outline view also supports data
source delegation. This method sets the data source object. Just like the
TableView you have CPTableColumns but instead of rows you deal with items.
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 table header. You should sort the datasource based off of the new sort descriptors and reload the data
Return the drag operation (move, copy, etc) that should be performed if a registered drag type is over the tableview
The data source can retarget a drop if you want by calling <pre>-(void)setDropItem:(id)anItem dropChildIndex:(int)anIndex;</pre>
@code - (CPDragOperation)outlineView:(CPOutlineView)outlineView validateDrop:(id < CPDraggingInfo >)info proposedItem:(id)item proposedChildIndex:(CPInteger)index; @endcode
Drag and Drop:
In order for the outlineview to receive drops don't 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 performed 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 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.
</pre>
Returns YES if the drop operation is allowed otherwise NO.
This method is invoked by the outlineview after a drag should begin, but before it is started. If you don't want the drag to being return NO.
If you want the drag to begin you should return YES and place the drag data on the pboard.
@code - (BOOL)outlineView:(CPOutlineView)outlineView writeItems:(CPArray)items toPasteboard:(CPPasteboard)pboard; @endcode
*/
- (void)setDataSource:(id)aDataSource
{
@@ -713,74 +714,80 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
}
/*!
<pre>
Sets the delegate for the outlineview.
The following methods can be implemented:
User Interaction Notifications:
- (void)outlineViewColumnDidMove:(CPNotification)notification;
Called when the user moves a column in the outlineview.
- (void)outlineViewColumnDidResize:(CPNotification)notification;
Called when the user resizes a column in the outlineview.
- (void)outlineViewItemDidCollapse:(CPNotification)notification;
Called when the user collapses an item in the outlineview.
- (void)outlineViewItemDidExpand:(CPNotification)notification;
Called when the user expands an item in the outlineview.
- (void)outlineViewItemWillCollapse:(CPNotification)notification;
Called when the user collapses an item in the outlineview, but before the item is actually collapsed.
- (void)outlineViewItemWillExpand:(CPNotification)notification;
Called when the used expands an item, but before the item is actually expanded.
- (void)outlineViewSelectionDidChange:(CPNotification)notification;
Called when the user changes the selection of the outlineview.
- (void)outlineViewSelectionIsChanging:(CPNotification)notification
Called when the user changes the selection of the outlineview, but before the change is made.
Expanding and collapsing items:
- (BOOL)outlineView:(CPOutlineView)outlineView shouldExpandItem:(id)item;
Return YES if the item should be given permission to expand, otherwise NO.
- (BOOL)outlineView:(CPOutlineView)outlineView shouldCollapseItem:(id)item;
Return YES if the item should be given permission to collapse, otherwise NO.
Selection:
- (BOOL)outlineView:(CPOutlineView)outlineView shouldSelectTableColumn:(CPTableColumn)tableColumn;
Return YES to allow the selection of tableColumn, otherwise NO.
- (BOOL)outlineView:(CPOutlineView)outlineView shouldSelectItem:(id)item;
Return YES to allow the selection of an item, otherwise NO.
- (BOOL)selectionShouldChangeInOutlineView:(CPOutlineView)outlineView;
Return YES to allow the selection of the outlineview to be changed, otherwise NO.
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.
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.
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.
Variable Item Heights
- (int)outlineView:(CPOutlineView)outlineView heightOfRowByItem:(id)anItem;
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:
@param aDelegate - the delegate object you wish to set for the receiver.
<pre>
@section notifications User Interaction Notifications:
Called when the user moves a column in the outlineview.
@code - (void)outlineViewColumnDidMove:(CPNotification)notification; @endcode
Called when the user resizes a column in the outlineview.
@code - (void)outlineViewColumnDidResize:(CPNotification)notification; @endcode
Called when the user collapses an item in the outlineview.
@code - (void)outlineViewItemDidCollapse:(CPNotification)notification; @endcode
Called when the user expands an item in the outlineview.
@code - (void)outlineViewItemDidExpand:(CPNotification)notification; @endcode
Called when the user collapses an item in the outlineview, but before the item is actually collapsed.
@code - (void)outlineViewItemWillCollapse:(CPNotification)notification; @endcode
Called when the used expands an item, but before the item is actually expanded.
@code - (void)outlineViewItemWillExpand:(CPNotification)notification; @endcode
Called when the user changes the selection of the outlineview.
@code - (void)outlineViewSelectionDidChange:(CPNotification)notification; @endcode
Called when the user changes the selection of the outlineview, but before the change is made.
@code - (void)outlineViewSelectionIsChanging:(CPNotification)notification; @endcode
@section expandingandcollapsing Expanding and collapsing items:
Return YES if the item should be given permission to expand, otherwise NO.
@code - (BOOL)outlineView:(CPOutlineView)outlineView shouldExpandItem:(id)item; @endcode
Return YES if the item should be given permission to collapse, otherwise NO.
@code - (BOOL)outlineView:(CPOutlineView)outlineView shouldCollapseItem:(id)item; @endcode
@section selection Selection:
Return YES to allow the selection of tableColumn, otherwise NO.
@code- (BOOL)outlineView:(CPOutlineView)outlineView shouldSelectTableColumn:(CPTableColumn)tableColumn; @endcode
Return YES to allow the selection of an item, otherwise NO.
@code- (BOOL)outlineView:(CPOutlineView)outlineView shouldSelectItem:(id)item; @endcode
Return YES to allow the selection of the outlineview to be changed, otherwise NO.
@code - (BOOL)selectionShouldChangeInOutlineView:(CPOutlineView)outlineView; @endcode
@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
*/
- (void)setDelegate:(id)aDelegate
{
@@ -872,7 +879,8 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
CPOutlineViewDelegate_outlineView_typeSelectStringForTableColumn_item_ , @selector(outlineView:typeSelectStringForTableColumn:item:),
CPOutlineViewDelegate_outlineView_willDisplayOutlineView_forTableColumn_item_ , @selector(outlineView:willDisplayOutlineView:forTableColumn:item:),
CPOutlineViewDelegate_outlineView_willDisplayView_forTableColumn_item_ , @selector(outlineView:willDisplayView:forTableColumn:item:),
CPOutlineViewDelegate_selectionShouldChangeInOutlineView_ , @selector(selectionShouldChangeInOutlineView:)
CPOutlineViewDelegate_selectionShouldChangeInOutlineView_ , @selector(selectionShouldChangeInOutlineView:),
CPOutlineViewDelegate_outlineView_menuForTableColumn_item_ , @selector(outlineView:menuForTableColumn:item:)
],
delegateCount = [delegateMethods count];
@@ -944,6 +952,17 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
}
- (BOOL)_sendDelegateDeleteKeyPressed
{
if ([[self delegate] respondsToSelector: @selector(outlineViewDeleteKeyPressed:)])
{
[[self delegate] outlineViewDeleteKeyPressed:self];
return YES;
}
return NO;
}
/*!
Returns the delegate object for the outlineview.
*/
@@ -983,7 +1002,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
Also see -setOutlineTableColumn:.
NOTE: This behavior deviates from cocoa slightly.
@note This behavior deviates from cocoa slightly.
@param CPTableColumn aTableColumn - The table column to add.
*/
@@ -1622,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];
}
@@ -1704,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
@@ -1777,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
+9 -15
View File
@@ -86,10 +86,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
[self setPullsDown:shouldPullDown];
var options = CPKeyValueObservingOptionNew |
CPKeyValueObservingOptionOld;/* |
CPKeyValueObservingOptionInitial;
*/
var options = CPKeyValueObservingOptionNew |CPKeyValueObservingOptionOld;/* |CPKeyValueObservingOptionInitial;*/
[self addObserver:self forKeyPath:@"menu.items" options:options context:nil];
[self addObserver:self forKeyPath:@"_firstItem.changeCount" options:options context:nil];
[self addObserver:self forKeyPath:@"selectedItem.changeCount" options:options context:nil];
@@ -195,11 +192,7 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (void)removeAllItems
{
var menu = [self menu],
count = [menu numberOfItems];
while (count--)
[menu removeItemAtIndex:0];
[[self menu] removeAllItems];
}
/*!
@@ -402,9 +395,13 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (CPMenuItem)itemWithTitle:(CPString)aTitle
{
var menu = [self menu];
var menu = [self menu],
itemIndex = [menu indexOfItemWithTitle:aTitle];
return [menu itemAtIndex:[menu indexOfItemWithTitle:aTitle]];
if (itemIndex === CPNotFound)
return nil;
return [menu itemAtIndex:itemIndex];
}
/*!
@@ -810,10 +807,7 @@ var DEPRECATED_CPPopUpButtonMenuKey = @"CPPopUpButtonMenuKey",
[self setObjectValue:[aCoder decodeObjectForKey:DEPRECATED_CPPopUpButtonSelectedIndexKey]];
}
var options = CPKeyValueObservingOptionNew |
CPKeyValueObservingOptionOld;/* |
CPKeyValueObservingOptionInitial;
*/
var options = CPKeyValueObservingOptionNew | CPKeyValueObservingOptionOld;/* | CPKeyValueObservingOptionInitial */
[self addObserver:self forKeyPath:@"menu.items" options:options context:nil];
[self addObserver:self forKeyPath:@"_firstItem.changeCount" options:options context:nil];
+38
View File
@@ -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
+12 -5
View File
@@ -231,11 +231,18 @@ CPDeleteForwardKeyCode = 46;
[_nextResponder performSelector:_cmd withObject:anEvent];
}
/*
FIXME This description is bad.
Based on \c anEvent, the receiver should simulate the event.
@param anEvent the event to simulate
@return \c YES if the event receiver simulated the event
/*!
Overridden by subclasses to handle a key equivalent.
If the character code or codes in \c anEvent match the receivers key equivalent,
the receiver should respond to the event and return \c YES. The default implementation
does nothing and returns \c NO.
You should extract the characters for a key equivalent using
\ref CPEvent::charactersIgnoringModifiers "[anEvent charactersIgnoringModifiers]".
@param anEvent An event object that represents the key equivalent pressed
@return \c YES if theEvent is a key equivalent that the receiver handled, \c NO if it is not a key equivalent that it should handle.
*/
- (BOOL)performKeyEquivalent:(CPEvent)anEvent
{
+504
View File
@@ -0,0 +1,504 @@
/*
* CPPredicateEditor.j
* AppKit
*
* Created by cacaodev.
* Copyright 2011, cacaodev.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPRuleEditor.j"
@import "_CPPredicateEditorTree.j"
@import "_CPPredicateEditorRowNode.j"
@import "CPPredicateEditorRowTemplate.j"
@implementation CPPredicateEditor : CPRuleEditor
{
CPArray _allTemplates;
CPArray _rootTrees;
CPArray _rootHeaderTrees;
id _predicateTarget @accessors(property=target);
SEL _predicateAction @accessors(property=action);
}
#pragma mark public methods
/*!
@ingroup appkit
@class CPPredicateEditor
@brief CPPredicateEditor is a subclass of CPRuleEditor that is specialized for editing CPPredicate objects.
CPPredicateEditor provides a CPPredicate property—objectValue (inherited from CPControl)—that you can get and set directly, and that you can bind using bindings (you typically configure a predicate editor in Interface Builder). CPPredicateEditor depends on another class, CPPredicateEditorRowTemplate, that describes the available predicates and how to display them.
Unlike CPRuleEditor, CPPredicateEditor does not depend on its delegate to populate its rows (and does not call the populating delegate methods). Instead, its rows are populated from its objectValue property (an instance of CPPredicate). CPPredicateEditor relies on instances CPPredicateEditorRowTemplate, which are responsible for mapping back and forth between the displayed view values and various predicates.
CPPredicateEditor exposes one property, rowTemplates, which is an array of CPPredicateEditorRowTemplate objects.
*/
/*!
@brief Returns the row templates for the receiver.
@return The row templates for the receiver.
@discussion Until otherwise set, this contains a single compound CPPredicateEditorRowTemplate object.
@see setRowTemplates:
*/
- (CPArray)rowTemplates
{
return _allTemplates;
}
/*!
@brief Sets the row templates for the receiver.
@param rowTemplates An array of CPPredicateEditorRowTemplate objects.
@see rowTemplates
*/
- (void)setRowTemplates:(id)rowTemplates
{
if (_allTemplates == rowTemplates)
return;
_allTemplates = rowTemplates;
[self _updateItemsByCompoundTemplates];
[self _updateItemsBySimpleTemplates];
if ([self numberOfRows] > 0)
{
var predicate = [super predicate];
[self _reflectPredicate:predicate];
}
}
/*! @cond */
- (void)_initRuleEditorShared
{
[super _initRuleEditorShared];
_rootTrees = [CPArray array];
_rootHeaderTrees = [CPArray array];
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self != nil)
{
var initialTemplate = [[CPPredicateEditorRowTemplate alloc] initWithCompoundTypes:[CPAndPredicateType, CPOrPredicateType]];
_allTemplates = [CPArray arrayWithObject:initialTemplate];
}
return self;
}
- (id)objectValue
{
return [super predicate];
}
- (void)_updateItemsBySimpleTemplates
{
var templates = [CPMutableArray array],
count = [_allTemplates count],
t;
while (count--)
{
var t = _allTemplates[count];
if ([t _rowType] == CPRuleEditorRowTypeSimple)
[templates insertObject:t atIndex:0];
}
var trees = [self _constructTreesForTemplates:templates];
if ([trees count] > 0)
_rootTrees = [self _mergeTree:trees];
}
- (void)_updateItemsByCompoundTemplates
{
var templates = [CPMutableArray array],
count = [_allTemplates count],
t;
while (count--)
{
var t = _allTemplates[count];
if ([t _rowType] == CPRuleEditorRowTypeCompound)
[templates insertObject:t atIndex:0];
}
var trees = [self _constructTreesForTemplates:templates];
if ([trees count] > 0)
_rootHeaderTrees = [self _mergeTree:trees];
}
- (CPArray)_constructTreesForTemplates:(id)templates
{
var trees = [CPMutableArray array],
count = [templates count];
for (var i = 0; i < count; i++)
{
var tree = [self _constructTreeForTemplate:templates[i]];
[trees addObjectsFromArray:tree];
}
return trees;
}
- (id)_mergeTree:(id)tree
{
var merged = [CPMutableArray array],
titles = [CPMutableArray array],
count = [tree count];
for (var i = 0; i < count; i++)
{
var t = tree[i],
title = [CPString stringWithString:[t title]];
if ([titles containsObject:title])
{
CPLogConsole("CPPredicateEditor does not support templates merging yet. Ignoring duplicate template: " + [t description]);
continue;
}
[merged addObject:t];
[titles addObject:title];
}
return merged;
}
- (id)_constructTreeForTemplate:(CPPredicateEditorRowTemplate)aTemplate
{
var tree = [CPArray array],
templateViews = [aTemplate templateViews],
count = [templateViews count];
while (count--)
{
var children = [CPArray array],
itemsCount = 0,
menuIndex = -1,
itemsArray,
templateView = [templateViews objectAtIndex:count],
isPopup = [templateView isKindOfClass:[CPPopUpButton class]];
if (isPopup)
{
itemArray = [[templateView itemArray] valueForKey:@"title"];
itemsCount = [itemArray count],
menuIndex = 0;
}
for (; menuIndex < itemsCount; menuIndex++)
{
var item = [_CPPredicateEditorTree new];
[item setIndexIntoTemplate:count];
[item setTemplate:aTemplate];
[item setMenuItemIndex:menuIndex];
if (isPopup)
[item setTitle:[itemArray objectAtIndex:menuIndex]];
[children addObject:item];
}
[children makeObjectsPerformSelector:@selector(setChildren:) withObject:tree];
tree = children;
}
return tree;
}
#pragma mark Set the Predicate
- (void)setObjectValue:(id)objectValue
{
if (![[objectValue predicateFormat] isEqualToString:[[super predicate] predicateFormat]]) // ??
[self _reflectPredicate:objectValue];
}
- (void)_reflectPredicate:(id)predicate
{
var animation = _currentAnimation;
_currentAnimation = nil;
if (predicate != nil)
{
if ((_nestingMode == CPRuleEditorNestingModeSimple || _nestingMode == CPRuleEditorNestingModeCompound)
&& [predicate isKindOfClass:[CPComparisonPredicate class]])
predicate = [[CPCompoundPredicate alloc] initWithType:[self _compoundPredicateTypeForRootRows] subpredicates:[CPArray arrayWithObject:predicate]];
var row = [self _rowObjectFromPredicate:predicate];
if (row != nil)
[_boundArrayOwner setValue:[CPArray arrayWithObject:row] forKey:_boundArrayKeyPath];
}
[self setAnimation:animation];
}
- (id)_rowObjectFromPredicate:(CPPredicate)predicate
{
var quality, // TODO: We should use this ref somewhere !
type,
matchedTemplate = [CPPredicateEditorRowTemplate _bestMatchForPredicate:predicate inTemplates:[self rowTemplates] quality:quality];
if (matchedTemplate == nil)
return nil;
var copyTemplate = [matchedTemplate copy],
subpredicates = [matchedTemplate displayableSubpredicatesOfPredicate:predicate];
if (subpredicates == nil)
{
[copyTemplate _setComparisonPredicate:predicate];
type = CPRuleEditorRowTypeSimple;
}
else
{
[copyTemplate _setCompoundPredicate:predicate];
type = CPRuleEditorRowTypeCompound;
}
var row = [self _rowFromTemplate:copyTemplate originalTemplate:matchedTemplate withRowType:type];
if (subpredicates == nil)
return row;
var count = [subpredicates count],
subrows = [CPMutableArray array];
for (var i = 0; i < count; i++)
{
var subrow = [self _rowObjectFromPredicate:subpredicates[i]];
if (subrow != nil)
[subrows addObject:subrow];
}
[row setValue:subrows forKey:[super subrowsKeyPath]];
return row;
}
- (id)_rowFromTemplate:(CPPredicateEditorRowTemplate)aTemplate originalTemplate:(CPPredicateEditorRowTemplate)originalTemplate withRowType:(CPRuleEditorRowType)rowType
{
var criteria = [CPArray array],
values = [CPArray array],
templateViews = [aTemplate templateViews],
rootItems,
count;
rootItems = (rowType == CPRuleEditorRowTypeSimple) ? _rootTrees : _rootHeaderTrees;
while ((count = [rootItems count]) > 0)
{
var treeChild;
for (var i = 0; i < count; i++)
{
treeChild = [rootItems objectAtIndex:i];
var currentView = [templateViews objectAtIndex:[treeChild indexIntoTemplate]],
menuItemIndex = [treeChild menuItemIndex];
if (menuItemIndex == -1 || [[treeChild title] isEqual:[currentView titleOfSelectedItem]])
{
var node = [_CPPredicateEditorRowNode rowNodeFromTree:treeChild];
[node applyTemplate:aTemplate withViews:templateViews forOriginalTemplate:originalTemplate];
[criteria addObject:node];
[values addObject:[node displayValue]];
break;
}
}
rootItems = [treeChild children];
}
var row = [CPDictionary dictionaryWithObjectsAndKeys:criteria, @"criteria", values, @"displayValues", rowType, @"rowType"];
return row;
}
#pragma mark Get the predicate
- (void)_updatePredicate
{
[self willChangeValueForKey:@"objectValue"];
[self _updatePredicateFromRows];
[self didChangeValueForKey:@"objectValue"];
}
- (void)_updatePredicateFromRows
{
var rootRowsArray = [super _rootRowsArray],
subpredicates = [CPMutableArray array],
count = count2 = [rootRowsArray count],
predicate;
while (count--)
{
var item = [rootRowsArray objectAtIndex:count],
subpredicate = [self _predicateFromRowItem:item];
if (subpredicate != nil)
[subpredicates insertObject:subpredicate atIndex:0];
}
if (_nestingMode != CPRuleEditorNestingModeList && count2 == 1)
predicate = [subpredicates lastObject];
else
predicate = [[CPCompoundPredicate alloc] initWithType:[self _compoundPredicateTypeForRootRows] subpredicates:subpredicates];
[super _setPredicate:predicate];
}
- (id)_predicateFromRowItem:(id)rowItem
{
var subpredicates = [CPArray array],
rowType = [rowItem valueForKey:_typeKeyPath];
if (rowType == CPRuleEditorRowTypeCompound)
{
var subrows = [rowItem valueForKey:_subrowsArrayKeyPath],
count = [subrows count];
for (var i = 0; i < count; i++)
{
var subrow = [subrows objectAtIndex:i];
var predicate = [self _predicateFromRowItem:subrow];
[subpredicates addObject:predicate];
}
}
var criteria = [rowItem valueForKey:_itemsKeyPath],
displayValues = [rowItem valueForKey:_valuesKeyPath],
count = [criteria count],
lastItem = [criteria lastObject],
template = [lastItem templateForRow],
templateViews = [template templateViews];
for (var j = 0; j < count; j++)
{
var view = [templateViews objectAtIndex:j],
value = [displayValues objectAtIndex:j];
[[criteria objectAtIndex:j] setTemplateViews:templateViews];
if ([view isKindOfClass:[CPPopUpButton class]])
[view selectItemWithTitle:value];
else if ([view respondsToSelector:@selector(setObjectValue:)])
[view setObjectValue:[value objectValue]];
}
return [template predicateWithSubpredicates:subpredicates];
}
- (CPCompoundPredicateType)_compoundPredicateTypeForRootRows
{
return CPAndPredicateType;
}
#pragma mark Control delegate
- (void)_sendRuleAction
{
[self _updatePredicate];
[super _sendRuleAction];
}
- (BOOL)_sendsActionOnIncompleteTextChange
{
return NO;
}
/*
- (void)_setDefaultTargetAndActionOnView:(CPView)view
{
if ([view isKindOfClass:[CPControl class]])
{
[view setTarget:self];
[view setAction:@selector(_templateControlValueDidChange:)];
}
}
- (void)_templateControlValueDidChange:(id)sender
{
}
- (void)controlTextDidBeginEditing:(CPNotification)notification
{
}
- (void)controlTextDidEndEditing:(CPNotification)notification
{
}
- (void)controlTextDidChange:(CPNotification)notification
{
}
*/
#pragma mark RuleEditor delegate methods
- (int)_queryNumberOfChildrenOfItem:(id)rowItem withRowType:(int)type
{
if (rowItem == nil)
{
var trees = (type == CPRuleEditorRowTypeSimple) ? _rootTrees : _rootHeaderTrees;
return [trees count];
}
return [[rowItem children] count];
}
- (id)_queryChild:(int)childIndex ofItem:(id)rowItem withRowType:(int)type
{
if (rowItem == nil)
{
var trees = (type == CPRuleEditorRowTypeSimple) ? _rootTrees : _rootHeaderTrees;
return [_CPPredicateEditorRowNode rowNodeFromTree:trees[childIndex]];
}
return [[rowItem children] objectAtIndex:childIndex];
}
- (id)_queryValueForItem:(id)rowItem inRow:(int)rowIndex
{
return [rowItem displayValue];
}
@end
var CPPredicateTemplatesKey = @"CPPredicateTemplates";
@implementation CPPredicateEditor (CPCoding)
- (id)initWithCoder:(id)aCoder
{
self = [super initWithCoder:aCoder];
if (self != nil)
{
var nibTemplates = [aCoder decodeObjectForKey:CPPredicateTemplatesKey];
if (nibTemplates != nil)
[self setRowTemplates:nibTemplates];
}
return self;
}
- (void)encodeWithCoder:(id)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeObject:_allTemplates forKey:CPPredicateTemplatesKey];
}
@end
/*! @endcond */
@@ -0,0 +1,788 @@
/*
* CPPredicateEditorRowTemplate.j
* AppKit
*
* Created by cacaodev.
* Copyright 2011, cacaodev.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
CPUndefinedAttributeType = 0,
CPInteger16AttributeType = 100,
CPInteger32AttributeType = 200,
CPInteger64AttributeType = 300,
CPDecimalAttributeType = 400,
CPDoubleAttributeType = 500,
CPFloatAttributeType = 600,
CPStringAttributeType = 700,
CPBooleanAttributeType = 800,
CPDateAttributeType = 900,
CPBinaryDataAttributeType = 1000,
CPTransformableAttributeType = 1800;
@implementation CPPredicateEditorRowTemplate : CPObject
{
int _templateType @accessors(readwrite, getter=_templateType, setter=_setTemplateType:);
unsigned _predicateOptions @accessors(readwrite, setter=_setOptions:);
unsigned _predicateModifier @accessors(readwrite, setter=_setModifier:);
unsigned _leftAttributeType @accessors(readwrite, getter=leftAttributeType, setter=_setLeftAttributeType:);
unsigned _rightAttributeType @accessors(readwrite, getter=rightAttributeType, setter=_setRightAttributeType:);
BOOL _leftIsWildcard @accessors(property=leftIsWildcard);
BOOL _rightIsWildcard @accessors(property=rightIsWildcard);
CPArray _views @accessors(setter=setTemplateViews:);
}
/*!
@ingroup appkit
@class CPPredicateEditorRowTemplate
@brief CPPredicateEditorRowTemplate describes available predicates and how to display them.
You can create instances of CPPredicateEditorRowTemplate programmatically or in Interface Builder. By default, a non-compound row template has three views: a popup (or static text field) on the left, a popup or static text field for operators, and either a popup or other view on the right. You can subclass CPPredicateEditorRowTemplate to create a row template with different numbers or types of views.
CPPredicateEditorRowTemplate is a concrete class, but it has five primitive methods which are called by CPPredicateEditor: -#templateViews, -#matchForPredicate:, -#setPredicate:, -#displayableSubpredicatesOfPredicate:, and -#predicateWithSubpredicates:. CPPredicateEditorRowTemplate implements all of them, but you can override them for custom templates. The primitive methods are used by an instance of CPPredicateEditor as follows.
First, an instance of CPPredicateEditor is created, and some row templates are set on it—either through a nib file or programmatically. The first thing predicate editor does is ask each of the templates for their views, using templateViews.
After setting up the predicate editor, you typically send it a CPPredicateEditor#setObjectValue: message to restore a saved predicate. CPPredicateEditor needs to determine which of its templates should display each predicate in the predicate tree. It does this by sending each of its row templates a matchForPredicate: message and choosing the one that returns the highest value.
After finding the best match for a predicate, CPPredicateEditor copies that template to get fresh views, inserts them into the proper row, and then sets the predicate on the template using setPredicate:. Within that method, the CPPredicateEditorRowTemplate object must set its views' values to represent that predicate.
CPPredicateEditorRowTemplate next asks the template for the “displayable sub-predicates” of the predicate by sending a -#displayableSubpredicatesOfPredicate: message. If a template represents a predicate in its entirety, or if the predicate has no subpredicates, it can return nil for this. Otherwise, it should return a list of predicates to be made into sub-rows of that template's row. The whole process repeats for each sub-predicate.
At this point, the user sees the predicate that was saved. If the user then makes some changes to the views of the templates, this causes CPPredicateEditor to recompute its predicate by asking each of the templates to return the predicate represented by the new view values, passing in the subpredicates represented by the sub-rows (an empty array if there are none, or nil if they aren't supported by that predicate type).
*/
/*!
@name Initializing a Template
*/
/*!
@brief Initializes and returns a “pop-up-pop-up-pop-up”-style row template.
@param leftExpressions An array of CPExpression objects that represent the left hand side of a predicate.
@param rightExpressions An array of CPExpression objects that represent the right hand side of a predicate.
@param modifier A modifier for the predicate (see @c CPComparisonPredicateModifier for possible values).
@param operators An array of CPNumber objects specifying the operator type (see @c CPPredicateOperatorType for possible values).
@param options Options for the predicate (see @c CPComparisonPredicateOptions for possible values).
@return A row template of the “pop-up-pop-up-pop-up”-form, with the left and right popups representing the left and right expression arrays -#leftExpressions and -#rightExpressions, and the center popup representing the operators.
*/
- (id)initWithLeftExpressions:(CPArray)leftExpressions rightExpressions:(CPArray)rightExpressions modifier:(int)modifier operators:(CPArray)operators options:(int)options
{
self = [super init];
if (self != nil)
{
_templateType = 1;
_leftIsWildcard = NO;
_rightIsWildcard = NO;
_leftAttributeType = 0;
_rightAttributeType = 0;
_predicateModifier = modifier;
_predicateOptions = options;
var leftView = [self _viewFromExpressions:leftExpressions],
rightView = [self _viewFromExpressions:rightExpressions],
middleView = [self _viewFromOperatorTypes:operators];
_views = [[CPArray alloc] initWithObjects:leftView, middleView, rightView];
}
return self;
}
/*!
@brief Initializes and returns a “pop-up-pop-up-view”-style row template.
@param leftExpressions An array of CPExpression objects that represent the left hand side of a predicate.
@param attributeType An attribute type for the right hand side of a predicate. This value dictates the type of view created, and how the controls object value is coerced before putting it into a predicate.
@param modifier A modifier for the predicate (see @c CPComparisonPredicateModifier for possible values).
@param operators An array of CPNumber objects specifying the operator type (see @c CPPredicateOperatorType for possible values).
@param options Options for the predicate (see CPComparisonPredicateOptions for possible values).
@return A row template initialized using the given arguments.
*/
- (id)initWithLeftExpressions:(CPArray )leftExpressions rightExpressionAttributeType:(CPAttributeType)attributeType modifier:(CPComparisonPredicateModifier)modifier operators:(CPArray )operators options:(int)options
{
self = [super init];
if (self != nil)
{
var leftView = [self _viewFromExpressions:leftExpressions],
middleView = [self _viewFromOperatorTypes:operators],
rightView = [self _viewFromAttributeType:attributeType];
_templateType = 1;
_leftIsWildcard = NO;
_rightIsWildcard = YES;
_leftAttributeType = 0;
_rightAttributeType = attributeType;
_predicateModifier = modifier;
_predicateOptions = options;
_views = [[CPArray alloc] initWithObjects:leftView, middleView, rightView];
}
return self;
}
/*!
@brief Initializes and returns a row template suitable for displaying compound predicates.
@param compoundTypes An array of CPNumber objects specifying compound predicate types. See @c CPCompoundPredicateTypes for possible values.
@return A row template initialized for displaying compound predicates of the types specified by @a compoundTypes.
@discussion CPPredicateEditor contains such a template by default.
*/
- (id)initWithCompoundTypes:(CPArray )compoundTypes
{
self = [super init];
if (self != nil)
{
var leftView = [self _viewFromCompoundTypes:compoundTypes],
rightView = [[CPPopUpButton alloc] init];
[rightView addItemWithTitle:@"of the following are true"];
_templateType = 2;
_leftIsWildcard = NO;
_rightIsWildcard = NO;
_rightAttributeType = 0;
_views = [[CPArray alloc] initWithObjects:leftView, rightView];
}
return self;
}
/*!
@name Primitive Methods
*/
/*!
@brief Returns a positive number if the receiver can represent a given predicate, and 0 if it cannot.
@return A positive number if the template can represent predicate, and @c 0 if it cannot.
@discussion By default, returns values in the range @c 0 to @c 1.
The highest match among all the templates determines which template is responsible for displaying the predicate. You can override this to determine which predicates your custom template handles.
*/
- (double)matchForPredicate:(CPPredicate)predicate
{
// How exactly this value (float 0-1) is computed ?
if ([self _templateType] == 2 && [predicate isKindOfClass:[CPCompoundPredicate class]])
{
if ([[self compoundTypes] containsObject:[predicate compoundPredicateType]])
return 1;
}
else if ([self _templateType] == 1 && [predicate isKindOfClass:[CPComparisonPredicate class]])
{
if (!_leftIsWildcard && ![[self leftExpressions] containsObject:[predicate leftExpression]])
return 0;
if (![[self operators] containsObject:[predicate predicateOperatorType]])
return 0;
if (!_rightIsWildcard && ![[self rightExpressions] containsObject:[predicate rightExpression]]) return 0;
return 1;
}
return 0;
}
/*!
@brief Returns the views for the receiver.
@return The views for the receiver.
@discussion Instances of CPPopUpButton are treated specially by CPPredicateEditor; their menu items are merged into a single popup button, and matching menu item titles are combined. In this way, a single tree is built from the separate templates.
*/
- (CPArray)templateViews
{
return _views;
}
/*!
@brief Sets the value of the views according to the given predicate.
@param predicate The predicate value for the receiver.
@discussion This method is only called if -#matchForPredicate: returned a positive value for the receiver.
You can override this to set the values of custom views.
*/
- (void)setPredicate:(CPPredicate)predicate
{
if (_templateType == 2)
[self _setCompoundPredicate:predicate];
else
[self _setComparisonPredicate:predicate];
}
/*!
@brief Returns the subpredicates that should be made sub-rows of a given predicate.
@param predicate A predicate object.
@return The subpredicates that should be made sub-rows of @a predicate. For compound predicates (instances of CPCompoundPredicate), the array of subpredicates; for other types of predicate, returns @c nil. If a template represents a predicate in its entirety, or if the predicate has no subpredicates, returns @c nil.
@discussion You can override this method to create custom templates that handle complicated compound predicates.
*/
- (CPArray)displayableSubpredicatesOfPredicate:(CPPredicate)predicate
{
if ([predicate isKindOfClass:[CPCompoundPredicate class]])
{
var subpredicates = [predicate subpredicates];
if ([subpredicates count] == 0)
return nil;
return subpredicates;
}
return nil;
}
/*!
@brief Returns the predicate represented by the receivers views' values and the given sub-predicates.
@param subpredicates An array of predicates.
@return The predicate represented by the values of the template's views and the given @a subpredicates. You can override this method to return the predicate represented by your custom views.
@discussion This method is only called if -#matchForPredicate: returned a positive value for the receiver.
You can override this method to return the predicate represented by a custom view.
*/
- (CPPredicate)predicateWithSubpredicates:(CPArray)subpredicates
{
if (_templateType == 2)
{
var type = [[_views[0] selectedItem] representedObject];
return [[CPCompoundPredicate alloc] initWithType:type subpredicates:subpredicates];
}
if (_templateType == 1)
{
var lhs = [self _leftExpression],
rhs = [self _rightExpression],
operator = [[_views[1] selectedItem] representedObject];
return [CPComparisonPredicate predicateWithLeftExpression:lhs
rightExpression:rhs
modifier:[self modifier]
type:operator
options:[self options]];
}
return nil;
}
/*!
@name Information About a Row Template
*/
/*!
@brief Returns the left hand expressions for the receiver.
@return The left hand expressions for the receiver.
*/
- (CPArray)leftExpressions
{
if (_templateType ==1 && !_leftIsWildcard)
{
var view = [_views objectAtIndex:0];
return [[view itemArray] valueForKey:@"representedObject"];
}
return nil;
}
/*!
@brief Returns the right hand expressions for the receiver.
@return The right hand expressions for the receiver.
*/
- (CPArray)rightExpressions
{
if (_templateType == 1 && !_rightIsWildcard)
{
var view = [_views objectAtIndex:2];
return [[view itemArray] valueForKey:@"representedObject"];
}
return nil;
}
/*!
@brief Returns the compound predicate types for the receiver.
@return An array of CPNumber objects specifying compound predicate types. See @c CompoundPredicateTypes for possible values.
*/
- (CPArray)compoundTypes
{
if (_templateType == 2)
{
var view = [_views objectAtIndex:0];
return [[view itemArray] valueForKey:@"representedObject"];
}
return nil;
}
/*!
@brief Returns the comparison predicate modifier for the receiver.
@return The comparison predicate modifier for the receiver.
*/
- (CPComparisonPredicateModifier)modifier
{
if (_templateType == 1)
return _predicateModifier;
return nil;
}
/*!
@brief Returns Returns the array of operators for the receiver.
@return The array of operators for the receiver.
*/
- (CPArray)operators
{
if (_templateType == 1)
{
var view = [_views objectAtIndex:1];
return [[view itemArray] valueForKey:@"representedObject"];
}
return nil;
}
/*!
@brief Returns the comparison predicate options for the receiver.
@return The comparison predicate options for the receiver. See @c CPComparisonPredicateOptions for possible values. Returns @c 0 if this does not apply (for example, for a compound template initialized with -#initWithCompoundTypes:).
*/
- (int)options
{
if (_templateType == 1)
return _predicateOptions;
return nil;
}
/*!
@brief Returns the attribute type of the receivers right expression.
@return The attribute type of the receivers right expression.
*/
- (CPAttributeType)rightExpressionAttributeType
{
return _rightAttributeType;
}
/*!
@brief Returns the attribute type of the receivers left expression.
@return The attribute type of the receivers left expression.
*/
- (CPAttributeType)leftExpressionAttributeType
{
return _leftAttributeType;
}
/*! @cond */
+ (id)_bestMatchForPredicate:(CPPredicate)predicate inTemplates:(CPArray)templates quality:(double)quality
{
var count = [templates count],
match_value = 0,
templateIndex = CPNotFound,
i;
for (i = 0; i < count; i++)
{
var template = [templates objectAtIndex:i],
amatch = [template matchForPredicate:predicate];
if (amatch > match_value)
{
templateIndex = i;
match_value = amatch;
}
}
if (templateIndex == CPNotFound)
{
[CPException raise:CPRangeException reason:@"Unable to find template matching predicate: " + [predicate predicateFormat]];
return nil;
}
return [templates objectAtIndex:templateIndex];
}
- (void)_setCompoundPredicate:(CPCompoundPredicate)predicate
{
var left = [_views objectAtIndex:0],
type = [predicate compoundPredicateType],
index = [left indexOfItemWithRepresentedObject:type];
[left selectItemAtIndex:index];
}
- (void)_setComparisonPredicate:(CPComparisonPredicate)predicate
{
var left = [_views objectAtIndex:0],
middle = [_views objectAtIndex:1],
right = [_views objectAtIndex:2],
leftExpression = [predicate leftExpression],
rightExpression = [predicate rightExpression],
operator = [predicate predicateOperatorType];
if (_leftIsWildcard)
[left setObjectValue:[leftExpression constantValue]];
else
{
var index = [left indexOfItemWithRepresentedObject:leftExpression];
[left selectItemAtIndex:index];
}
var op_index = [middle indexOfItemWithRepresentedObject:operator];
[middle selectItemAtIndex:op_index];
if (_rightIsWildcard)
[right setObjectValue:[rightExpression constantValue]];
else
{
var index = [right indexOfItemWithRepresentedObject:rightExpression];
[right selectItemAtIndex:index];
}
}
- (CPExpression)_leftExpression
{
return [self _expressionFromView:_views[0] forAttributeType:_leftAttributeType];
}
- (CPExpression)_rightExpression
{
return [self _expressionFromView:_views[2] forAttributeType:_rightAttributeType];
}
- (CPExpression)_expressionFromView:(CPView)aView forAttributeType:(CPAttributeType)attributeType
{
if (attributeType == 0)
return [[aView selectedItem] representedObject];
var value;
if (attributeType >= CPInteger16AttributeType && attributeType <= CPFloatAttributeType)
value = [aView intValue];
else if (attributeType == CPBooleanAttributeType)
value = [aView state];
else
value = [aView stringValue];
return [CPExpression expressionForConstantValue:value];
}
- (int)_rowType
{
return (_templateType - 1);
}
- (id)copy
{
return [CPKeyedUnarchiver unarchiveObjectWithData:[CPKeyedArchiver archivedDataWithRootObject:self]];
}
+ (id)_operatorsForAttributeType:(CPAttributeType)attributeType
{
var operators_array = [CPMutableArray array];
switch (attributeType)
{
case CPInteger16AttributeType : [operators_array addObjects:4,5,0,2,1,3];
break;
case CPInteger32AttributeType : [operators_array addObjects:4,5,0,2,1,3];
break;
case CPInteger64AttributeType : [operators_array addObjects:4,5,0,2,1,3];
break;
case CPDecimalAttributeType : [operators_array addObjects:4,5,0,2,1,3];
break;
case CPDoubleAttributeType : [operators_array addObjects:4,5,0,2,1,3];
break;
case CPFloatAttributeType : [operators_array addObjects:4,5,0,2,1,3];
break;
case CPStringAttributeType : [operators_array addObjects:99,4,5,8,9];
break;
case CPBooleanAttributeType : [operators_array addObjects:4,5];
break;
case CPDateAttributeType : [operators_array addObjects:4,5,0,2,1,3];
break;
default : CPLogConsole("Cannot create operators for an CPAttributeType " + attributeType);
break;
}
return operators_array;
}
- (int)_templateType
{
return _templateType;
}
- (id)_displayValueForPredicateOperator:(int)operator
{
var value;
switch (operator)
{
case CPLessThanPredicateOperatorType : value = @"is less than";
break;
case CPLessThanOrEqualToPredicateOperatorType : value = @"is less than or equal to";
break;
case CPGreaterThanPredicateOperatorType : value = @"is greater than";
break;
case CPGreaterThanOrEqualToPredicateOperatorType : value = @"is greater than or equal to";
break;
case CPEqualToPredicateOperatorType : value = @"is";
break;
case CPNotEqualToPredicateOperatorType : value = @"is not";
break;
case CPMatchesPredicateOperatorType : value = @"matches";
break;
case CPLikePredicateOperatorType : value = @"is like";
break;
case CPBeginsWithPredicateOperatorType : value = @"begins with";
break;
case CPEndsWithPredicateOperatorType : value = @"ends with";
break;
case CPInPredicateOperatorType : value = @"in";
break;
case CPContainsPredicateOperatorType : value = @"contains";
break;
case CPBetweenPredicateOperatorType : value = @"between";
break;
default : CPLogConsole(@"unknown predicate operator %d" + operator);
}
return value;
}
- (id)_displayValueForCompoundPredicateType:(unsigned int)predicateType
{
var value;
switch (predicateType)
{
case CPNotPredicateType: value = @"None";
break;
case CPAndPredicateType: value = @"All";
break;
case CPOrPredicateType: value = @"Any";
break;
default : value = [CPString stringWithFormat:@"unknown compound predicate type %d",predicateType];
}
return value;
}
- (id)_displayValueForConstantValue:(id)value
{
return [value description]; // number, date, string, ... localize
}
- (id)_displayValueForKeyPath:(CPString)keyPath
{
return keyPath; // localize
}
- (CPPopUpButton)_viewFromExpressions:(CPArray)expressions
{
var popup = [[CPPopUpButton alloc] initWithFrame:CPMakeRect(0, 0, 100, 18)],
count = [expressions count];
for (var i = 0; i < count; i++)
{
var exp = expressions[i],
type = [exp expressionType],
title;
switch (type)
{
case CPKeyPathExpressionType: title = [self _displayValueForKeyPath:[exp keyPath]];
break;
case CPConstantValueExpressionType: title = [self _displayValueForConstantValue:[exp constantValue]];
break;
default: [CPException raise:CPInvalidArgumentException reason:@"Invalid Expression type " + type];
break;
}
var item = [[CPMenuItem alloc] initWithTitle:title action:nil keyEquivalent:@""];
[item setRepresentedObject:exp];
[popup addItem:item];
}
[popup sizeToFit];
return popup;
}
- (CPPopUpButton)_viewFromOperatorTypes:(CPArray)operators
{
var popup = [[CPPopUpButton alloc] initWithFrame:CGRectMake(0, 0, 100, 18)],
count = [operators count];
for (var i = 0; i < count; i++)
{
var op = operators[i],
title = [self _displayValueForPredicateOperator:op],
item = [[CPMenuItem alloc] initWithTitle:title action:nil keyEquivalent:@""];
[item setRepresentedObject:op];
[popup addItem:item];
}
[popup sizeToFit];
return popup;
}
- (CPView)_viewFromCompoundTypes:(CPArray)compoundTypes
{
var popup = [[CPPopUpButton alloc] initWithFrame:CGRectMake(0, 0, 100, 18)],
count = [compoundTypes count];
for (var i = 0; i < count; i++)
{
var type = compoundTypes[i],
title = [self _displayValueForCompoundPredicateType:type],
item = [[CPMenuItem alloc] initWithTitle:title action:nil keyEquivalent:@""];
[item setRepresentedObject:type];
[popup addItem:item];
}
[popup sizeToFit];
return popup;
}
- (CPView)_viewFromAttributeType:(CPAttributeType)attributeType
{
var view;
if (attributeType >= CPInteger16AttributeType && attributeType <= CPFloatAttributeType)
{
view = [self _textFieldWithFrame:CGRectMake(0, 0, 50, 26)];
}
else if (attributeType == CPStringAttributeType)
{
view = [self _textFieldWithFrame:CGRectMake(0, 0, 150, 26)];
}
else if (attributeType == CPBooleanAttributeType)
{
view = [[CPCheckBox alloc] initWithFrame:CGRectMake(0, 0, 50, 26)];
}
else if (attributeType == CPDateAttributeType)
view = [[CPDatePicker alloc] initWithFrame:CGRectMake(0, 0, 150, 26)];
else
return nil;
[view setTag:attributeType];
return view;
}
- (CPTextField)_textFieldWithFrame:(CGRect)frame
{
var textField = [[CPTextField alloc] initWithFrame:frame];
[textField setBezeled:YES];
[textField setBezelStyle:CPTextFieldSquareBezel];
[textField setBordered:YES];
[textField setEditable:YES];
[textField setFont:[CPFont systemFontOfSize:10]];
return textField;
}
- (void)_setOptions:(unsigned int)options
{
_predicateOptions = options;
}
- (void)_setModifier:(unsigned int)modifier
{
_predicateModifier = modifier;
}
- (CPString)description
{
if (_templateType == 2)
return [CPString stringWithFormat:@"<%@ %p %@>",[self className],self,[[self compoundTypes] componentsJoinedByString:@", "]];
else if (_templateType == 1 && _rightIsWildcard)
return [CPString stringWithFormat:@"<%@ %p [%@] [%@] %d>",[self className],self,[[self leftExpressions] componentsJoinedByString:@", "],[[self operators] componentsJoinedByString:@", "],[self rightExpressionAttributeType]];
else
return [CPString stringWithFormat:@"<%@ %p [%@] [%@] [%@]>",[self className],self,[[self leftExpressions] componentsJoinedByString:@", "],[[self operators] componentsJoinedByString:@", "],[[self rightExpressions] componentsJoinedByString:@", "]];
}
/*
- (void)_setLeftExpressionObject:(id)object
{
}
- (void)_setRightExpressionObject:(id)object
{
}
- (BOOL)_predicateIsNoneAreTrue:(id)predicate
{
}
- (id)_viewFromExpressionObject:(id)object
{
}
*/
@end
var CPPredicateTemplateTypeKey = @"CPPredicateTemplateType",
CPPredicateTemplateOptionsKey = @"CPPredicateTemplateOptions",
CPPredicateTemplateModifierKey = @"CPPredicateTemplateModifier",
CPPredicateTemplateLeftAttributeTypeKey = @"CPPredicateTemplateLeftAttributeType",
CPPredicateTemplateRightAttributeTypeKey = @"CPPredicateTemplateRightAttributeType",
CPPredicateTemplateLeftIsWildcardKey = @"CPPredicateTemplateLeftIsWildcard",
CPPredicateTemplateRightIsWildcardKey = @"CPPredicateTemplateRightIsWildcard",
CPPredicateTemplateViewsKey = @"CPPredicateTemplateViews";
@implementation CPPredicateEditorRowTemplate (CPCoding)
- (id)initWithCoder:(CPCoder)coder
{
self = [super init];
if (self != nil)
{
_templateType = [coder decodeIntForKey:CPPredicateTemplateTypeKey];
_predicateOptions = [coder decodeIntForKey:CPPredicateTemplateOptionsKey];
_predicateModifier = [coder decodeIntForKey:CPPredicateTemplateModifierKey];
_leftAttributeType = [coder decodeIntForKey:CPPredicateTemplateLeftAttributeTypeKey];
_rightAttributeType = [coder decodeIntForKey:CPPredicateTemplateRightAttributeTypeKey];
_leftIsWildcard = [coder decodeBoolForKey:CPPredicateTemplateLeftIsWildcardKey];
_rightIsWildcard = [coder decodeBoolForKey:CPPredicateTemplateRightIsWildcardKey];
_views = [coder decodeObjectForKey:CPPredicateTemplateViewsKey];
// In Xcode 4, when the menu item title == template's expression keypath, representedObject is empty.
// So we need to regenerate expressions from titles.
if (_templateType == 1 && _leftIsWildcard == NO)
{
var itemArray = [_views[0] itemArray],
count = [itemArray count];
for (var i = 0; i < count; i++)
{
var item = itemArray[i];
if ([item representedObject] == nil)
{
var exp = [CPExpression expressionForKeyPath:[item title]];
[item setRepresentedObject:exp];
}
}
}
}
return self;
}
- (void)encodeWithCoder:(CPCoder)coder
{
[coder encodeInt:_templateType forKey:CPPredicateTemplateTypeKey];
[coder encodeInt:_predicateOptions forKey:CPPredicateTemplateOptionsKey];
[coder encodeInt:_predicateModifier forKey:CPPredicateTemplateModifierKey];
[coder encodeInt:_leftAttributeType forKey:CPPredicateTemplateLeftAttributeTypeKey];
[coder encodeInt:_rightAttributeType forKey:CPPredicateTemplateRightAttributeTypeKey];
[coder encodeBool:_leftIsWildcard forKey:CPPredicateTemplateLeftIsWildcardKey];
[coder encodeBool:_rightIsWildcard forKey:CPPredicateTemplateRightIsWildcardKey];
[coder encodeObject:_views forKey:CPPredicateTemplateViewsKey];
}
@end
/*! @endcond */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,132 @@
/*
* Created by cacaodev@gmail.com.
* Copyright (c) 2011 Pear, Inc. All rights reserved.
*/
@class _CPPredicateEditorTree;
@implementation _CPPredicateEditorRowNode : CPObject
{
_CPPredicateEditorTree tree @accessors;
CPMutableArray templateViews @accessors;
CPMutableArray copiedTemplateContainer @accessors;
CPArray children @accessors(copy);
}
+ (id)rowNodeFromTree:(id)aTree
{
var mapTable = {};
return [_CPPredicateEditorRowNode _rowNodeFromTree:aTree withTemplateTable:mapTable];
}
+ (id)_rowNodeFromTree:(id)aTree withTemplateTable:(id)templateTable
{
var node,
views,
copiedContainer;
node = [[_CPPredicateEditorRowNode alloc] init];
node.tree = aTree;
var template = [aTree template],
uuid = [template UID];
var cachedNode = templateTable[uuid];
if (cachedNode == nil)
{
views = [CPMutableArray array];
copiedContainer = [CPMutableArray array];
templateTable[uuid] = node;
}
else
{
views = [cachedNode templateViews];
copiedContainer = [cachedNode copiedTemplateContainer];
}
node.templateViews = views;
node.copiedTemplateContainer = copiedContainer;
var nodeChildren = [CPMutableArray array],
treeChildren = [aTree children],
count = [treeChildren count];
for (var i = 0; i < count; i++)
{
var treeChild = treeChildren[i],
child = [_CPPredicateEditorRowNode _rowNodeFromTree:treeChild withTemplateTable:templateTable];
[nodeChildren addObject:child];
}
[node setChildren:nodeChildren];
return node;
}
- (BOOL)applyTemplate:(id)template withViews:(id)views forOriginalTemplate:(id)originalTemplate
{
var t = [tree template];
if (t !== template)
{
[templateViews setArray:views];
[copiedTemplateContainer removeAllObjects];
[copiedTemplateContainer addObject:template];
}
var count = [children count];
for (var i; i < count; i++)
[children[i] applyTemplate:template withViews:views forOriginalTemplate:originalTemplate];
}
- (BOOL)isEqual:(id)node
{
if (![node isKindOfClass:[_CPPredicateEditorRowNode class]])
return NO;
return (tree === [node tree]);
}
- (void)copyTemplateIfNecessary
{
if ([copiedTemplateContainer count] == 0)
{
CPLogConsole("COPYING TEMPLATE");
var copy = [[tree template] copy];
[copiedTemplateContainer addObject:copy];
[templateViews addObjectsFromArray:[copy templateViews]];
}
}
- (CPView)templateView
{
[self copyTemplateIfNecessary];
return [templateViews objectAtIndex:[tree indexIntoTemplate]];
}
- (id)templateForRow
{
[self copyTemplateIfNecessary];
return [copiedTemplateContainer lastObject];
}
- (CPString)title
{
return [tree title];
}
- (id)displayValue
{
var title = [self title];
if (title != nil)
return title;
return [self templateView];
}
- (CPString)description
{
return [CPString stringWithFormat:@"<%@ %@ %@ tree:%@ tviews:%@", [self className],[self UID], [self title], [tree UID], [templateViews description]];
}
@end
@@ -0,0 +1,33 @@
/*
* Created by cacaodev@gmail.com.
* Copyright (c) 2011 Pear, Inc. All rights reserved.
*/
@implementation _CPPredicateEditorTree : CPObject
{
CPPredicateEditorRowTemplate template @accessors;
CPString title @accessors(copy);
CPArray children @accessors(copy);
CPInteger indexIntoTemplate @accessors;
CPInteger menuItemIndex @accessors;
}
- (id)copy
{
var tree = [[_CPPredicateEditorTree alloc] init];
[tree setTemplate:template];
[tree setTitle:title];
[tree setMenuItemIndex:menuItemIndex];
[tree setIndexIntoTemplate:indexIntoTemplate];
[tree setChildren:children];
return tree;
}
- (CPString)description
{
return [CPString stringWithFormat:@"<%@: %p (%@) [%d-%d] T:%p at:%d> [\r%@\r]", [self className], self, title, indexIntoTemplate, menuItemIndex, template, [template rightExpressionAttributeType], children];
}
@end
@@ -0,0 +1,75 @@
/*
* Created by cacaodev@gmail.com.
* Copyright (c) 2011 Pear, Inc. All rights reserved.
*/
@import <Foundation/CPObject.j>
@import <Foundation/CPDictionary.j>
@import <Foundation/CPString.j>
var regex = new RegExp("\"(.+)\"\\s*=\\s*\"(.+)\"\\s*;\\s*(//.+)?");
@implementation _CPRuleEditorLocalizer : CPObject
{
CPDictionary _dictionary @accessors(property=dictionary);
CPURLConnection connection;
CPURLRequest resquest;
}
- (void)loadContentOfURL:(CPURL)aURL
{
request = [CPURLRequest requestWithURL:aURL];
connection = [CPURLConnection connectionWithRequest:request delegate:self];
}
- (void)reloadIfNeeded
{
if (connection != nil) // Connection waiting
{
connection = nil;
var data = [CPURLConnection sendSynchronousRequest:request returningResponse:NULL];
[self loadContent:[data rawString]];
}
}
- (void)connection:(CPURLConnection)aConnection didReceiveData:(CPString)rawString
{
if (connection != nil && rawString != nil)
[self loadContent:rawString];
connection = nil;
}
- (void)loadContent:(CPString)aContent
{
var dict = [CPDictionary dictionary],
lines = [aContent componentsSeparatedByString:"\n"],
count = [lines count];
for (var i = 0 ; i < count ; i++)
{
var line = [lines objectAtIndex:i];
if (line.length > 1)
{
var match = regex.exec(line);
if (match.length >= 3)
[dict setObject:match[2] forKey:match[1]];
}
}
_dictionary = [CPDictionary dictionaryWithDictionary:dict];
}
- (CPString)localizedStringForString:(CPString)aString
{
[self reloadIfNeeded];
if (_dictionary != nil && aString != nil)
{
var localized = [_dictionary objectForKey:aString];
if (localized != nil)
return localized;
}
return aString;
}
@@ -0,0 +1,157 @@
/*
* Created by cacaodev@gmail.com.
* Copyright (c) 2011 Pear, Inc. All rights reserved.
*/
var GRADIENT_NORMAL,
GRADIENT_HIGHLIGHTED,
IE_FILTER = "progid:DXImageTransform.Microsoft.gradient(startColorstr='#fcfcfc', endColorstr='#dfdfdf')";
@implementation _CPRuleEditorPopUpButton : CPPopUpButton
{
CPInteger radius;
}
+ (void)initialize
{
if (CPBrowserIsEngine(CPWebKitBrowserEngine))
{
GRADIENT_NORMAL = "-webkit-gradient(linear, left top, left bottom, from(rgb(252, 252, 252)), to(rgb(223, 223, 223)))",
GRADIENT_HIGHLIGHTED = "-webkit-gradient(linear, left top, left bottom, from(rgb(223, 223, 223)), to(rgb(252, 252, 252)))";
}
else if (CPBrowserIsEngine(CPGeckoBrowserEngine))
{
GRADIENT_NORMAL = "-moz-linear-gradient(top, rgb(252, 252, 252), rgb(223, 223, 223))",
GRADIENT_HIGHLIGHTED = "-moz-linear-gradient(top, rgb(223, 223, 223), rgb(252, 252, 252))";
}
}
- (id)initWithFrame:(CGRect)aFrame
{
if (self = [super initWithFrame:aFrame])
{
var style = _DOMElement.style;
style.backgroundImage = GRADIENT_NORMAL;
style.border = "1px solid rgb(189, 189, 189)";
style.filter = IE_FILTER;
[self setTextColor:[CPColor colorWithWhite:101/255 alpha:1]];
[self setBordered:NO];
}
return self;
}
- (id)hitTest:(CPPoint)point
{
var slice = [self superview];
if (!CPRectContainsPoint([self frame], point) || ![self sliceIsEditable])
return nil;
return self;
}
- (void)setHighlighted:(BOOL)shouldHighlight
{
_DOMElement.style.backgroundImage = (shouldHighlight) ? GRADIENT_HIGHLIGHTED : GRADIENT_NORMAL;
}
- (BOOL)sliceIsEditable
{
return [[self superview] isEditable];
}
- (BOOL)trackMouse:(CPEvent)theEvent
{
if (![self sliceIsEditable])
return NO;
return [super trackMouse:theEvent];
}
- (CGRect)contentRectForBounds:(CGRect)bounds
{
var contentRect = [super contentRectForBounds:bounds];
contentRect.origin.x += radius;
contentRect.size.width -= 2 * radius;
return contentRect;
}
- (void)layoutSubviews
{
radius = FLOOR(CGRectGetHeight([self bounds])/2);
var style = _DOMElement.style,
radiusCSS = radius + "px";
//style.webkitBorderRadius = radiusCSS;
//style.mozBorderRadius = radiusCSS;
style.borderRadius = radiusCSS;
[super layoutSubviews];
}
- (void)drawRect:(CGRect)aRect
{
var bounds = [self bounds],
context = [[CPGraphicsContext currentContext] graphicsPort];
var arrow_width = FLOOR(CGRectGetHeight(bounds)/3.5);
CGContextTranslateCTM(context, CGRectGetWidth(bounds) - radius - arrow_width, CGRectGetHeight(bounds) / 2);
var arrowsPath = [CPBezierPath bezierPath];
[arrowsPath moveToPoint:CGPointMake(0, 1)];
[arrowsPath lineToPoint:CGPointMake(arrow_width, 1)];
[arrowsPath lineToPoint:CGPointMake(arrow_width/2, arrow_width + 1)];
[arrowsPath closePath];
CGContextSetFillColor(context, [CPColor colorWithWhite:101/255 alpha:1]);
[arrowsPath fill];
CGContextScaleCTM(context, 1 , -1);
[arrowsPath fill];
}
@end
@implementation _CPRuleEditorButton : CPButton
{
CPInteger radius;
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
if (self)
{
[self setFont:[CPFont boldFontWithName:@"Apple Symbol" size:12.0]];
[self setTextColor:[CPColor colorWithWhite:150/255 alpha:1]];
[self setAlignment:CPCenterTextAlignment];
[self setAutoresizingMask:CPViewMinXMargin];
[self setImagePosition:CPImageOnly];
[self setBordered:NO];
var style = _DOMElement.style;
style.border = "1px solid rgb(189, 189, 189)";
style.filter = IE_FILTER;
}
return self;
}
- (void)layoutSubviews
{
radius = FLOOR(CGRectGetHeight([self bounds])/2);
var style = _DOMElement.style,
radiusCSS = radius + "px";
style.borderRadius = radiusCSS;
style.backgroundImage = ([self isHighlighted]) ? GRADIENT_HIGHLIGHTED : GRADIENT_NORMAL;
[super layoutSubviews];
}
@end
@@ -0,0 +1,109 @@
/*
* Created by cacaodev@gmail.com.
* Copyright (c) 2011 Pear, Inc. All rights reserved.
*/
@implementation _CPRuleEditorViewSlice : CPView
{
CPRuleEditor _ruleEditor;
int _indentation @accessors(property=indentation);
int _rowIndex @accessors(property=rowIndex);
CPRect _animationTargetRect @accessors(property=_animationTargetRect);
BOOL _selected @accessors(getter=_isSelected, setter=_setSelected:);
BOOL _lastSelected @accessors(getter=_isLastSelected, setter=_setLastSelected:);
CPColor _backgroundColor @accessors(property=backgroundColor);
}
- (void)removeFromSuperview
{
[super removeFromSuperview];
}
- (id)initWithFrame:(CGRect)frame ruleEditorView:(id)editor
{
if (self = [super initWithFrame:frame])
{
_ruleEditor = editor;
_selected = NO;
_lastSelected = NO;
}
return self;
}
- (void)_setSelected:(BOOL)select
{
if (select == _selected)
return;
var selector = select ? @"setThemeState:" : @"unsetThemeState:";
[[self subviews] makeObjectsPerformSelector:CPSelectorFromString(selector) withObject:CPThemeStateSelectedDataView];
_selected = select;
}
- (void)drawRect:(CPRect)rect
{
var context = [[CPGraphicsContext currentContext] graphicsPort],
bounds = [self bounds],
maxX = CGRectGetWidth(bounds) - 2,
maxY = CGRectGetHeight(bounds);
// Draw background
if ([self _isSelected])
_backgroundColor = [_ruleEditor _selectedRowColor];
else
{
var colors = [_ruleEditor _backgroundColors],
count = [colors count];
_backgroundColor = [colors objectAtIndex:(_rowIndex % count)];
}
CGContextSetFillColor(context, _backgroundColor);
CGContextFillRect(context, rect);
// Draw Top Border
CGContextBeginPath(context);
CGContextMoveToPoint(context, 1, 0);
CGContextAddLineToPoint(context, maxX, 0);
CGContextClosePath(context);
CGContextSetStrokeColor(context, [_ruleEditor _sliceTopBorderColor]);
CGContextStrokePath(context);
// Draw Bottom Border
CGContextBeginPath(context);
CGContextMoveToPoint(context, 1, maxY - 0.5);
CGContextAddLineToPoint(context, maxX, maxY - 0.5);
CGContextClosePath(context);
var bottomColor = (_rowIndex == [_ruleEditor _lastRow]) ? [_ruleEditor _sliceLastBottomBorderColor] : [_ruleEditor _sliceBottomBorderColor];
CGContextSetStrokeColor(context, bottomColor);
CGContextStrokePath(context);
}
- (void)mouseDown:(CPEvent)theEvent
{
if (editable)
[_ruleEditor _mouseDownOnSlice:self withEvent:theEvent];
}
- (void)mouseUp:(CPEvent)theEvent
{
if (editable)
[_ruleEditor _mouseUpOnSlice:self withEvent:theEvent];
}
/*
- (void)rightMouseDown:(CPEvent)theEvent
{
[_ruleEditor _rightMouseDownOnSlice:self withEvent:theEvent];
}
*/
// =========
// ! DEBUG
// =========
- (CPString)description
{
return [CPString stringWithFormat:@"<%@ %p index:%d indentation:%d>",[self className],self,[self rowIndex],[self indentation]];
}
@end
@@ -0,0 +1,512 @@
/*
* Created by cacaodev@gmail.com.
* Copyright (c) 2011 Pear, Inc. All rights reserved.
*/
@import "_CPRuleEditorViewSlice.j"
@import "_CPRuleEditorPopUpButton.j"
@import "CPRuleEditor.j"
var CONTROL_HEIGHT = 16.,
BUTTON_HEIGHT = 16.;
@implementation _CPRuleEditorViewSliceRow : _CPRuleEditorViewSlice
{
CPMutableArray _ruleOptionViews;
CPMutableArray _ruleOptionFrames;
CPMutableArray _correspondingRuleItems;
CPMutableArray _ruleOptionInitialViewFrames;
CPButton _addButton;
CPButton _subtractButton;
BOOL editable;
CPRuleEditorRowType _rowType @accessors;
CPRuleEditorRowType _plusButtonRowType;
}
- (id)initWithFrame:(CGRect)frame ruleEditorView:(id)editor
{
if (self = [super initWithFrame:frame ruleEditorView:editor])
[self _initShared];
return self;
}
- (void)_initShared
{
_correspondingRuleItems = [[CPMutableArray alloc] init];
_ruleOptionFrames = [[CPMutableArray alloc] init];
_ruleOptionInitialViewFrames = [[CPMutableArray alloc] init];
_ruleOptionViews = [[CPMutableArray alloc] init];
editable = [_ruleEditor isEditable];
_addButton = [self _createAddRowButton];
_subtractButton = [self _createDeleteRowButton];
//[_addButton setToolTip:[_ruleEditor _toolTipForAddSimpleRowButton]];
//[_subtractButton setToolTip:[_ruleEditor _toolTipForDeleteRowButton]];
[_addButton setHidden:!editable];
[_subtractButton setHidden:!editable];
[self addSubview:_addButton];
[self addSubview:_subtractButton];
[self setAutoresizingMask:CPViewWidthSizable];
var center = [CPNotificationCenter defaultCenter];
[center addObserver:self selector:@selector(_textDidChange:) name:CPControlTextDidChangeNotification object:nil];
}
- (CPButton)_createAddRowButton
{
var button = [[_CPRuleEditorButton alloc] initWithFrame:CGRectMakeZero()];
[button setImage:[_ruleEditor _addImage]];
[button setAction:@selector(_addOption:)];
[button setTarget:self];
[button setAutoresizingMask:CPViewMinXMargin];
return button;
}
- (CPButton)_createDeleteRowButton
{
var button = [[_CPRuleEditorButton alloc] initWithFrame:CGRectMakeZero()];
[button setImage:[_ruleEditor _removeImage]];
[button setAction:@selector(_deleteOption:)];
[button setTarget:self];
[button setAutoresizingMask:CPViewMinXMargin];
return button;
}
- (CPMenuItem)_createMenuItemWithTitle:(CPString )title
{
title = [[_ruleEditor standardLocalizer] localizedStringForString:title];
var mItem = [[CPMenuItem alloc] initWithTitle:title action:nil keyEquivalent:@""];
return mItem;
}
- (CPPopUpButton)_createPopUpButtonWithItems:(CPArray)itemsArray selectedItemIndex:(int)index
{
var title = [[itemsArray objectAtIndex:index] title];
var font = [_ruleEditor font],
width = [title sizeWithFont:font].width + 20,
rect = CGRectMake(0, 0, (width - width % 40) + 80, CONTROL_HEIGHT);
var popup = [[_CPRuleEditorPopUpButton alloc] initWithFrame:rect];
[popup setValue:font forThemeAttribute:@"font"];
var count = [itemsArray count];
for (var i = 0; i < count; i++)
[popup addItem:[itemsArray objectAtIndex:i]];
[popup selectItemAtIndex:index];
return popup;
}
- (CPMenuItem)_createMenuSeparatorItem
{
return [CPMenuItem separatorItem];
}
- (_CPRuleEditorTextField)_createStaticTextFieldWithStringValue:(CPString )text
{
text = [[_ruleEditor standardLocalizer] localizedStringForString:text];
var textField = [[_CPRuleEditorTextField alloc] initWithFrame:CPMakeRect(0, 0, 200, CONTROL_HEIGHT)];
var font = [_ruleEditor font];
font = [CPFont fontWithName:font._name size:font._size + 2];
[textField setValue:font forThemeAttribute:@"font"];
[textField setStringValue:text];
[textField sizeToFit];
return textField;
}
- (void)_addOption:(id)sender
{
if (_rowIndex == [_ruleEditor numberOfRows] - 1)
[self setNeedsDisplay:YES];
var type = _plusButtonRowType;
if ([_ruleEditor nestingMode] == CPRuleEditorNestingModeCompound && ([[CPApp currentEvent] modifierFlags] & CPAlternateKeyMask))
type = CPRuleEditorRowTypeCompound;
[_ruleEditor _addOptionFromSlice:self ofRowType:type];
}
- (void)_deleteOption:(id)sender
{
[_ruleEditor _deleteSlice:self];
}
- (void)_ruleOptionPopupChangedAction:(CPMenuItem )sender
{
var layoutdict = [sender representedObject],
newItem = [layoutdict objectForKey:@"item"],
indexInCriteria = [layoutdict objectForKey:@"indexInCriteria"],
oldItem = [_correspondingRuleItems objectAtIndex:indexInCriteria];
if (![newItem isEqual:oldItem])
{
[_correspondingRuleItems replaceObjectAtIndex:indexInCriteria withObject:newItem];
[_ruleEditor _changedItem:oldItem toItem:newItem inRow:_rowIndex atCriteriaIndex:indexInCriteria];
}
}
- (BOOL)validateMenuItem:(CPMenuItem )menuItem
{
return [_ruleEditor _validateItem:menuItem value:[[menuItem representedObject] valueForKey:@"item"] inRow:_rowIndex];
}
- (void)_emptyRulePartSubviews
{
var count = [_ruleOptionViews count];
while (count--)
[_ruleOptionViews[count] removeFromSuperview];
[_ruleOptionViews removeAllObjects];
[_ruleOptionFrames removeAllObjects];
[_ruleOptionInitialViewFrames removeAllObjects];
}
- (void)_reconfigureSubviews
{
var ruleItems,
criteria,
repObject,
menuItem,
ruleView,
criterion,
parent,
numberOfCriteria,
numberOfChildren,
firstResponderIndex;
var ruleItems = [CPMutableArray array];
[self _emptyRulePartSubviews];
criteria = [_ruleEditor criteriaForRow:_rowIndex];
numberOfCriteria = [criteria count];
firstResponderIndex = numberOfCriteria - 1;
var responder = [[self window] firstResponder];
if (responder)
firstResponderIndex = [_ruleOptionViews indexOfObjectIdenticalTo:responder];
for (var i = 0; i < numberOfCriteria; i++)
{
ruleView = nil;
parent = nil;
criterion = [criteria objectAtIndex:i];
if (i > 0)
parent = [criteria objectAtIndex:i - 1];
var childItems = [],
childValues = [];
[_ruleEditor _getAllAvailableItems:childItems values:childValues asChildrenOfItem:parent inRow:_rowIndex];
numberOfChildren = [childItems count];
if (numberOfChildren > 1)
{
var menuItems = [CPMutableArray arrayWithCapacity:numberOfChildren];
var selectedIndex = [childItems indexOfObject:criterion];
if (selectedIndex == CPNotFound)
break;
for (var j = 0; j < numberOfChildren; ++j)
{
var childItem = [childItems objectAtIndex:j];
var childValue = [childValues objectAtIndex:j];
if ([childValue isKindOfClass:[CPMenuItem class]])
{
[[childValue menu] removeItem:childValue];
menuItem = childValue;
}
else
{
if ([childValue isEqualToString:@""])
menuItem = [self _createMenuSeparatorItem];
else
{
menuItem = [self _createMenuItemWithTitle:childValue];
[menuItem setTarget:self];
[menuItem setAction:@selector(_ruleOptionPopupChangedAction:)];
}
}
repObject = [CPDictionary dictionaryWithObjectsAndKeys:childItem, @"item", childValue, @"value", i, @"indexInCriteria"];
[menuItem setRepresentedObject:repObject];
[menuItems addObject:menuItem];
}
ruleView = [self _createPopUpButtonWithItems:menuItems selectedItemIndex:selectedIndex];
}
else
{
var value = [childValues objectAtIndex:0];
var type = [value valueType];
if (type === 0)
ruleView = [self _createStaticTextFieldWithStringValue:value];
else
{
if (type !== 1)
{
[CPException raise:CPInternalInconsistencyException reason:@"Display value must be a string or a menu item"];
continue;
}
ruleView = value;
[ruleView setTarget:self];
[ruleView setAction:@selector(_sendRuleAction:)];
if ([ruleView respondsToSelector:@selector(setDelegate:)])
[ruleView setDelegate:self];
}
}
if (ruleView != nil)
{
[_ruleOptionViews addObject:ruleView];
var frame = [ruleView frame];
[_ruleOptionInitialViewFrames addObject:frame];
[_ruleOptionFrames addObject:frame];
if (!criterion)
criterion = [CPNull null];
[ruleItems addObject:criterion];
}
}
[_correspondingRuleItems setArray:ruleItems];
if (!editable)
[self _updateEnabledStateForSubviews];
[self _relayoutSubviewsWidthChanged:YES];
if (firstResponderIndex != CPNotFound)
{
var aView = [_ruleOptionViews objectAtIndex:firstResponderIndex];
[[self window] makeFirstResponder:aView]; // This is not working. bug in CPPopUpButton firstResponder ?
}
//[self setNeedsDisplay:YES];
}
- (void)_updateEnabledStateForSubviews
{
[_ruleOptionViews makeObjectsPerformSelector:@selector(setEnabled:) withObject:NO];
}
- (void)layoutSubviews
{
// CPLogConsole(_cmd);
[self _relayoutSubviewsWidthChanged:YES];
}
- (void)_relayoutSubviewsWidthChanged:(BOOL)widthChanged
{
var optionViewOriginX,
leftHorizontalPadding,
leftButtonMinX,
rowHeight = [_ruleEditor rowHeight],
count = [_ruleOptionViews count],
sliceFrame = [self frame];
var buttonFrame = CGRectMake(CGRectGetWidth(sliceFrame) - BUTTON_HEIGHT - [self _rowButtonsRightHorizontalPadding], ([_ruleEditor rowHeight] - BUTTON_HEIGHT)/2 - 2, BUTTON_HEIGHT, BUTTON_HEIGHT);
[_addButton setFrame:buttonFrame];
buttonFrame.origin.x -= BUTTON_HEIGHT + [self _rowButtonsInterviewHorizontalPadding];
[_subtractButton setFrame:buttonFrame];
if (widthChanged)
{
optionViewOriginX = [self _leftmostViewFixedHorizontalPadding] + [self _indentationHorizontalPadding] * _indentation;
leftHorizontalPadding = [self _rowButtonsLeftHorizontalPadding];
leftButtonMinX = CGRectGetMinX(buttonFrame);
}
for (var i = 0; i < count; i++)
{
var ruleOptionView = _ruleOptionViews[i],
optionFrame = _ruleOptionFrames[i];
optionFrame.origin.y = (rowHeight - CGRectGetHeight(optionFrame))/2 - 2;
if (widthChanged)
{
optionFrame.origin.x = optionViewOriginX;
if (i == count - 1 && ![self _isRulePopup:ruleOptionView])
{
var initialFrame = _ruleOptionInitialViewFrames[i];
optionFrame.size.width = MIN(CGRectGetWidth(initialFrame), leftButtonMinX - leftHorizontalPadding - optionViewOriginX);
}
}
[ruleOptionView setFrame:optionFrame];
[self addSubview:ruleOptionView];
if (widthChanged)
optionViewOriginX += CGRectGetWidth(optionFrame) + [self _interviewHorizontalPadding];
}
}
- (void)_updateButtonVisibilities
{
[_addButton setHidden:[_ruleEditor _shouldHideAddButtonForSlice:self]];
[_subtractButton setHidden:[_ruleEditor _shouldHideSubtractButtonForSlice:self]];
}
- (void)_configurePlusButtonByRowType:(CPRuleEditorRowType)type
{
[self _setRowTypeToAddFromPlusButton:type];
}
- (BOOL)isEditable
{
return editable;
}
- (void)setEditable:(BOOL)value
{
editable = value;
// [self _updateEnabledStateForSubviews];
[self _updateButtonVisibilities];
}
- (float)_alignmentGridWidth
{
return [_ruleEditor _alignmentGridWidth];
}
- (float)_indentationHorizontalPadding
{
return 30.;
}
- (float)_interviewHorizontalPadding
{
return 6.;
}
- (float)_leftmostViewFixedHorizontalPadding
{
return 7.;
}
- (float)_minimumVerticalPopupPadding
{
return 2.;
}
- (float)_rowButtonsInterviewHorizontalPadding
{
return 6.;
}
- (float)_rowButtonsLeftHorizontalPadding
{
return 10.;
}
- (float)_rowButtonsRightHorizontalPadding
{
return 10.;
}
- (void)_setRowTypeToAddFromPlusButton:(int)type
{
_plusButtonRowType = type;
}
- (void)setNeedsDisplay:(BOOL)flag
{
[super setNeedsDisplay:flag];
}
- (BOOL)_nestingModeShouldHideAddButton
{
return [_ruleEditor _applicableNestingMode] == CPRuleEditorNestingModeSingle;
}
- (BOOL)_nestingModeShouldHideSubtractButton
{
return [_ruleEditor _applicableNestingMode] == CPRuleEditorNestingModeSingle;
}
- (BOOL)containsDisplayValue:(id)value
{
return [[_ruleEditor displayValuesForRow:_rowIndex] containsObject:value];
// Ou alors avec _correspondingRuleItems
}
- (void)viewDidMoveToWindow
{
[self layoutSubviews];
}
- (void)drawRect:(CPRect)rect
{
[super drawRect:rect];
}
- (BOOL)_isRulePopup:(CPView)view
{
if ([view isKindOfClass:[_CPRuleEditorPopUpButton class]])
return YES;
return NO;
}
- (BOOL)_isRuleStaticTextField:(CPView)view
{
if ([view isKindOfClass:[_CPRuleEditorTextField class]])
return YES;
return NO;
}
- (void)_sendRuleAction:(id)sender
{
[_ruleEditor _sendRuleAction];
}
- (void)_textDidChange:(CPNotification)aNotif
{
if ([[aNotif object] superview] == self && [_ruleEditor _sendsActionOnIncompleteTextChange])
[_ruleEditor _sendRuleAction];
}
@end
@implementation _CPRuleEditorTextField : CPTextField
{
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self != nil)
{
[self setBordered:NO];
[self setEditable:NO];
[self setDrawsBackground:NO];
}
return self;
}
- (id)hitTest:(CPPoint)point
{
if (!CPRectContainsPoint([self frame], point))
return nil;
return [self superview];
}
@end
+21
View File
@@ -1,3 +1,24 @@
/*
* CPSavePanel.j
* AppKit
*
* Created by Francisco Tolmasky.
* Copyright 2009, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import "CPPanel.j"
+36 -2
View File
@@ -1,11 +1,45 @@
/*
* CPScreen.j
* AppKit
*
* Created by Francisco Tolmasky.
* Copyright 2009, 280 North, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPObject.j>
/*!
@ingroup appkit
@class CPScreen
A CPScreen object describes the attributes of a display device available
to Cappuccino.
*/
@implementation CPScreen : CPObject
{
}
/*!
Returns the position and size of the visible area of the receiving screen.
This will normally be smaller than the full size of the screen to account
for system UI elements. For example, on a Mac the top of the visible frame
is placed below the bottom of the menu bar.
@return the visible screen rectangle
*/
- (CGRect)visibleFrame
{
#if PLATFORM(DOM)
@@ -15,4 +49,4 @@
#endif
}
@end
@end
+9 -7
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
{
@@ -713,7 +715,7 @@
*/
- (void)setLineScroll:(float)aLineScroll
{
[self setHorizonalLineScroll:aLineScroll];
[self setHorizontalLineScroll:aLineScroll];
[self setVerticalLineScroll:aLineScroll];
}
@@ -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);
}
}
}
+17 -5
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(cancelOperation:)];
[_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
{
@@ -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])
{
@@ -680,7 +691,8 @@ var RECENT_SEARCH_PREFIX = @" ";
- (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"
+5 -2
View File
@@ -382,6 +382,11 @@ CPCircularSlider = 1;
[self setNeedsDisplay:YES];
}
- (BOOL)isContinuous
{
return (_sendActionOn & CPLeftMouseDraggedMask) !== 0;
}
/*!
@ignore
should we have _continuous?
@@ -425,8 +430,6 @@ var CPSliderMinValueKey = "CPSliderMinValueKey",
{
_altIncrementValue = [aCoder decodeDoubleForKey:CPSliderAltIncrValueKey];
[self setContinuous:YES];
[self _recalculateIsVertical];
[self setNeedsLayout];
+16 -16
View File
@@ -74,7 +74,7 @@
[_rgbLabel setStringValue: "Red, Green, Blue"];
[_rgbLabel setTextColor:[CPColor blackColor]];
_redLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 35, 15, 20)];
_redLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 37, 15, 20)];
[_redLabel setStringValue: "R"];
[_redLabel setTextColor:[CPColor blackColor]];
@@ -86,18 +86,18 @@
[_redSlider setAutoresizingMask: CPViewWidthSizable];
// red value input box
_redValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 30, 45, 29)];
_redValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 30, 45, 28)];
[_redValue setAutoresizingMask: CPViewMinXMargin];
[_redValue setEditable: YES];
[_redValue setBezeled: YES];
[_redValue setDelegate: self];
[_contentView addSubview: _redValue];
_greenLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 58, 15, 20)];
_greenLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 63, 15, 20)];
[_greenLabel setStringValue: "G"];
[_greenLabel setTextColor:[CPColor blackColor]];
_greenSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 58, aFrame.size.width - 70, 20)];
_greenSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 61, aFrame.size.width - 70, 20)];
[_greenSlider setMaxValue: 1.0];
[_greenSlider setMinValue: 0.0];
[_greenSlider setTarget: self];
@@ -105,18 +105,18 @@
[_greenSlider setAutoresizingMask: CPViewWidthSizable];
// green value input box
_greenValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 53, 45, 29)];
_greenValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 56, 45, 28)];
[_greenValue setAutoresizingMask: CPViewMinXMargin];
[_greenValue setEditable: YES];
[_greenValue setBezeled: YES];
[_greenValue setDelegate: self];
[_contentView addSubview: _greenValue];
_blueLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 81, 15, 20)];
_blueLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 90, 15, 20)];
[_blueLabel setStringValue: "B"];
[_blueLabel setTextColor:[CPColor blackColor]];
_blueSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 81, aFrame.size.width - 70, 20)];
_blueSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 87, aFrame.size.width - 70, 20)];
[_blueSlider setMaxValue: 1.0];
[_blueSlider setMinValue: 0.0];
[_blueSlider setTarget: self];
@@ -124,7 +124,7 @@
[_blueSlider setAutoresizingMask: CPViewWidthSizable];
// blue value input box
_blueValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 76, 45, 29)];
_blueValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 82, 45, 28)];
[_blueValue setAutoresizingMask: CPViewMinXMargin];
[_blueValue setEditable: YES];
[_blueValue setBezeled: YES];
@@ -139,7 +139,7 @@
[_hueLabel setStringValue: "H"];
[_hueLabel setTextColor:[CPColor blackColor]];
_hueSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 145, aFrame.size.width - 70, 20)];
_hueSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 143, aFrame.size.width - 70, 20)];
[_hueSlider setMaxValue: 359.0];
[_hueSlider setMinValue: 0.0];
[_hueSlider setTarget: self];
@@ -147,14 +147,14 @@
[_hueSlider setAutoresizingMask: CPViewWidthSizable];
// hue value input box
_hueValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 140, 45, 29)];
_hueValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 138, 45, 28)];
[_hueValue setAutoresizingMask: CPViewMinXMargin];
[_hueValue setEditable: YES];
[_hueValue setBezeled: YES];
[_hueValue setDelegate: self];
[_contentView addSubview: _hueValue];
_saturationLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 168, 15, 20)];
_saturationLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 170, 15, 20)];
[_saturationLabel setStringValue: "S"];
[_saturationLabel setTextColor:[CPColor blackColor]];
@@ -166,18 +166,18 @@
[_saturationSlider setAutoresizingMask: CPViewWidthSizable];
// saturation value input box
_saturationValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 163, 45, 29)];
_saturationValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 164, 45, 28)];
[_saturationValue setAutoresizingMask: CPViewMinXMargin];
[_saturationValue setEditable: YES];
[_saturationValue setBezeled: YES];
[_saturationValue setDelegate: self];
[_contentView addSubview: _saturationValue];
_brightnessLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 191, 15, 20)];
_brightnessLabel = [[CPTextField alloc] initWithFrame: CGRectMake(0, 196, 15, 20)];
[_brightnessLabel setStringValue: "B"];
[_brightnessLabel setTextColor:[CPColor blackColor]];
_brightnessSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 191, aFrame.size.width - 70, 20)];
_brightnessSlider = [[CPSlider alloc] initWithFrame: CGRectMake(15, 194, aFrame.size.width - 70, 20)];
[_brightnessSlider setMaxValue: 100.0];
[_brightnessSlider setMinValue: 0.0];
[_brightnessSlider setTarget: self];
@@ -185,7 +185,7 @@
[_brightnessSlider setAutoresizingMask: CPViewWidthSizable];
// brightness value input box
_brightnessValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 186, 45, 29)];
_brightnessValue = [[CPTextField alloc] initWithFrame: CGRectMake(aFrame.size.width - 45, 190, 45, 28)];
[_brightnessValue setAutoresizingMask: CPViewMinXMargin];
[_brightnessValue setEditable: YES];
[_brightnessValue setBezeled: YES];
@@ -197,7 +197,7 @@
[_hexLabel setTextColor:[CPColor blackColor]];
//hex input box
_hexValue = [[CPTextField alloc] initWithFrame: CGRectMake(32, 225, 80, 29)];
_hexValue = [[CPTextField alloc] initWithFrame: CGRectMake(32, 225, 80, 28)];
[_hexValue setEditable: YES];
[_hexValue setBezeled: YES];
[_hexValue setDelegate: self];
+45 -10
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;
@@ -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;
}
/*!
+75 -31
View File
@@ -72,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"]];
}
@@ -259,6 +259,32 @@ var CPSplitViewHorizontalImage = nil,
[self drawDividerInRect:[self rectOfDividerAtIndex:count]];
}
}
/*!
@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.
@@ -286,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 = "";
}
}
@@ -713,41 +739,59 @@ var CPSplitViewHorizontalImage = nil,
Sets the delegate of the receiver.
Possible delegate methods to implement are listed below.
<pre>
- (void)splitViewDidResizeSubviews:(CPSplitView)aSplitView;
Notifies the delegate when the subviews have resized.
Notifies the delegate when the subviews have resized.
@code
- (void)splitViewDidResizeSubviews:(CPNotification)aNotification;
@endcode
- (void)splitViewWillResizeSubviews:(CPSplitView)aSplitView;
Notifies the delegate when the subviews will be resized.
Notifies the delegate when the subviews will be resized.
@code
- (void)splitViewWillResizeSubviews:(CPNotification)aNotification;
@endcode
- (CGRect)splitView:(CPSplitView)aSplitView effectiveRect:(CGRect)aRect forDrawnRect:(CGRect)aDrawnRect ofDividerAtIndex:(int)aDividerIndex;
Lets the delegate specify a different rect for which the user can drag the splitView divider.
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
- (CGRect)splitView:(CPSplitView)aSplitView additionalEffectiveRectOfDividerAtIndex:(int)indexOfDivider;
Lets the delegate specify an additional rect for which the user can drag the splitview divider.
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
- (BOOL)splitView:(CPSplitView)aSplitView canCollapseSubview:(CPView)aSubview;
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.
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
- (BOOL)splitView:(CPSplitView)aSplitView shouldCollapseSubview:(CPView)aSubview;
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 should be collapsed, otherwise NO.
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
- (float)splitView:(CPSplitView)aSpiltView constrainSplitPosition:(float)proposedPosition ofSubviewAt:(int)subviewIndex;
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.
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
- (float)splitView:(CPSplitView)aSplitView constrainMinCoordinate:(float)proposedMin ofSubviewAt:(int)subviewIndex;
Allows the delegate to constrain the minimum position of a subview.
Allows the delegate to constrain the minimum position of a subview.
@code
- (float)splitView:(CPSplitView)aSplitView constrainMinCoordinate:(float)proposedMin ofSubviewAt:(int)subviewIndex;
@endcode
- (float)splitView:(CPSplitView)aSplitView constrainMaxCoordinate:(float)proposedMax ofSubviewAt:(int)subviewIndex;
Allows the delegate to constrain the maximum position of a subview.
Allows the delegate to constrain the maximum position of a subview.
@code
- (float)splitView:(CPSplitView)aSplitView constrainMaxCoordinate:(float)proposedMax ofSubviewAt:(int)subviewIndex;
@endcode
- (void)splitView:(CPSplitView)aSplitView resizeSubviewsWithOldSize:(CGSize)oldSize;
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.
</pre>
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.
*/
+4 -102
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:)];
@@ -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
+47 -2
View File
@@ -16,6 +16,14 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
CPTabViewWillSelectTabViewItemSelector = 4,
CPTabViewDidChangeNumberOfTabViewItemsSelector = 8;
/*!
@ingroup appkit
@class CPTabView
A CPTabView object presents a tabbed interface where each page is one a
complete view hiearchy of its own. The user can navigate between various
pages by clicking on the tab headers.
*/
@implementation CPTabView : CPView
{
CPArray _items;
@@ -26,6 +34,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
CPNumber _selectedIndex;
CPTabViewType _type;
CPFont _font;
id _delegate;
unsigned _delegateSelectors;
@@ -74,8 +83,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
}
/*!
Inserts a CPTabViewItem into the tab view
at the specified index.
Inserts a CPTabViewItem into the tab view at the specified index.
@param aTabViewItem the item to insert
@param anIndex the index for the item
*/
@@ -121,6 +129,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
/*!
Returns the index of the specified item
@param aTabViewItem the item to find the index for
@return the index of aTabViewItem or CPNotFound
*/
- (int)indexOfTabViewItem:(CPTabViewItem)aTabViewItem
{
@@ -130,6 +139,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
/*!
Returns the index of the CPTabViewItem with the specified identifier.
@param anIdentifier the identifier of the item
@return the index of the tab view item identified by anIdentifier, or CPNotFound
*/
- (int)indexOfTabViewItemWithIdentifier:(CPString)anIdentifier
{
@@ -142,6 +152,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
/*!
Returns the number of items in the tab view.
@return the number of tab view items in the receiver
*/
- (unsigned)numberOfTabViewItems
{
@@ -150,6 +161,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
/*!
Returns the CPTabViewItem at the specified index.
@return a tab view item, or nil
*/
- (CPTabViewItem)tabViewItemAtIndex:(unsigned)anIndex
{
@@ -158,6 +170,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
/*!
Returns the array of items that backs this tab view.
@return a copy of the array of items in the receiver
*/
- (CPArray)tabViewItems
{
@@ -261,12 +274,36 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
/*!
Returns the current item being displayed.
@return the tab view item currenly being displayed by the receiver
*/
- (CPTabViewItem)selectedTabViewItem
{
return [_items objectAtIndex:_selectedIndex];
}
// Modifying the font
/*!
Returns the font for tab label text.
@return the font for tab label text
*/
- (CPFont)font
{
return _font;
}
/*!
Sets the font for tab label text to font.
@param font the font the receiver should use for tab label text
*/
- (void)setFont:(CPFont)font
{
if ([_font isEqual:font])
return;
_font = font;
[_tabs setFont:_font];
}
//
/*!
Sets the tab view type.
@@ -314,6 +351,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
/*!
Returns the tab view type.
@return the tab view type of the receiver
*/
- (CPTabViewType)tabViewType
{
@@ -322,6 +360,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
/*!
Returns the receiver's delegate.
@return the receiver's delegate
*/
- (id)delegate
{
@@ -415,6 +454,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1,
var CPTabViewItemsKey = "CPTabViewItemsKey",
CPTabViewSelectedItemKey = "CPTabViewSelectedItemKey",
CPTabViewTypeKey = "CPTabViewTypeKey",
CPTabViewFontKey = "CPTabViewFontKey",
CPTabViewDelegateKey = "CPTabViewDelegateKey";
@implementation CPTabView (CPCoding)
@@ -425,12 +465,16 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
{
[self _init];
_font = [aCoder decodeObjectForKey:CPTabViewFontKey];
[_tabs setFont:_font];
_items = [aCoder decodeObjectForKey:CPTabViewItemsKey];
[self _updateItems];
[self _repositionTabs];
var selected = [aCoder decodeObjectForKey:CPTabViewSelectedItemKey];
if (selected)
[self selectTabViewItem:selected];
@@ -450,6 +494,7 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
[aCoder encodeObject:[self selectedTabViewItem] forKey:CPTabViewSelectedItemKey];
[aCoder encodeInt:_type forKey:CPTabViewTypeKey];
[aCoder encodeObject:_font forKey:CPTabViewFontKey];
[aCoder encodeConditionalObject:_delegate forKey:CPTabViewDelegateKey];
}
+61 -18
View File
@@ -326,39 +326,38 @@ CPTableColumnUserResizingMask = 1 << 1;
}
/*!
<pre>
This method sets the "prototype" view which will be used to create all table cells in this column.
It creates a snapshot of aView, using keyed archiving, which is then copied over and over for each
individual cell that is shown. As a result, changes made after calling this method won't be reflected.
When you set a dataview and it is added to the tableview the theme state will be set to CPThemeStateTableDataView
When the dataview becomes selected the theme state will be set to CPThemeStateSelectedDataView.
If the dataview shows up in a group row of the tableview the theme state will be set to CPThemeStateGroupRow.
You should overide setThemeState: and unsetThemeState: to handle these theme state changes in your dataview.
Example:
@code
[tableColumn setDataView:someView]; // snapshot taken
[[tableColumn dataView] setSomething:x]; //won't work
@endcode
This doesn't work because the snapshot is taken before the new property is applied. Instead, do:
@code
[someView setSomething:x];
[tableColumn setDataView:someView];
@endcode
REMEMBER: you should implement CPKeyedArchiving otherwise you might see unexpected results.
@note you should implement CPKeyedArchiving otherwise you might see unexpected results.
This is done by adding the following methods to your class:
@endnote
@code
- (id)initWithCoder(CPCoder)aCoder;
- (void)encodeWithCoder:(CPCoder)aCoder;
@endcode
Example:
Say you have two instance variables in your object that need to be set up each time an object is create.
We will call these instance variables "image" and "text".
Your CPCoding methods will look like the following:
@code
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
@@ -379,7 +378,16 @@ CPTableColumnUserResizingMask = 1 << 1;
[aCoder encodeObject:image forKey:"MyDataViewImage"];
[aCoder encodeObject:text forKey:"MyDataViewText"];
}
</pre>
@endcode
@section Themeing
When you set a dataview and it is added to the tableview the theme state will be set to \c CPThemeStateTableDataView
When the dataview becomes selected the theme state will be set to \c CPThemeStateSelectedDataView.
If the dataview shows up in a group row of the tableview the theme state will be set to \c CPThemeStateGroupRow.
You should overide \c setThemeState: and \c unsetThemeState: to handle these theme state changes in your dataview.
*/
- (void)setDataView:(CPView)aView
{
@@ -420,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])
@@ -466,7 +474,7 @@ CPTableColumnUserResizingMask = 1 << 1;
/*!
Returns YES if the user can edit cells associated with the receiver by double-clicking the
column in the NSTableView, NO otherwise.
column in the CPTableView, NO otherwise.
*/
- (BOOL)isEditable
{
@@ -592,7 +600,7 @@ CPTableColumnUserResizingMask = 1 << 1;
/*!
@ignore
*/
- (void)prepareDataView:(CPView)aDataView forRow:(unsigned)aRow
- (void)_prepareDataView:(CPView)aDataView forRow:(unsigned)aRow
{
var bindingsDictionary = [CPBinder allBindingsForObject:self],
keys = [bindingsDictionary allKeys];
@@ -638,6 +646,41 @@ 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;
@@ -695,9 +738,9 @@ var CPTableColumnIdentifierKey = @"CPTableColumnIdentifierKey",
{
[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];
+10 -11
View File
@@ -212,7 +212,7 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
- (CGRect)headerRectOfColumn:(int)aColumnIndex
{
var headerRect = [self bounds],
var headerRect = CGRectMakeCopy([self bounds]),
columnRect = [_tableView rectOfColumn:aColumnIndex];
headerRect.origin.x = _CGRectGetMinX(columnRect);
@@ -592,15 +592,15 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
for (var i = 0; i < count; i++)
{
var column = [tableColumns objectAtIndex:i],
headerView = [column headerView];
headerView = [column headerView],
frame = [self headerRectOfColumn:i];
var frame = [self headerRectOfColumn:i];
// Make space for the gridline on the right.
frame.origin.x -= 0.5;
frame.size.width -= 1.0;
frame.size.height -= 0.5;
if (i > 0)
{
frame.origin.x += 0.5;
frame.size.width -= 1;
}
// Note: we're not adding in intercell spacing here. This setting only affects the regular
// table cell data views, not the header. Verified in Cocoa on March 29th, 2011.
[headerView setFrame:frame];
@@ -642,10 +642,9 @@ var _CPTableColumnHeaderViewStringValueKey = @"_CPTableColumnHeaderViewStringVal
columnMaxX = _CGRectGetMaxX(columnToStroke);
CGContextMoveToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(_CGRectGetMinY(columnToStroke)));
CGContextAddLineToPoint(context, ROUND(columnMaxX) + 0.5, ROUND(_CGRectGetMaxY(columnToStroke)));
CGContextMoveToPoint(context, FLOOR(columnMaxX) - 0.5, ROUND(_CGRectGetMinY(columnToStroke)));
CGContextAddLineToPoint(context, FLOOR(columnMaxX) - 0.5, ROUND(_CGRectGetMaxY(columnToStroke)));
}
CGContextClosePath(context);
CGContextStrokePath(context);
+375 -255
View File
@@ -136,110 +136,112 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
CPTableView object displays record-oriented data in a table and
allows the user to edit values and resize and rearrange columns.
A CPTableView requires you to either set a data source which implements
numberOfRowsInTableView: and tableView:objectValueForTableColumn:row:,
@ref numberofrows "numberOfRowsInTableView:" and @ref objectValueForTable "tableView:objectValueForTableColumn:row:",
or alternatively to provide data through Key Value Bindings.
To use a table view with Key Value Bindings, bind each column's
CPValueBinding to an array.field path - typically this would be to a path
in an array controller like "arrangedObjects.X", where X is the name of a
field. Optionally also bind the table's "selectionIndexes" and
"sortDescriptors" to the array controller.
\c CPValueBinding to an \c array.field path - typically this would be to a path
in an array controller like \c arrangedObjects.X, where \c X is the name of a
field. Optionally also bind the table's \c selectionIndexes and
\c sortDescriptors to the array controller.
All delegate and data source methods are documented in the setDataSource: and setDelegate: methods.
All delegate and data source methods are documented in the @ref setdatasource "setDataSource:" and @ref setdelegate "setDelegate:" methods.
If you want to display something other than just text in the table you should call setDataView: on a CPTableColumn object. More documentation in that class including theme states.
If you want to display something other than just text in the table you should call @link CPTableColumn::setDataView: setDataView:@endlink on a CPTableColumn object. More documentation in that class including theme states.
@note CPTableView does not contain its own scrollview. You should be sure you place the tableview in a CPScrollView on your own.
Note: CPTableView does not contain its own scrollview. You should be sure you place the tableview in a CPScrollView on your own.
*/
@implementation CPTableView : CPControl
{
id _dataSource;
CPInteger _implementedDataSourceMethods;
id _dataSource;
CPInteger _implementedDataSourceMethods;
id _delegate;
CPInteger _implementedDelegateMethods;
id _delegate;
CPInteger _implementedDelegateMethods;
CPArray _tableColumns;
CPArray _tableColumnRanges;
CPInteger _dirtyTableColumnRangeIndex;
CPInteger _numberOfHiddenColumns;
CPArray _tableColumns;
CPArray _tableColumnRanges;
CPInteger _dirtyTableColumnRangeIndex;
CPInteger _numberOfHiddenColumns;
BOOL _reloadAllRows;
Object _objectValues;
BOOL _reloadAllRows;
Object _objectValues;
CGRect _exposedRect;
CPIndexSet _exposedRows;
CPIndexSet _exposedColumns;
CGRect _exposedRect;
CPIndexSet _exposedRows;
CPIndexSet _exposedColumns;
Object _dataViewsForTableColumns;
Object _cachedDataViews;
Object _dataViewsForTableColumns;
Object _cachedDataViews;
//Configuring Behavior
BOOL _allowsColumnReordering;
BOOL _allowsColumnResizing;
BOOL _allowsColumnSelection;
BOOL _allowsMultipleSelection;
BOOL _allowsEmptySelection;
BOOL _allowsColumnReordering;
BOOL _allowsColumnResizing;
BOOL _allowsColumnSelection;
BOOL _allowsMultipleSelection;
BOOL _allowsEmptySelection;
CPArray _sortDescriptors;
CPArray _sortDescriptors;
//Setting Display Attributes
CGSize _intercellSpacing;
float _rowHeight;
CGSize _intercellSpacing;
float _rowHeight;
BOOL _usesAlternatingRowBackgroundColors;
CPArray _alternatingRowBackgroundColors;
BOOL _usesAlternatingRowBackgroundColors;
CPArray _alternatingRowBackgroundColors;
unsigned _selectionHighlightStyle;
CPTableColumn _currentHighlightedTableColumn;
unsigned _gridStyleMask;
unsigned _selectionHighlightStyle;
CPTableColumn _currentHighlightedTableColumn;
unsigned _gridStyleMask;
unsigned _numberOfRows;
CPIndexSet _groupRows;
unsigned _numberOfRows;
CPIndexSet _groupRows;
CPArray _cachedRowHeights;
CPArray _cachedRowHeights;
// Persistence
CPString _autosaveName;
BOOL _autosaveTableColumns;
CPString _autosaveName;
BOOL _autosaveTableColumns;
CPTableHeaderView _headerView;
_CPCornerView _cornerView;
CPTableHeaderView _headerView;
_CPCornerView _cornerView;
CPIndexSet _selectedColumnIndexes;
CPIndexSet _selectedRowIndexes;
CPInteger _selectionAnchorRow;
CPInteger _lastSelectedRow;
CPIndexSet _previouslySelectedRowIndexes;
CGPoint _startTrackingPoint;
CPDate _startTrackingTimestamp;
BOOL _trackingPointMovedOutOfClickSlop;
CGPoint _editingCellIndex;
CPIndexSet _selectedColumnIndexes;
CPIndexSet _selectedRowIndexes;
CPInteger _selectionAnchorRow;
CPInteger _lastSelectedRow;
CPIndexSet _previouslySelectedRowIndexes;
CGPoint _startTrackingPoint;
CPDate _startTrackingTimestamp;
BOOL _trackingPointMovedOutOfClickSlop;
CGPoint _editingCellIndex;
_CPTableDrawView _tableDrawView;
_CPTableDrawView _tableDrawView;
SEL _doubleAction;
CPInteger _clickedRow;
unsigned _columnAutoResizingStyle;
SEL _doubleAction;
CPInteger _clickedRow;
unsigned _columnAutoResizingStyle;
int _lastTrackedRowIndex;
CGPoint _originalMouseDownPoint;
BOOL _verticalMotionCanDrag;
unsigned _destinationDragStyle;
BOOL _isSelectingSession;
CPIndexSet _draggedRowIndexes;
int _lastTrackedRowIndex;
CGPoint _originalMouseDownPoint;
BOOL _verticalMotionCanDrag;
unsigned _destinationDragStyle;
BOOL _isSelectingSession;
CPIndexSet _draggedRowIndexes;
BOOL _wasSelectionBroken;
_CPDropOperationDrawingView _dropOperationFeedbackView;
CPDragOperation _dragOperationDefaultMask;
int _retargetedDropRow;
CPDragOperation _retargetedDropOperation;
CPDragOperation _dragOperationDefaultMask;
int _retargetedDropRow;
CPDragOperation _retargetedDropOperation;
BOOL _disableAutomaticResizing @accessors(property=disableAutomaticResizing);
BOOL _lastColumnShouldSnap;
BOOL _implementsCustomDrawRow;
BOOL _disableAutomaticResizing @accessors(property=disableAutomaticResizing);
BOOL _lastColumnShouldSnap;
BOOL _implementsCustomDrawRow;
CPTableColumn _draggedColumn;
CPArray _differedColumnDataToRemove;
CPTableColumn _draggedColumn;
CPArray _differedColumnDataToRemove;
}
/*!
@@ -291,11 +293,8 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
[self setGridColor:[CPColor colorWithHexString:@"dce0e2"]];
[self setGridStyleMask:CPTableViewGridNone];
_headerView = [[CPTableHeaderView alloc] initWithFrame:CGRectMake(0, 0, [self bounds].size.width, _rowHeight)];
[_headerView setTableView:self];
_cornerView = nil; //[[_CPCornerView alloc] initWithFrame:CGRectMake(0, 0, [CPScroller scrollerWidth], CGRectGetHeight([_headerView frame]))];
[self setHeaderView:[[CPTableHeaderView alloc] initWithFrame:_CGRectMake(0, 0, [self bounds].size.width, _rowHeight)]];
[self setCornerView:[[_CPCornerView alloc] initWithFrame:_CGRectMake(0, 0, [CPScroller scrollerWidth], _CGRectGetHeight([_headerView frame]))]];
_currentHighlightedTableColumn = nil;
@@ -342,14 +341,14 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
_dirtyTableColumnRangeIndex = 0;
_numberOfHiddenColumns = 0;
_objectValues = { };
_dataViewsForTableColumns = { };
_dataViews = [];
_numberOfRows = 0;
_exposedRows = [CPIndexSet indexSet];
_exposedColumns = [CPIndexSet indexSet];
_cachedDataViews = { };
_cachedRowHeights = [];
_objectValues = { };
_dataViewsForTableColumns = { };
_dataViews = [];
_numberOfRows = 0;
_exposedRows = [CPIndexSet indexSet];
_exposedColumns = [CPIndexSet indexSet];
_cachedDataViews = { };
_cachedRowHeights = [];
_groupRows = [CPIndexSet indexSet];
@@ -357,14 +356,6 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
[_tableDrawView setBackgroundColor:[CPColor clearColor]];
[self addSubview:_tableDrawView];
if (!_headerView)
_headerView = [[CPTableHeaderView alloc] initWithFrame:CGRectMake(0, 0, [self bounds].size.width, _rowHeight)];
[_headerView setTableView:self];
if (!_cornerView)
_cornerView = [[_CPCornerView alloc] initWithFrame:CGRectMake(0, 0, [CPScroller scrollerWidth], CGRectGetHeight([_headerView frame]))];
_draggedColumn = nil;
/* //gradients for the source list when CPTableView is NOT first responder or the window is NOT key
@@ -380,47 +371,69 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
}
/*!
<pre>
@anchor setdatasource
Sets the receiver's data source to a given object.
The data source implements various methods for handling the tableview's data when bindings are not used.
Methods include:
- (int)numberOfRowsInTableView:(CPTableView)aTableView;
Returns the number of rows in the tableview
- (id)tableView:(CPTableView)aTableView objectValueForTableColumn:(CPTableColumn)aColumn row:(int)aRowIndex;
Returns the object value for each dataview. Each dataview will be sent a setObjectValue: method which will contain
the object you return from this datasource method.
Editing:
- (void)tableView:(CPTableView)aTableView setObjectValue:(id)anObject forTableColumn:(CPTableColumn)aTableColumn row:(int)rowIndex;
Sets the data object for an item in a given row and column. This needs to be implemented if you want inline editing support
Sorting:
- (void)tableView:(CPTableView)aTableView sortDescriptorsDidChange:(CPArray)oldDescriptors;
The tableview 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 tableview to receive drops don't forget to first register the tableview for drag types like you do with every other view
- (CPDragOperation)tableView:(CPTableView)aTableView validateDrop:(CPDraggingInfo)info proposedRow:(int)row proposedDropOperation:(CPTableViewDropOperation)operation;
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 -(void)setDropRow:(int)aRow dropOperation:(CPTableViewDropOperation)anOperation;
- (BOOL)tableView:(CPTableView)aTableView writeRowsWithIndexes:(CPIndexSet)rowIndexes toPasteboard:(CPPasteboard)pboard;
Returns YES if the drop operation is allowed otherwise NO.
This method is invoked by the tableview 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.
- (BOOL)tableView:(CPTableView)aTableView acceptDrop:(CPDraggingInfo)info row:(int)row dropOperation:(CPTableViewDropOperation)operation;
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.
- (CPArray)tableView:(CPTableView)aTableView namesOfPromisedFilesDroppedAtDestination:(CPURL)dropDestination forDraggedRowsWithIndexes:(CPIndexSet)indexSet;
NOT YET IMPLEMENTED
</pre>
@param anObject The data source for the receiver. This object must implement numberOfRowsInTableView: and tableView:objectValueForTableColumn:row:
These methods are outlined below.
@section overview Overview
CPTableView generally requires a datasource to run. This data source can be thought of just like a delegate, but specifically for the tableview data.
Methods include:
@section required Required Methods
@anchor numberofrows
Returns the number of rows in the tableview
@code
- (int)numberOfRowsInTableView:(CPTableView)aTableView;
@endcode
Returns the object value for each dataview. Each dataview will be sent a setObjectValue: method which will contain the object you return from this datasource method.
@anchor objectValueForTable
@code
- (id)tableView:(CPTableView)aTableView objectValueForTableColumn:(CPTableColumn)aColumn row:(int)aRowIndex;
@endcode
@section editing Editing:
Sets the data object for an item in a given row and column. This needs to be implemented if you want inline editing support
@code
- (void)tableView:(CPTableView)aTableView setObjectValue:(id)anObject forTableColumn:(CPTableColumn)aTableColumn row:(int)rowIndex;
@endcode
@section sorting Sorting:
The tableview 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
@code
- (void)tableView:(CPTableView)aTableView sortDescriptorsDidChange:(CPArray)oldDescriptors;
@endcode
@section draganddrop Drag and Drop:
@note In order for the tableview to receive drops don't forget to first register the tableview for drag types like you do with every other view.
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)setDropRow:(int)aRow dropOperation:(CPTableViewDropOperation)anOperation;</pre>
@code
- (CPDragOperation)tableView:(CPTableView)aTableView validateDrop:(CPDraggingInfo)info proposedRow:(int)row proposedDropOperation:(CPTableViewDropOperation)operation;
@endcode
Returns YES if the drop operation is allowed otherwise NO. This method is invoked by the tableview 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)tableView:(CPTableView)aTableView writeRowsWithIndexes:(CPIndexSet)rowIndexes toPasteboard:(CPPasteboard)pboard;
@endcode
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)tableView:(CPTableView)aTableView acceptDrop:(CPDraggingInfo)info row:(int)row dropOperation:(CPTableViewDropOperation)operation;
@endcode
NOT YET IMPLEMENTED
@code
- (CPArray)tableView:(CPTableView)aTableView namesOfPromisedFilesDroppedAtDestination:(CPURL)dropDestination forDraggedRowsWithIndexes:(CPIndexSet)indexSet;
@endcode
*/
- (void)setDataSource:(id)aDataSource
{
@@ -555,7 +568,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
/*!
Passing YES will allow the user to resize columns. Passing NO will keep the table columns unmovable by the user.
Note the this does not affect autoresizing behavior.
@note The this does not affect autoresizing behavior.
*/
- (void)setAllowsColumnResizing:(BOOL)shouldAllowColumnResizing
{
@@ -649,13 +662,6 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
[self reloadData];
}
/*!
@ignore
*/
- (void)setThemeState:(int)aState
{
}
/*!
Returns the intercell spacing in a CGSize object.
*/
@@ -666,7 +672,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
/*!
Sets the height of each row.
NOTE: This may still used even if variable row height is being used.
@note This may still used even if variable row height is being used.
@param aRowHeight the height of each row
*/
@@ -730,9 +736,10 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
/*!
Returns an enumerated value for the selection highlight style.
<pre>
Valid values are:
<pre>
CPTableViewSelectionHighlightStyleNone
CPTableViewSelectionHighlightStyleRegular
CPTableViewSelectionHighlightStyleSourceList
@@ -744,11 +751,11 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
}
/*!
<pre>
Sets the selection highlight style to an enumerated value.
This value can also affect the way the tableview draws feedback when the user is dragging.
Valid values are:
<pre>
CPTableViewSelectionHighlightStyleNone
CPTableViewSelectionHighlightStyleRegular
CPTableViewSelectionHighlightStyleSourceList
@@ -790,10 +797,11 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
}
/*!
<pre>
Sets the highlight gradient for a row or column selection
This is specific to the
@param aDictionary a CPDictionary expects three keys to be set:
<pre>
CPSourceListGradient which is a CGGradient
CPSourceListTopLineColor which is a CPColor
CPSourceListBottomLineColor which is a CPColor
@@ -807,8 +815,8 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
}
/*!
<pre>
Returns a dictionary of containing the keys:
<pre>
CPSourceListGradient
CPSourceListTopLineColor
CPSourceListBottomLineColor
@@ -1351,7 +1359,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
[self selectColumnIndexes:[CPIndexSet indexSet] byExtendingSelection:NO];
}
/*
/*!
Returns the number of columns in the table
*/
- (int)numberOfColumns
@@ -1359,7 +1367,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
return NUMBER_OF_COLUMNS();
}
/*
/*!
Returns the number of rows in the receiver.
*/
- (int)numberOfRows
@@ -1377,7 +1385,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
_numberOfRows = [[destination valueForKeyPath:keyPath] count];
}
else if (_dataSource && (_implementedDataSourceMethods & CPTableViewDataSource_numberOfRowsInTableView_))
_numberOfRows = [_dataSource numberOfRowsInTableView:self];
_numberOfRows = [_dataSource numberOfRowsInTableView:self] || 0;
else
{
if (_dataSource)
@@ -1455,7 +1463,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
_cornerView = aView;
var scrollView = [[self superview] superview];
var scrollView = [self enclosingScrollView];
if ([scrollView isKindOfClass:[CPScrollView class]] && [scrollView documentView] === self)
[scrollView _updateCornerAndHeaderView];
@@ -1491,8 +1499,14 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
[_headerView setTableView:self];
[_headerView setFrameSize:_CGSizeMake(_CGRectGetWidth([self frame]), _CGRectGetHeight([_headerView frame]))];
}
else
{
// If there is no header view, there should be no corner view
[_cornerView removeFromSuperview];
_cornerView = nil;
}
var scrollView = [[self superview] superview];
var scrollView = [self enclosingScrollView];
if ([scrollView isKindOfClass:[CPScrollView class]] && [scrollView documentView] === self)
[scrollView _updateCornerAndHeaderView];
@@ -1523,7 +1537,6 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
_numberOfHiddenColumns += 1;
_tableColumnRanges[index] = CPMakeRange(x, 0.0);
}
else
{
var width = [_tableColumns[index] width] + _intercellSpacing.width;
@@ -1583,10 +1596,20 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
if (_implementedDelegateMethods & CPTableViewDelegate_tableView_heightOfRow_)
{
var rowToLookUp = MIN(aRowIndex, lastIndex),
y = _cachedRowHeights[rowToLookUp].heightAboveRow,
height = _cachedRowHeights[rowToLookUp].height + _intercellSpacing.height,
rowDelta = aRowIndex - rowToLookUp;
var rowToLookUp = MIN(aRowIndex, lastIndex);
// if the row doesn't exist
if (rowToLookUp !== CPNotFound)
{
var y = _cachedRowHeights[rowToLookUp].heightAboveRow,
height = _cachedRowHeights[rowToLookUp].height + _intercellSpacing.height,
rowDelta = aRowIndex - rowToLookUp;
}
else
{
y = aRowIndex * (_rowHeight + _intercellSpacing.height);
height = _rowHeight + _intercellSpacing.height;
}
// if we need the rect of a row past the last index
if (rowDelta > 0)
@@ -1812,7 +1835,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
leftInset = FLOOR(_intercellSpacing.width / 2.0),
topInset = FLOOR(_intercellSpacing.height / 2.0);
return _CGRectMake(tableColumnRange.location + leftInset, _CGRectGetMinY(rectOfRow) + topInset, tableColumnRange.length - _intercellSpacing.width, _CGRectGetHeight(rectOfRow) - _intercellSpacing.height);
return _CGRectMake(tableColumnRange.location + leftInset, _CGRectGetMinY(rectOfRow) + topInset, tableColumnRange.length - _intercellSpacing.width, _CGRectGetHeight(rectOfRow) - _intercellSpacing.height);
}
/*!
@@ -1899,7 +1922,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
/*!
@ignore
FIX ME: this is broken
FIX ME: this can be a lot faster
*/
- (void)_resizeAllColumnUniformlyWithOldSize:(CGSize)oldSize
{
@@ -1959,17 +1982,22 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
// now that we've reached the end we know there are likely rounding errors
// so we should size the last resized to fit
var delta = superviewWidth - _CGRectGetMaxX([self rectOfColumn:[self numberOfColumns] - 1]),
// find the last visisble column
while (count-- && [_tableColumns[count] isHidden]) ;
// find the max x, but subtract a single pixel since the spacing isn't applicable here.
var delta = superviewWidth - _CGRectGetMaxX([self rectOfColumn:count]) - ([self intercellSpacing].width || 1),
newSize = [item width] + delta;
[item _tryToResizeToWidth:newSize];
}
/*!
<pre>
Sets the column autoresizing style of the receiver to a given style.
@param aStyle the column autoresizing style for the receiver. Valid values are:
<pre>
CPTableViewNoColumnAutoresizing
CPTableViewUniformColumnAutoresizingStyle
CPTableViewLastColumnOnlyAutoresizingStyle
@@ -2164,8 +2192,8 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
/*!
Set the name under which the table information is automatically saved to theAutosaveName.
The table information is saved separately for each user and for each application that user uses.
Note that even though a table view has an autosave name, it may not be saving table information automatically.
To set whether table information is being saved automatically, use setAutosaveTableColumns:
@note Even though a table view has an autosave name, it may not be saving table information automatically.
To set whether table information is being saved automatically, use \c setAutosaveTableColumns:
*/
- (void)setAutosaveName:(CPString)theAutosaveName
{
@@ -2190,7 +2218,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
Sets whether the order and width of this table view's columns are automatically saved.
The table information is saved separately for each user and for each application that user uses.
Note that if autosaveName returns nil, this setting is ignored and table information isn't saved.
@note that if autosaveName returns nil, this setting is ignored and table information isn't saved.
*/
- (void)setAutosaveTableColumns:(BOOL)shouldAutosave
{
@@ -2278,80 +2306,141 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
/*!
<pre>
Sets the delegate of the receiver. The delegate can implement the following methods:
Displaying Cells
- (void)tableView:(CPTableView)aTableView willDisplayView:(id)aView forTableColumn:(CPTableColumn)aTableColumn row:(int)rowIndex;
Called when the tableview is about to display a dataview
- (BOOL)tableView:(CPTableView)tableView isGroupRow:(int)row;
Group rows are a way to separate a groups of data in a tableview. Return YES if the given row is a group row, otherwise NO.
Editing Cells
- (BOOL)tableView:(CPTableView)aTableView shouldEditTableColumn:(CPTableColumn)aTableColumn row:(int)rowIndex;
Return YES if the dataview at a given index and column should be edited, otherwise NO.
Setting Row and Column Size
- (float)tableView:(CPTableView)tableView heightOfRow:(int)row;
Return the height of the row at a given index. Only implement this if you want variable row heights. Otherwise use setRowHeight: on the tableview.
Selecting in the Tableview
- (BOOL)selectionShouldChangeInTableView:(CPTableView)aTableView;
Return YES if the selection of the tableview should change, otherwise NO to keep the current selection.
NOTE: this is only called via user interaction
- (BOOL)tableView:(CPTableView)aTableView shouldSelectRow:(int)rowIndex;
Return YES if the row at a given index should be selected, other NO to deny the selection.
NOTE: this is only called via user interaction
- (BOOL)tableView:(CPTableView)aTableView shouldSelectTableColumn:(CPTableColumn)aTableColumn;
Return YES if the table column given should be selected, otherwise NO to deny the selection.
NOTE: this is only called via user interaction
- (void)tableViewSelectionIsChanging:(CPNotification)aNotification
Inform the delegate that the tableview is in the process of chaining the selection.
This usually happens when the user is dragging their mouse across rows.
NOTE: this is only called via user interaction
- (void)tableViewSelectionDidChange:(CPNotification)aNotification;
Informs the delegate that the tableview selection has changed.
NOTE: this is only called via user interaction
Moving and Resizing Columns
- (BOOL)tableView:(CPTableView)tableView shouldReorderColumn:(int)columnIndex toColumn:(int)newColumnIndex;
Return YES if the column at a given index should move to a new column index, otherwise NO.
- (void)tableView:(CPTableView)tableView didDragTableColumn:(CPTableColumn)tableColumn;
Notifies the delegate that the tableview drag occurred. This is send on mouse up.
- (void)tableViewColumnDidMove:(CPNotification)aNotification;
Notifies the delegate that a tablecolumn was moved by the user.
- (void)tableViewColumnDidResize:(CPNotification)aNotification
Notifies the delegate that the user resized the table column
Responding to Mouse Events
- (void)tableView:(CPTableView)tableView didClickTableColumn:(CPTableColumn)tableColumn
Sent when the user clicks a table column but doesn't drag.
- (void)tableView:(CPTableView)tableView mouseDownInHeaderOfTableColumn:(CPTableColumn)tableColumn;
Notify the delegate that the user click the table header of a column.
Contextual Menus
- (CPMenu)tableView:(CPTableView)aTableView menuForTableColumn:(CPTableColumn)aColumn row:(int)aRow
Called when the user right clicks on the tableview. -1 is passed for the row or column if the user doesn't right click on a real row or column
Return a CPMenu that should be displayed if the user right clicks. If you do not implement this the tableview will just call super on menuForEvent
Delete Key
- (void)tableViewDeleteKeyPressed:(CPTableView)aTableView;
Called when the user presses the delete key. Many times you will want to delete data (or prompt for deletion) when the user hids the delete key.
Your delegate can implement this method to avoid subclassing the tableview to add this behaviour.
</pre>
@anchor setdelegate
Sets the delegate of the receiver.
@param aDelegate the delegate object for the tableview.
The delegate can provide easy notification for user interaction, display behaviour, contextual menus, and more.
@section displayingcells Displaying Cells:
Called when the tableview is about to display a dataview
@code
- (void)tableView:(CPTableView)aTableView willDisplayView:(id)aView forTableColumn:(CPTableColumn)aTableColumn row:(int)rowIndex;
@endcode
Group rows are a way to separate a groups of data in a tableview. Return YES if the given row is a group row, otherwise NO.
@code
- (BOOL)tableView:(CPTableView)tableView isGroupRow:(int)row;
@endcode
@section editingcells Editing Cells:
Return YES if the dataview at a given index and column should be edited, otherwise NO.
@code
- (BOOL)tableView:(CPTableView)aTableView shouldEditTableColumn:(CPTableColumn)aTableColumn row:(int)rowIndex;
@endcode
@section sizes Setting Row and Column Size:
Return the height of the row at a given index. Only implement this if you want variable row heights. Otherwise use setRowHeight: on the tableview.
@code
- (float)tableView:(CPTableView)tableView heightOfRow:(int)row;
@endcode
@section selection Selecting in the TableView:
@note These methods are only called when the user does something.@endnote
Return YES if the selection of the tableview should change, otherwise NO to keep the current selection.
@code
- (BOOL)selectionShouldChangeInTableView:(CPTableView)aTableView;
@endcode
Return YES if the row at a given index should be selected, other NO to deny the selection.
@code
- (BOOL)tableView:(CPTableView)aTableView shouldSelectRow:(int)rowIndex;
@endcode
Return YES if the table column given should be selected, otherwise NO to deny the selection.
@code
- (BOOL)tableView:(CPTableView)aTableView shouldSelectTableColumn:(CPTableColumn)aTableColumn;
@endcode
Inform the delegate that the tableview is in the process of chaining the selection.
This usually happens when the user is dragging their mouse across rows.
@code
- (void)tableViewSelectionIsChanging:(CPNotification)aNotification
@endcode
Informs the delegate that the tableview selection has changed.
@code
- (void)tableViewSelectionDidChange:(CPNotification)aNotification;
@endcode
@section movingandresizingcolumsn Moving and Resizing Columns:
Return YES if the column at a given index should move to a new column index, otherwise NO.
@code
- (BOOL)tableView:(CPTableView)tableView shouldReorderColumn:(int)columnIndex toColumn:(int)newColumnIndex;
@endcode
Notifies the delegate that the tableview drag occurred. This is send on mouse up.
@code
- (void)tableView:(CPTableView)tableView didDragTableColumn:(CPTableColumn)tableColumn;
@endcode
Notifies the delegate that a tablecolumn was moved by the user.
@code
- (void)tableViewColumnDidMove:(CPNotification)aNotification;
@endcode
Notifies the delegate that the user resized the table column
@code
- (void)tableViewColumnDidResize:(CPNotification)aNotification;
@endcode
@section mousevents Responding to Mouse Events:
Sent when the user clicks a table column but doesn't drag.
@code
- (void)tableView:(CPTableView)tableView didClickTableColumn:(CPTableColumn)tableColumn;
@endcode
Notify the delegate that the user click the table header of a column.
@code
- (void)tableView:(CPTableView)tableView mouseDownInHeaderOfTableColumn:(CPTableColumn)tableColumn;
@endcode
@section contextualmenus Contextual Menus:
Called when the user right clicks on the tableview. -1 is passed for the row or column if the user doesn't right click on a real row or column
Return a CPMenu that should be displayed if the user right clicks. If you do not implement this the tableview will just call super on menuForEvent
@code
- (CPMenu)tableView:(CPTableView)aTableView menuForTableColumn:(CPTableColumn)aColumn row:(int)aRow;
@endcode
@section deletekey Delete Key
Called when the user presses the delete key. Many times you will want to delete data (or prompt for deletion) when the user hids the delete key.
Your delegate can implement this method to avoid subclassing the tableview to add this behaviour.
@code
- (void)tableViewDeleteKeyPressed:(CPTableView)aTableView;
@endcode
*/
- (void)setDelegate:(id)aDelegate
{
@@ -2735,7 +2824,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
[dataView setObjectValue:[self _objectValueForTableColumn:tableColumn row:row]];
// If the column uses content bindings, allow them to override the objectValueForTableColumn.
[tableColumn prepareDataView:dataView forRow:row];
[tableColumn _prepareDataView:dataView forRow:row];
[view addSubview:dataView];
@@ -2801,7 +2890,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
/*!
Sets the default operation mask for the drag behavior of the table view.
NOTE: isLocal is not implemented.
@note isLocal is not implemented.
*/
- (void)setDraggingSourceOperationMask:(CPDragOperation)mask forLocal:(BOOL)isLocal
{
@@ -2831,11 +2920,11 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
}
/*!
<pre>
Sets the feedback style for when the table is the destination of a drag operation.
This style is used to determine how the tableview looks when it is the receiver of a drag and drop operation.
Can be:
<pre>
CPTableViewDraggingDestinationFeedbackStyleNone
CPTableViewDraggingDestinationFeedbackStyleRegular
CPTableViewDraggingDestinationFeedbackStyleSourceList
@@ -2848,10 +2937,10 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
}
/*!
<pre>
Returns the tableview dragging destination feedback style.
Can be:
<pre>
CPTableViewDraggingDestinationFeedbackStyleNone
CPTableViewDraggingDestinationFeedbackStyleRegular
CPTableViewDraggingDestinationFeedbackStyleSourceList
@@ -3181,7 +3270,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
// This gives the table column an opportunity to apply its bindings.
// It will override the value set above if there is a binding.
[tableColumn prepareDataView:dataView forRow:row];
[tableColumn _prepareDataView:dataView forRow:row];
if (isColumnSelected || [self isRowSelected:row])
[dataView setThemeState:CPThemeStateSelectedDataView];
@@ -3281,7 +3370,12 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
{
_editingCellIndex = nil;
[_dataSource tableView:self setObjectValue:[sender objectValue] forTableColumn:sender.tableViewEditedColumnObj row:sender.tableViewEditedRowIndex];
if (_implementedDataSourceMethods & CPTableViewDataSource_tableView_setObjectValue_forTableColumn_row_)
[_dataSource tableView:self setObjectValue:[sender objectValue] forTableColumn:sender.tableViewEditedColumnObj row:sender.tableViewEditedRowIndex];
// Allow the column binding to do a reverse set. Note that we do this even if the data source method above
// is implemented.
[sender.tableViewEditedColumnObj _reverseSetDataView:sender forRow:sender.tableViewEditedRowIndex];
if ([sender respondsToSelector:@selector(setEditable:)])
[sender setEditable:NO];
@@ -3416,8 +3510,8 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
var exposedRect = [self exposedRect];
[self drawBackgroundInClipRect:exposedRect];
[self drawGridInClipRect:exposedRect];
[self highlightSelectionInClipRect:exposedRect];
[self drawGridInClipRect:exposedRect];
if (_implementsCustomDrawRow)
[self _drawRows:_exposedRows clipRect:exposedRect];
@@ -3426,7 +3520,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
/*!
Draws the background in a given clip rect.
This method should only be overridden if you want something other than a solid color or alternating row colors.
NOTE: this method should not be called directly, instead use setNeedsDisplay:
@note this method should not be called directly, instead use \c setNeedsDisplay:
*/
- (void)drawBackgroundInClipRect:(CGRect)aRect
{
@@ -3480,7 +3574,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
/*!
Draws the grid for the tableview based on the set grid mask in a given clip rect.
NOTE: this method should not be called directly, instead use setNeedsDisplay:
@note this method should not be called directly, instead use setNeedsDisplay:
*/
- (void)drawGridInClipRect:(CGRect)aRect
{
@@ -3538,11 +3632,10 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
minY = _CGRectGetMinY(aRect),
maxY = _CGRectGetMaxY(aRect);
for (; columnArrayIndex < columnArrayCount; ++columnArrayIndex)
{
var columnRect = [self rectOfColumn:columnsArray[columnArrayIndex]],
columnX = _CGRectGetMaxX(columnRect) + 0.5;
columnX = _CGRectGetMaxX(columnRect) - 0.5;
CGContextMoveToPoint(context, columnX, minY);
CGContextAddLineToPoint(context, columnX, maxY);
@@ -3557,7 +3650,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
/*!
Draws the selection with the set selection highlight style in a given clip rect.
You can change the highlight style to a source list style gradient in setSelectionHighlightStyle:
NOTE: this method should not be called directly, instead use setNeedsDisplay:
@note this method should not be called directly, instead use \c setNeedsDisplay:
*/
- (void)highlightSelectionInClipRect:(CGRect)aRect
{
@@ -3576,7 +3669,6 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
[_selectedRowIndexes getIndexes:indexes maxCount:-1 inIndexRange:exposedRange];
}
else if ([_selectedColumnIndexes count] >= 1)
{
rectSelector = @selector(rectOfColumn:);
@@ -3788,7 +3880,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
While this method doesn't do anything in Cappuccino, subclasses can override it to customize the
appearance of a row.
NOTE: tableView:willDisplayView:forTableColumn:row is sent to the delegate before drawing
@note \c tableView:willDisplayView:forTableColumn:row is sent to the delegate before drawing
*/
- (void)drawRow:(CPInteger)row clipRect:(CGRect)rect
{
@@ -3922,7 +4014,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
column = [self columnAtPoint:location],
tableColumn = [[self tableColumns] objectAtIndex:column];
return [[self delegate] tableView:self menuForTableColumn:tableColumn row:row];
return [_delegate tableView:self menuForTableColumn:tableColumn row:row];
}
/*
@@ -4052,10 +4144,12 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
}
}
// Accept either tableView:setObjectValue:forTableColumn:row: delegate method, or a binding.
if (mouseIsUp
&& (_implementedDataSourceMethods & CPTableViewDataSource_tableView_setObjectValue_forTableColumn_row_)
&& !_trackingPointMovedOutOfClickSlop
&& ([[CPApp currentEvent] clickCount] > 1))
&& ([[CPApp currentEvent] clickCount] > 1)
&& ((_implementedDataSourceMethods & CPTableViewDataSource_tableView_setObjectValue_forTableColumn_row_)
|| [self infoForBinding:@"content"]))
{
columnIndex = [self columnAtPoint:lastPoint];
if (columnIndex !== -1)
@@ -4233,6 +4327,9 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
*/
- (CPDragOperation)draggingUpdated:(id)sender
{
_retargetedDropRow = nil;
_retargetedDropOperation = nil;
var location = [self convertPoint:[sender draggingLocation] fromView:nil],
dropOperation = [self _proposedDropOperationAtPoint:location],
numberOfRows = [self numberOfRows],
@@ -4241,6 +4338,8 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
if (_retargetedDropRow !== nil)
row = _retargetedDropRow;
if (_retargetedDropOperation !== nil)
dropOperation = _retargetedDropOperation;
if (dropOperation === CPTableViewDropOn && row >= numberOfRows)
@@ -4478,7 +4577,17 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
/*!
@ignore
Selection behavior depends on two things:
Determines if the selection is broken. A broken selection
is a non-continuous selection of rows.
*/
- (BOOL)_selectionIsBroken
{
return [self selectedRowIndexes]._ranges.length !== 1;
}
/*!
@ignore
Selection behaviour depends on two things:
_lastSelectedRow and the anchored selection (the last row selected by itself)
*/
- (void)_moveSelectionWithEvent:(CPEvent)theEvent upward:(BOOL)shouldGoUpward
@@ -4492,7 +4601,23 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
var extend = (([theEvent modifierFlags] & CPShiftKeyMask) && _allowsMultipleSelection),
i = [self selectedRow];
shouldGoUpward ? i-- : i++;
if ([self _selectionIsBroken])
{
while ([selectedIndexes containsIndex:i])
{
shouldGoUpward ? i-- : i++;
}
_wasSelectionBroken = true;
}
else if (_wasSelectionBroken && ((shouldGoUpward && i !== [selectedIndexes firstIndex]) || (!shouldGoUpward && i !== [selectedIndexes lastindex])))
{
shouldGoUpward ? i = [selectedIndexes firstIndex] - 1 : i = [selectedIndexes lastIndex];
_wasSelectionBroken = false;
}
else
{
shouldGoUpward ? i-- : i++;
}
}
else
{
@@ -4652,11 +4777,6 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey",
_headerView = [aCoder decodeObjectForKey:CPTableViewHeaderViewKey];
_cornerView = [aCoder decodeObjectForKey:CPTableViewCornerViewKey];
// Make sure we unhide the cornerview because a corner view loaded from cib is always hidden
// This might be a bug in IB, or the way we load the NSvFlags might be broken for _NSCornerView
if (_cornerView)
[_cornerView setHidden:NO];
[self setDataSource:[aCoder decodeObjectForKey:CPTableViewDataSourceKey]];
[self setDelegate:[aCoder decodeObjectForKey:CPTableViewDelegateKey]];
+19 -4
View File
@@ -84,7 +84,6 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
CPColor _textFieldBackgroundColor;
id _placeholderString;
BOOL _currentValueIsPlaceholder;
id _delegate;
@@ -804,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];
}
@@ -1002,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
@@ -1023,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
@@ -1403,6 +1414,10 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
newValue = [options objectForKey:CPNotApplicablePlaceholderBindingOption] || @"Not Applicable";
break;
case CPNullMarker:
newValue = [options objectForKey:CPNullPlaceholderBindingOption] || @"";
break;
}
[_source setPlaceholderString:newValue];
+5 -1
View File
@@ -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
+56 -7
View File
@@ -186,6 +186,9 @@ var CPViewFlags = { },
CPView _previousKeyView;
unsigned _viewClassFlags;
// ToolTips
CPString _toolTip @accessors(property=toolTip);
}
/*
@@ -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
@@ -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];
+59 -31
View File
@@ -29,26 +29,38 @@
var CPViewControllerCachedCibs;
/*! @class CPViewController
The CPViewController class provides the fundamental view-management controller for Cappuccino applications.
The basic view controller class supports the presentation of an associated view in addition to basic support
for managing modal views and, in the future, animations. Subclasses such as CPNavigationController and
CPTabBarController provide additional behavior for managing complex hierarchies of view controllers and views.
/*!
@ingroup appkit
@class CPViewController
You use each instance of CPViewController to manage a single view (and hierarchy). For a simple view controller,
this entails managing the view hierarchy responsible for presenting your application content.
A typical view hierarchy consists of a root viewŃa reference to which is available in the view property of this classŃ
and one or more subviews presenting the actual content. In the case of navigation and tab bar controllers, the view
controller manages not only the high-level view hierarchy (which provides the navigation controls) but also one
or more additional view controllers that handle the presentation of the application content.
The CPViewController class provides the fundamental view-management
controller for Cappuccino applications. The basic view controller class
supports the presentation of an associated view in addition to basic
support for managing modal views and, in the future, animations.
Subclasses such as CPNavigationController and CPTabBarController provide
additional behavior for managing complex hierarchies of view controllers
and views.
Unlike UIViewController in Cocoa Touch, a CPViewController does not represent an entire screen of content. You
will add your root view to an existing view or window's content view. You can manage many view controllers
on screen at once. CPViewController is also the preferred way of working with Cibs.
You use each instance of CPViewController to manage a single view (and
hierarchy). For a simple view controller, this entails managing the view
hierarchy responsible for presenting your application content. A typical
view hierarchy consists of a root view, a reference to which is available
in the view property of this class, and one or more subviews presenting
the actual content. In the case of navigation and tab bar controllers, the
view controller manages not only the high-level view hierarchy (which
provides the navigation controls) but also one or more additional view
controllers that handle the presentation of the application content.
Subclasses can override -loadView to create their custom view hierarchy, or specify a cib name to be loaded automatically.
It has methods that are called when a view appears or disappears.
This class is also a good place for delegate & datasource methods, and other controller stuff.
Unlike UIViewController in Cocoa Touch, a CPViewController does not
represent an entire screen of content. You will add your root view to an
existing view or window's content view. You can manage many view
controllers on screen at once. CPViewController is also the preferred way
of working with Cibs.
Subclasses can override -loadView to create their custom view hierarchy,
or specify a cib name to be loaded automatically. It has methods that are
called when a view appears or disappears. This class is also a good place
for delegate & datasource methods, and other controller stuff.
*/
@implementation CPViewController : CPResponder
{
@@ -88,9 +100,14 @@ var CPViewControllerCachedCibs;
}
/*!
The designated initializer. If you subclass CPViewController, you must call the super implementation of this method, even if you aren't using a Cib.
In the specified Cib, the File's Owner proxy should have its class set to your view controller subclass, with the view outlet connected to the main view.
If you pass in a nil Cib name, then you must either call -setView: before -view is invoked, or override -loadView to set up your views.
The designated initializer. If you subclass CPViewController, you must
call the super implementation of this method, even if you aren't using a
Cib.
In the specified Cib, the File's Owner proxy should have its class set to
your view controller subclass, with the view outlet connected to the main
view. If you pass in a nil Cib name, then you must either call -setView:
before -view is invoked, or override -loadView to set up your views.
@param cibNameOrNil The path to the cib to load for the root view or nil to programmatically create views.
@param cibBundleOrNil The bundle that the cib is located in or nil for the main bundle.
@@ -113,14 +130,18 @@ var CPViewControllerCachedCibs;
}
/*!
Programmatically creates the view that the controller manages.
You should never call this method directly. The view controller calls this method when the view property is requested but is nil.
Programmatically creates the view that the controller manages. You should
never call this method directly. The view controller calls this method
when the view property is requested but is nil.
If you create your views manually, you must override this method and use it to create your view and assign it to the view property.
The default implementation for programmatic views is to create a plain view. You can invoke super to utilize this view.
If you create your views manually, you must override this method and use
it to create your view and assign it to the view property. The default
implementation for programmatic views is to create a plain view. You can
invoke super to utilize this view.
If you use Interface Builder to create your views, you initialize the view using the
initWithCibName:bundle: method then you must not override this method. The consequences risk shattering the space-time continuum.
If you use Interface Builder to create your views, you initialize the view
using the initWithCibName:bundle: method then you must not override this
method. The consequences risk shattering the space-time continuum.
Note: The cib loading system is currently synchronous.
*/
@@ -144,8 +165,10 @@ var CPViewControllerCachedCibs;
/*!
Returns the view that the controller manages.
If this property is nil, the controller sends loadView to itself to create the view that it manages.
Subclasses should override the loadView method to create any custom views. The default value is nil.
If this property is nil, the controller sends loadView to itself to create
the view that it manages. Subclasses should override the loadView method
to create any custom views. The default value is nil.
*/
- (CPView)view
{
@@ -183,8 +206,11 @@ var CPViewControllerCachedCibs;
/*!
This method is called after the view controller has loaded its associated views into memory.
This method is called regardless of whether the views were stored in a nib file or created programmatically in the loadView method.
This method is most commonly used to perform additional initialization steps on views that are loaded from cib files.
This method is called regardless of whether the views were stored in a nib
file or created programmatically in the loadView method. This method is
most commonly used to perform additional initialization steps on views
that are loaded from cib files.
*/
- (void)viewDidLoad
{
@@ -194,7 +220,9 @@ var CPViewControllerCachedCibs;
/*!
Manually sets the view that the controller manages.
Setting to nil will cause -loadView to be called on all subsequent calls of -view.
Setting to nil will cause -loadView to be called on all subsequent calls
of -view.
@param aView The view this controller should represent.
*/
+309 -88
View File
@@ -36,55 +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 is a class which allows you to display arbitrary HTML or embed a
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.
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
@@ -93,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];
}
@@ -123,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)
{
@@ -137,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];
@@ -170,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;
@@ -209,75 +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 options are
CPWebViewScrollAppKit and CPWebViewScrollNative.
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];
@@ -289,10 +398,21 @@ 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 webview.
Loads a string of HTML into the receiver.
@param CPString - The string to load.
*/
@@ -302,7 +422,7 @@ CPWebViewScrollNative = 2;
}
/*!
Loads a string of HTML into the webview.
Loads a string of HTML into the receiver.
@param CPString - The string to load.
@param CPURL - The base url of the string. (not implemented)
@@ -310,17 +430,13 @@ CPWebViewScrollNative = 2;
- (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];
@@ -328,15 +444,12 @@ CPWebViewScrollNative = 2;
- (void)_loadMainFrameURL
{
[self _setScrollMode:CPWebViewScrollNative];
[self _startedLoading];
_ignoreLoadStart = YES;
_ignoreLoadEnd = NO;
_url = _mainFrameURL;
_html = null;
_html = nil;
[self _load];
}
@@ -345,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);
@@ -363,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);
@@ -373,6 +502,8 @@ CPWebViewScrollNative = 2;
- (void)_startedLoading
{
_isLoading = YES;
[[CPNotificationCenter defaultCenter] postNotificationName:CPWebViewProgressStartedNotification object:self];
if ([_frameLoadDelegate respondsToSelector:@selector(webView:didStartProvisionalLoadForFrame:)])
@@ -381,15 +512,54 @@ 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.
@@ -570,19 +740,44 @@ CPWebViewScrollNative = 2;
*/
- (BOOL)drawsBackground
{
return _iframe.style.backgroundColor != "";
return _drawsBackground;
}
/*!
Sets whether the webview draws its own background.
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)drawsBackround
- (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
@@ -634,7 +829,11 @@ CPWebViewScrollNative = 2;
*/
- (@action)reload:(id)sender
{
[self _loadMainFrameURL];
// If we're displaying pure HTML, redisplay it.
if(!_url && (_html !== nil))
[self loadHTMLString:_html];
else
[self _loadMainFrameURL];
}
/*!
@@ -789,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;
@@ -815,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
+33 -14
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
*/
@@ -2377,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];
}
/*
@@ -2412,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
@@ -2906,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);
+14 -7
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
{
@@ -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;
}
+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>";
}
+8 -3
View File
@@ -449,23 +449,28 @@ var CALayerRegisteredRunLoopUpdates = nil;
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)
{
@@ -791,7 +796,7 @@ if (_DOMContentsElement && aLayer._zPosition > _DOMContentsElement.style.zIndex)
layer._runLoopUpdateMask = 0;
}
window.loop= false;
window.loop = false;
CALayerRegisteredRunLoopUpdates = nil;
}
+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));
}
+14 -11
View File
@@ -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);
}
/*!
+8 -8
View File
@@ -123,17 +123,17 @@ function CGColorSpaceCreatePattern(aBaseColorSpace)
{
if (aBaseColorSpace)
return _CGColorSpaceCreateWithModel(kCGColorSpaceModelPattern, aBaseColorSpace.count, aBaseColorSpace);
return _CGColorSpaceCreateWithModel(kCGColorSpaceModelPattern, 0, NULL);
}
function CGColorSpaceCreateWithName(aName)
{
var colorSpace = _CGNamedColorSpaces[aName];
if (colorSpace)
return colorSpace;
switch (aName)
{
case kCGColorSpaceGenericGray: return _CGNamedColorSpaces[aName] = _CGColorSpaceCreateWithModel(kCGColorSpaceModelMonochrome, 1, NULL);
@@ -144,7 +144,7 @@ function CGColorSpaceCreateWithName(aName)
case kCGColorSpaceAdobeRGB1998: return _CGNamedColorSpaces[aName] = _CGColorSpaceCreateWithModel(kCGColorSpaceModelRGB, 3, NULL);
case kCGColorSpaceSRGB: return _CGNamedColorSpaces[aName] = _CGColorSpaceCreateWithModel(kCGColorSpaceModelRGB, 3, NULL);
}
return NULL;
}
@@ -214,9 +214,9 @@ function CGColorSpaceRetain(aColorSpace)
function CGColorSpaceStandardizeComponents(aColorSpace, components)
{
var count = aColorSpace.count;
// Standardize the alpha value. We allow the alpha value to have a
// higher precision than other components since it is not ultimately
// Standardize the alpha value. We allow the alpha value to have a
// higher precision than other components since it is not ultimately
// bound to 256 bits like RGB.
STANDARDIZE(components, count, 0, 1, 1000);
@@ -231,7 +231,7 @@ function CGColorSpaceStandardizeComponents(aColorSpace, components)
case kCGColorSpaceModelDeviceN: while (count--)
STANDARDIZE(components, count, 0, 1, 255);
break;
// We don't currently support these color spaces.
case kCGColorSpaceModelIndexed:
case kCGColorSpaceModelLab:
+2 -2
View File
@@ -129,7 +129,7 @@ function CGGStateCreateCopy(aGState)
return { alpha:aGState.alpha, strokeStyle:aGState.strokeStyle, fillStyle:aGState.fillStyle, lineWidth:aGState.lineWidth,
lineJoin:aGState.lineJoin, lineCap:aGState.lineCap, miterLimit:aGState.miterLimit, globalAlpha:aGState.globalAlpha,
blendMode:aGState.blendMode,
shadowOffset:aGState.shadowOffset, shadowBlur:aGState.shadowBlur, shadowColor:aGState.shadowColor, CTM:_CGAffineTransformMakeCopy(aGState.CTM) };
shadowOffset:_CGSizeMakeCopy(aGState.shadowOffset), shadowBlur:aGState.shadowBlur, shadowColor:aGState.shadowColor, CTM:_CGAffineTransformMakeCopy(aGState.CTM) };
}
/*!
@@ -606,7 +606,7 @@ function CGContextStrokeLineSegments(aContext, points, count)
{
var i = 0;
if (arguments["count"] == NULL)
if (count === NULL)
var count = points.length;
CGContextBeginPath(aContext);
+48 -30
View File
@@ -22,12 +22,12 @@
var CANVAS_LINECAP_TABLE = [ "butt", "round", "square" ],
CANVAS_LINEJOIN_TABLE = [ "miter", "round", "bevel" ],
CANVAS_COMPOSITE_TABLE = [ "source-over", "source-over", "source-over", "source-over", "darker",
"lighter", "source-over", "source-over", "source-over", "source-over",
"source-over", "source-over", "source-over", "source-over", "source-over",
"source-over", "source-over",
"copy", "source-in", "source-out", "source-atop",
"destination-over", "destination-in", "destination-out", "destination-atop",
CANVAS_COMPOSITE_TABLE = [ "source-over", "source-over", "source-over", "source-over", "darker",
"lighter", "source-over", "source-over", "source-over", "source-over",
"source-over", "source-over", "source-over", "source-over", "source-over",
"source-over", "source-over",
"copy", "source-in", "source-out", "source-atop",
"destination-over", "destination-in", "destination-out", "destination-atop",
"xor", "source-over", "source-over" ];
#define _CGContextAddArcCanvas(aContext, x, y, radius, startAngle, endAngle, anticlockwise) aContext.arc(x, y, radius, startAngle, endAngle, anticlockwise)
@@ -106,15 +106,15 @@ function CGContextAddPath(aContext, aPath)
return;
var elements = aPath.elements,
i = 0,
count = aPath.count;
for (; i < count; ++i)
{
var element = elements[i],
type = element.type;
switch (type)
{
case kCGPathElementMoveToPoint: _CGContextMoveToPointCanvas(aContext, element.x, element.y);
@@ -143,10 +143,10 @@ function CGContextAddRect(aContext, aRect)
function CGContextAddRects(aContext, rects, count)
{
var i = 0;
if (arguments["count"] == NULL)
if (count === NULL)
var count = rects.length;
for (; i < count; ++i)
{
var rect = rects[i];
@@ -180,7 +180,7 @@ function CGContextDrawPath(aContext, aMode)
aContext.fill();
else if (aMode == kCGPathEOFill || aMode == kCGPathEOFillStroke)
alert("not implemented!!!");
if (aMode == kCGPathStroke || aMode == kCGPathFillStroke || aMode == kCGPathEOFillStroke)
aContext.stroke();
}
@@ -193,10 +193,10 @@ function CGContextFillRect(aContext, aRect)
function CGContextFillRects(aContext, rects, count)
{
var i = 0;
if (arguments["count"] == NULL)
if (count === NULL)
var count = rects.length;
for (; i < count; ++i)
{
var rect = rects[i];
@@ -219,13 +219,13 @@ function CGContextClipToRect(aContext, aRect)
_CGContextBeginPathCanvas(aContext);
_CGContextAddRectCanvas(aContext, aRect);
_CGContextClosePathCanvas(aContext);
_CGContextClipCanvas(aContext);
}
function CGContextClipToRects(aContext, rects, count)
{
if (arguments["count"] == NULL)
if (count === NULL)
var count = rects.length;
_CGContextBeginPathCanvas(aContext);
@@ -240,7 +240,25 @@ function CGContextSetAlpha(aContext, anAlpha)
function CGContextSetFillColor(aContext, aColor)
{
aContext.fillStyle = [aColor cssString];
if ([aColor patternImage])
{
var patternImg = [aColor patternImage],
size = [patternImg size],
img;
if (size)
img = new Image(size.width, size.height);
else
img = new Image();
img.src = [patternImg filename];
var pattern = aContext.createPattern(img, "repeat");
aContext.fillStyle = pattern;
}
else
aContext.fillStyle = [aColor cssString];
}
function CGContextSetStrokeColor(aContext, aColor)
@@ -302,7 +320,7 @@ function CGContextTranslateCTM(aContext, tx, ty)
sx = (abs_cos * a / cos + abs_sin * -c / sin) / (abs_cos + abs_sin);\
sy = (abs_cos * d / cos + abs_sin * b / sin) / (abs_cos + abs_sin);\
}\
#define rotate_scale(a, b, c, d) \
var sign = (a * d < 0.0 || b * c > 0.0) ? -1.0 : 1.0;\
a1 = (Math.atan2(sign * b, sign * a) + Math.atan2(-c, d)) / 2.0,\
@@ -350,7 +368,7 @@ CGContextConcatCTM = function(aContext, anAffineTransform)
{
var a = anAffineTransform.a,
b = anAffineTransform.b,
c = anAffineTransform.c,
c = anAffineTransform.c,
d = anAffineTransform.d,
tx = anAffineTransform.tx,
ty = anAffineTransform.ty,
@@ -365,13 +383,13 @@ CGContextConcatCTM = function(aContext, anAffineTransform)
sx = a;
sy = d;
}
// a scale followed by a rotate
else if (a * b == -c * d)
{
scale_rotate(a, b, c, d)
}
// rotate, then scale.
else if (a * c == -b * d)
{
@@ -384,8 +402,8 @@ CGContextConcatCTM = function(aContext, anAffineTransform)
v = eigen(CGAffineTransformConcat(transpose, anAffineTransform)),
U = CGAffineTransformMake(u.vector_1.x, u.vector_2.x, u.vector_1.y, u.vector_2.y, 0.0, 0.0), // inline
VT = CGAffineTransformMake(v.vector_1.x, v.vector_1.y, v.vector_2.x, v.vector_2.y, 0.0, 0.0),
S = CGAffineTransformConcat(CGAffineTransformConcat(CGAffineTransformInvert(U), anAffineTransform), CGAffineTransformInvert(VT));
S = CGAffineTransformConcat(CGAffineTransformConcat(CGAffineTransformInvert(U), anAffineTransform), CGAffineTransformInvert(VT));
a = VT.a;
b = VT.b;
c = VT.c;
@@ -401,7 +419,7 @@ CGContextConcatCTM = function(aContext, anAffineTransform)
sx = S.a * sx;
sy = S.d * sy;
}
if (tx != 0 || ty != 0)
CGContextTranslateCTM(aContext, tx, ty);
if (a1 != 0.0)
@@ -428,12 +446,12 @@ function CGContextDrawLinearGradient(aContext, aGradient, aStartPoint, anEndPoin
{
var colors = aGradient.colors,
count = colors.length,
linearGradient = aContext.createLinearGradient(aStartPoint.x, aStartPoint.y, anEndPoint.x, anEndPoint.y);
while (count--)
linearGradient.addColorStop(aGradient.locations[count], to_string(colors[count]));
aContext.fillStyle = linearGradient;
aContext.fill();
}
@@ -442,8 +460,8 @@ function CGBitmapGraphicsContextCreate()
{
var DOMElement = document.createElement("canvas"),
context = DOMElement.getContext("2d");
context.DOMElement = DOMElement;
return context;
}
+91 -74
View File
@@ -32,12 +32,21 @@ function CGBitmapGraphicsContextCreate()
// The first time around, we have to set up our environment to support vml.
document.namespaces.add("cg_vml_", "urn:schemas-microsoft-com:vml");
document.createStyleSheet().cssText = "cg_vml_\\:*{behavior:url(#default#VML)}";
CGBitmapGraphicsContextCreate = _CGBitmapGraphicsContextCreate;
return _CGBitmapGraphicsContextCreate();
}
function CGContextSetFillColor(aContext, aColor)
{
if ([aColor patternImage])
// Prefix a marker character to the string so we know it's a pattern image filename
aContext.gState.fillStyle = "!" + [[aColor patternImage] filename];
else
aContext.gState.fillStyle = [aColor cssString];
}
// FIXME: aRect is ignored.
function CGContextClearRect(aContext, aRect)
{
@@ -45,7 +54,7 @@ function CGContextClearRect(aContext, aRect)
aContext.buffer = "";
else
aContext.DOMElement.innerHTML = "";
aContext.path = NULL;
}
@@ -54,12 +63,12 @@ var W = 10.0,
Z = 10.0,
Z_2 = Z / 2.0;
#define COORD(aCoordinate) (ROUND(Z * (aCoordinate) - Z_2))
#define COORD(aCoordinate) (aCoordinate === 0.0 ? 0 : ROUND(Z * (aCoordinate) - Z_2))
function CGContextDrawImage(aContext, aRect, anImage)
{
var string = "";
if (anImage.buffer != nil)
string = anImage.buffer;
else
@@ -68,24 +77,24 @@ function CGContextDrawImage(aContext, aRect, anImage)
origin = CGPointApplyAffineTransform(aRect.origin, ctm),
similarity = ctm.a == ctm.d && ctm.b == -ctm.c,
vml = ["<cg_vml_:group coordsize=\"1,1\" coordorigin=\"0,0\" style=\"width:1;height:1;position:absolute"];
/*if (similarity)
{
var angle = CGPointMake(1.0, 0.0);
angle = _CGPointApplyAffineTransform(angle, ctm);
vml.push(";rotation:", ATAN2(angle.y - ctm.ty, angle.x - ctm.tx) * 180 / PI);
}*/
// Only create a filter if absolutely necessary. This actually
// turns out to only be the case if our transform matrix is not
// a similarity matrix, that is to say, the transform actually
// Only create a filter if absolutely necessary. This actually
// turns out to only be the case if our transform matrix is not
// a similarity matrix, that is to say, the transform actually
// morphs the shape beyond scaling and rotation.
//if (!similarity && (ctm.a != 1.0 || ctm.b || ctm.c || ctm.d != 1.0))
{
var transformedRect = CGRectApplyAffineTransform(aRect, ctm);
vml.push( ";padding:0 ", ROUND(_CGRectGetMaxX(transformedRect)), "px ", ROUND(_CGRectGetMaxY(transformedRect)),
"px 0;filter:progid:DXImageTransform.Microsoft.Matrix(",
"M11='", ctm.a, "',M12='", ctm.c, "',M21='", ctm.b, "',M22='", ctm.d, "',",
@@ -93,14 +102,14 @@ function CGContextDrawImage(aContext, aRect, anImage)
}
//else
// vml.push(";top:", ROUND(origin.y - 0.5), "px;left:", ROUND(origin.x - 0.5), "px;");
vml.push( "\"><cg_vml_:image src=\"", anImage._image.src,
"\" style=\"width:", _CGRectGetWidth(aRect), "px;height:", _CGRectGetHeight(aRect),
vml.push( "\"><cg_vml_:image src=\"", anImage._image.src,
"\" style=\"width:", _CGRectGetWidth(aRect), "px;height:", _CGRectGetHeight(aRect),
"px;\"/></g_vml_:group>");
string = vml.join("");
}
if (aContext.buffer != nil)
aContext.buffer += string;
else
@@ -111,74 +120,77 @@ function CGContextDrawPath(aContext, aMode)
{
if (!aContext || CGPathIsEmpty(aContext.path))
return;
var elements = aContext.path.elements,
i = 0,
count = aContext.path.count,
gState = aContext.gState,
fill = (aMode == kCGPathFill || aMode == kCGPathFillStroke) ? 1 : 0,
stroke = (aMode == kCGPathStroke || aMode == kCGPathFillStroke) ? 1 : 0,
opacity = gState.alpha,
vml = [ "<cg_vml_:shape",
" fillcolor=\"", gState.fillStyle,
"\" filled=\"", VML_TRUTH_TABLE[fill],
"\" style=\"position:absolute;width:", W, ";height:", H,
";\" coordorigin=\"0 0\" coordsize=\"", Z * W, " ", Z * H,
"\" stroked=\"", VML_TRUTH_TABLE[stroke],
"\" strokeweight=\"", gState.lineWidth,
"\" strokecolor=\"", gState.strokeStyle,
"\" path=\""];
vml = ["<cg_vml_:shape"];
if (gState.fillStyle.charAt(0) !== "!")
vml.push(" fillcolor=\"", gState.fillStyle, "\"");
vml.push( " filled=\"", VML_TRUTH_TABLE[fill],
"\" style=\"position:absolute;width:", W, ";height:", H,
";\" coordorigin=\"0 0\" coordsize=\"", Z * W, " ", Z * H,
"\" stroked=\"", VML_TRUTH_TABLE[stroke],
"\" strokeweight=\"", gState.lineWidth,
"\" strokecolor=\"", gState.strokeStyle,
"\" path=\"");
for (; i < count; ++i)
{
var element = elements[i],
type = element.type;
switch(type)
switch (type)
{
case kCGPathElementMoveToPoint:
case kCGPathElementMoveToPoint:
case kCGPathElementAddLineToPoint: vml.push(VML_ELEMENT_TABLE[type], COORD(element.x), ',', COORD(element.y));
break;
case kCGPathElementAddQuadCurveToPoint: vml.push(VML_ELEMENT_TABLE[type],
case kCGPathElementAddQuadCurveToPoint: vml.push(VML_ELEMENT_TABLE[type],
COORD(element.cpx), ',', COORD(element.cpy), ',',
COORD(element.x), ',', COORD(element.y));
break;
case kCGPathElementAddCurveToPoint: vml.push(VML_ELEMENT_TABLE[type],
case kCGPathElementAddCurveToPoint: vml.push(VML_ELEMENT_TABLE[type],
COORD(element.cp1x), ',', COORD(element.cp1y), ',',
COORD(element.cp2x), ',', COORD(element.cp2y), ',',
COORD(element.x), ',', COORD(element.y));
break;
case kCGPathElementCloseSubpath: vml.push(VML_ELEMENT_TABLE[type]);
break;
case kCGPathElementAddArc: var x = element.x,
y = element.y,
radius = element.radius,
clockwise = element.clockwise ? 1 : 0,
endAngle = element.endAngle,
startAngle = element.startAngle,
start = _CGPointMake(x + radius * COS(startAngle), y + radius * SIN(startAngle));
// If the angle's are equal, then we won't actually draw an arc, but instead
// If the angle's are equal, then we won't actually draw an arc, but instead
// simply move to its start/end to get the proper fill.
// We only need this special case for anti-clockwise because start == end is
// We only need this special case for anti-clockwise because start == end is
// interpreted as a full circle with anti-clockwise, but empty for clockwise.
if (startAngle == endAngle && !clockwise)
{
vml.push(VML_ELEMENT_TABLE[kCGPathElementMoveToPoint], COORD(start.x), ',', COORD(start.y));
continue;
}
var end = _CGPointMake(x + radius * COS(endAngle), y + radius * SIN(endAngle));
// Only do the start correction if the angles aren't equal. If they are, then
// Only do the start correction if the angles aren't equal. If they are, then
// let the circle be empty.
// FIXME: Should this be |star.x - end.x| < 0.125 ?
if (clockwise && startAngle != endAngle && _CGPointEqualToPoint(start, end))
@@ -196,10 +208,10 @@ function CGContextDrawPath(aContext, aMode)
else
end.y += 0.125;
}
vml.push(VML_ELEMENT_TABLE[type][clockwise],
COORD(x - radius), ',', COORD(y - radius), " ",
COORD(x + radius), ',', COORD(y + radius), " ",
vml.push(VML_ELEMENT_TABLE[type][clockwise],
COORD(x - radius), ',', COORD(y - radius), " ",
COORD(x + radius), ',', COORD(y + radius), " ",
COORD(start.x), ',', COORD(start.y), " ",
COORD(end.x), ',', COORD(end.y));
break;
@@ -228,31 +240,36 @@ function CGContextDrawPath(aContext, aMode)
}
vml.push("\">");
if (gState.gradient)
vml.push(gState.gradient)
else if (fill)
vml.push("<cg_vml_:fill color=\"", gState.fillStyle, "\" opacity=\"", opacity, "\" />");
{
if (gState.fillStyle.charAt(0) === "!")
vml.push("<cg_vml_:fill type=\"tile\" src=\"", gState.fillStyle.substring(1), "\" opacity=\"", opacity, "\" />");
else // should be a CSS color spec
vml.push("<cg_vml_:fill color=\"", gState.fillStyle, "\" opacity=\"", opacity, "\" />");
}
if (stroke)
vml.push( "<cg_vml_:stroke opacity=\"", opacity,
"\" joinstyle=\"", VML_LINEJOIN_TABLE[gState.lineJoin],
"\" miterlimit=\"", gState.miterLimit,
"\" endcap=\"", VML_LINECAP_TABLE[gState.lineCap],
vml.push( "<cg_vml_:stroke opacity=\"", opacity,
"\" joinstyle=\"", VML_LINEJOIN_TABLE[gState.lineJoin],
"\" miterlimit=\"", gState.miterLimit,
"\" endcap=\"", VML_LINECAP_TABLE[gState.lineCap],
"\" weight=\"", gState.lineWidth, "",
"px\" color=\"", gState.strokeStyle,"\" />");
var shadowColor = gState.shadowColor;
//\"", [shadowColor cssString], "\"
if (shadowColor)
{
var shadowOffset = gState.shadowOffset;
vml.push("<cg_vml_:shadow on=\"t\" offset=\"",
vml.push("<cg_vml_:shadow on=\"t\" offset=\"",
shadowOffset.width, "pt ", shadowOffset.height, "pt\" opacity=\"", [shadowColor alphaComponent], "\" color=black />");
}
vml.push("</cg_vml_:shape>");
if (aContext.buffer != nil)
@@ -270,25 +287,25 @@ function CGContextDrawLinearGradient(aContext, aGradient, aStartPoint, anEndPoin
{
if (!aContext || !aGradient)
return;
var vml = nil;
if (aGradient.vml_gradient)
{
var stops = [[aGradient.vml_gradient stops] sortedArrayUsingSelector:@selector(comparePosition:)],
count = [stops count];
vml = ["<cg_vml_:fill type=\"gradient\" method=\"linear sigma\" "];
vml.push("angle=\"" + ([aGradient.vml_gradient angle] + 90) +"\" ");
vml.push("angle=\"" + ([aGradient.vml_gradient angle] + 90) + "\" ");
vml.push("colors=\"");
for (var i = 0; i < count; i++)
{
vml.push(([stops[i] position]*100).toFixed(0)+"% ");
vml.push(([stops[i] position] * 100).toFixed(0) + "% ");
vml.push([[[stops[i] color] colorForSlideBase:nil] cssString]);
if (i < count-1)
if (i < count - 1)
vml.push(",");
}
@@ -304,13 +321,13 @@ function CGContextDrawLinearGradient(aContext, aGradient, aStartPoint, anEndPoin
vml.push("colors=\"");
for (var i = 0; i < count; i++)
vml.push((aGradient.locations[i]*100).toFixed(0)+"% "+to_string(colors[i])+(i<count-1 ? "," : ""));
vml.push((aGradient.locations[i] * 100).toFixed(0)+"% " + to_string(colors[i])+(i < count - 1 ? "," : ""));
vml.push("\" />");
}
aContext.gState.gradient = vml.join("");
// if (aContext.buffer != nil)
// aContext.buffer += vml.join("");
// else
+9 -4
View File
@@ -29,10 +29,15 @@ kCGGradientDrawsAfterEndLocation = 1 << 1;
function CGGradientCreateWithColorComponents(aColorSpace, components, locations, count)
{
if (arguments["locations"] == NULL)
var locations = [0.0, 1.0];
if ( locations === undefined || locations === NULL )
{
var num_of_colors = components.length / 4,
locations = [];
for ( var idx = 0; idx < num_of_colors; idx++ )
locations.push( idx / (num_of_colors - 1) );
}
if (arguments["count"] == NULL)
if ( count === undefined || count === NULL)
var count = locations.length;
var colors = [];
@@ -58,4 +63,4 @@ function CGGradientRelease()
function CGGradientRetain(aGradient)
{
return aGradient;
}
}
+32 -32
View File
@@ -53,9 +53,9 @@ function CGPathCreateMutable()
function CGPathCreateMutableCopy(aPath)
{
var path = CGPathCreateMutable();
CGPathAddPath(path, aPath);
return path;
}
@@ -99,7 +99,7 @@ function CGPathAddArc(aPath, aTransform, x, y, aRadius, aStartAngle, anEndAngle,
aStartAngle = ATAN2(start.y - aTransform.ty, start.x - aTransform.tx);
// Angles that equal "modulo" 2 pi return as equal after transforming them,
// so we have to make sure to make them different again if they were different
// so we have to make sure to make them different again if they were different
// to start out with. It's the difference between no circle and a full circle.
if (anEndAngle == aStartAngle && oldEndAngle != oldStartAngle)
if (oldStartAngle > oldEndAngle)
@@ -111,7 +111,7 @@ function CGPathAddArc(aPath, aTransform, x, y, aRadius, aStartAngle, anEndAngle,
aRadius = _CGSizeApplyAffineTransform(aRadius, aTransform);
aRadius = SQRT(aRadius.width * aRadius.width + aRadius.height * aRadius.height);
}
aPath.current = _CGPointMake(x + aRadius * COS(anEndAngle), y + aRadius * SIN(anEndAngle));
aPath.elements[aPath.count++] = { type:kCGPathElementAddArc, x:x, y:y, radius:aRadius, startAngle:aStartAngle, endAngle:anEndAngle };
}
@@ -125,14 +125,14 @@ function CGPathAddCurveToPoint(aPath, aTransform, cp1x, cp1y, cp2x, cp2y, x, y)
var cp1 = _CGPointMake(cp1x, cp1y),
cp2 = _CGPointMake(cp2x, cp2y),
end = _CGPointMake(x, y);
if (aTransform)
{
cp1 = _CGPointApplyAffineTransform(cp1, aTransform);
cp2 = _CGPointApplyAffineTransform(cp2, aTransform);
end = _CGPointApplyAffineTransform(end, aTransform);
}
aPath.current = end;
aPath.elements[aPath.count++] = { type:kCGPathElementAddCurveToPoint, cp1x:cp1.x, cp1y:cp1.y, cp2x:cp2.x, cp2y:cp2.y, x:end.x, y:end.y };
}
@@ -140,13 +140,13 @@ function CGPathAddCurveToPoint(aPath, aTransform, cp1x, cp1y, cp2x, cp2y, x, y)
function CGPathAddLines(aPath, aTransform, points, count)
{
var i = 1;
if (arguments["count"] == NULL)
if (count === NULL)
var count = points.length;
if (!aPath || count < 2)
return;
CGPathMoveToPoint(aPath, aTransform, points[0].x, points[0].y);
for (; i < count; ++i)
@@ -156,7 +156,7 @@ function CGPathAddLines(aPath, aTransform, points, count)
function CGPathAddLineToPoint(aPath, aTransform, x, y)
{
var point = _CGPointMake(x, y);
if (aTransform != NULL)
point = _CGPointApplyAffineTransform(point, aTransform);
@@ -204,13 +204,13 @@ function CGPathAddQuadCurveToPoint(aPath, aTransform, cpx, cpy, x, y)
{
var cp = _CGPointMake(cpx, cpy),
end = _CGPointMake(x, y);
if (aTransform)
{
cp = _CGPointApplyAffineTransform(cp, aTransform);
end = _CGPointApplyAffineTransform(end, aTransform);
}
aPath.elements[aPath.count++] = { type:kCGPathElementAddQuadCurveToPoint, cpx:cp.x, cpy:cp.y, x:end.x, y:end.y }
aPath.current = end;
}
@@ -223,19 +223,19 @@ function CGPathAddRect(aPath, aTransform, aRect)
function CGPathAddRects(aPath, aTransform, rects, count)
{
var i = 0;
if (arguments["count"] == NULL)
if (count === NULL)
var count = rects.length;
for (; i < count; ++i)
{
var rect = rects[i];
CGPathMoveToPoint(aPath, aTransform, _CGRectGetMinX(rect), _CGRectGetMinY(rect));
CGPathAddLineToPoint(aPath, aTransform, _CGRectGetMaxX(rect), _CGRectGetMinY(rect));
CGPathAddLineToPoint(aPath, aTransform, _CGRectGetMaxX(rect), _CGRectGetMaxY(rect));
CGPathAddLineToPoint(aPath, aTransform, _CGRectGetMinX(rect), _CGRectGetMaxY(rect));
CGPathCloseSubpath(aPath);
}
}
@@ -244,15 +244,15 @@ function CGPathMoveToPoint(aPath, aTransform, x, y)
{
var point = _CGPointMake(x, y),
count = aPath.count;
if (aTransform != NULL)
point = _CGPointApplyAffineTransform(point, aTransform);
aPath.start = point;
aPath.current = point;
var previous = aPath.elements[count - 1];
if (count != 0 && previous.type == kCGPathElementMoveToPoint)
{
previous.x = point.x;
@@ -338,11 +338,11 @@ function CGPathWithRoundedRectangleInRect(aRect, xRadius, yRadius/*not currently
function CGPathCloseSubpath(aPath)
{
var count = aPath.count;
// Don't bother closing this subpath if there aren't any current elements, or the last element already closed the subpath.
if (count == 0 || aPath.elements[count - 1].type == kCGPathElementCloseSubpath)
return;
aPath.elements[aPath.count++] = { type:kCGPathElementCloseSubpath, points:[aPath.start] };
}
@@ -350,32 +350,32 @@ function CGPathEqualToPath(aPath, anotherPath)
{
if (aPath == anotherPath)
return YES;
if (aPath.count != anotherPath.count || !_CGPointEqualToPoint(aPath.start, anotherPath.start) || !_CGPointEqualToPoint(aPath.current, anotherPath.current))
return NO;
var i = 0,
count = aPath.count;
for (; i < count; ++i)
{
var element = aPath[i],
anotherElement = anotherPath[i];
if (element.type != anotherElement.type)
return NO;
if ((element.type == kCGPathElementAddArc || element.type == kCGPathElementAddArcToPoint) &&
if ((element.type == kCGPathElementAddArc || element.type == kCGPathElementAddArcToPoint) &&
element.radius != anotherElement.radius)
return NO;
var j = element.points.length;
while (j--)
if (!_CGPointEqualToPoint(element.points[j], anotherElement.points[j]))
return NO;
}
return YES;
}
+99
View File
@@ -0,0 +1,99 @@
/*
* CGContextText.j
* CoreText
*
* Created by Nicholas Small.
* Copyright 2011, 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
*/
kCGTextFill = 0;
kCGTextStroke = 1;
kCGTextFillStroke = 2;
kCGTextInvisible = 3;
function CGContextGetTextMatrix(/* CGContext */ aContext)
{
return aContext._textMatrix;
}
function CGContextSetTextMatrix(/* CGContext */ aContext, /* CGAffineTransform */ aTransform)
{
aContext._textMatrix = aTransform;
}
function CGContextGetTextPosition(/* CGContext */ aContext)
{
return aContext._textPosition || _CGPointMakeZero();
}
function CGContextSetTextPosition(/* CGContext */ aContext, /* float */ x, /* float */ y)
{
aContext._textPosition = CGPointMake(x, y);
}
function CGContextGetFont(/* CGContext */ aContext)
{
return aContext._CPFont;
}
function CGContextSelectFont(/* CGContext */ aContext, /* CPFont */ aFont)
{
aContext.font = [aFont cssString];
aContext._CPFont = aFont;
}
function CGContextSetTextDrawingMode(/* CGContext */ aContext, /* CGTextDrawingMode */ aMode)
{
aContext._textDrawingMode = aMode;
}
function CGContextShowText(/* CGContext */ aContext, /* CPString */ aString)
{
CGContextShowTextAtPoint(aContext, aContext._textPosition.x, aContext._textPosition.y, aString);
}
function CGContextShowTextAtPoint(/* CGContext */ aContext, /* float */ x, /* float */ y, /* CPString */ aString)
{
aContext.textBaseline = @"middle";
aContext.textAlign = @"left";
var mode = aContext._textDrawingMode;
if (!mode && mode !== 0)
mode = kCGTextFill;
var width = aContext.measureText(aString).width;
if (mode === kCGTextFill || mode === kCGTextFillStroke)
aContext.fillText(aString, x, y);
if (mode === kCGTextStroke || mode === kCGTextFillStroke)
aContext.strokeText(aString, x, y);
aContext._textPosition = CGPointMake(x + width, y);
}
// FIXME: these are hacks that override the default behavior.
function CGContextSetFillColor(/* CGContext */ aContext, /* CPColor */ aColor)
{
aContext.fillStyle = [aColor cssString];
aContext._CPColor = aColor;
}
function CGContextGetFillColor(/* CGContext */ aContext)
{
return aContext._CPColor;
}
+192
View File
@@ -0,0 +1,192 @@
/*
* CTFrame.j
* CoreText
*
* Created by Nicholas Small.
* Copyright 2011, 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 "CTLine.j"
kCTFrameProgressionTopToBottom = 0;
kCTFrameProgressionRightToLeft = 1;
kCTFrameProgressionAttributeName = @"kCTFrameProgressionAttributeName";
function _CTFrameCreate(aPath, attributes, lines, attributedString)
{
return {
path: aPath,
attributes: attributes,
lines: lines,
string: attributedString
};
}
_CTFrameCreate.displayName = @"_CTFrameCreate";
/*!
Returns the range of the frame based on the original string
FIX ME: This implementation is wrong
*/
function CTFrameGetStringRange(/* CTFrame */ aFrame)
{
return CPMakeRange();
}
CTFrameGetStringRange.displayName = @"CTFrameGetStringRange";
/*!
Returns a range object with the visisble characters
FIX ME: THis implementation is wrong
*/
function CTFrameGetVisibleStringRange(/* CTFrame */ aFrame)
{
return CPMakeRange();
}
CTFrameGetVisibleStringRange.displayName = @"CTFrameGetVisibleStringRange";
/*!
Returns the path for the frame.
*/
function CTFrameGetPath(/* CTFrame */ aFrame)
{
return aFrame.path;
}
CTFrameGetPath.displayName = @"CTFrameGetPath";
/*!
Returns a dictionary of attributes for the frame.
*/
function CTFrameGetFrameAttributes(/* CTFrame */ aFrame)
{
return aFrame.frameAttributes;
}
CTFrameGetFrameAttributes.displayName = @"CTFrameGetFrameAttributes";
/*!
Returns the array containing CTLines that make up the frame
*/
function CTFrameGetLines(/* CTFrame */ aFrame)
{
return aFrame.lines;
}
CTFrameGetLines.displayName = @"CTFrameGetLines";
/*!
Returns an array of CGPoints for the origin of each CTLine in the frame
*/
function CTFrameGetLineOrigins(/* CTFrame */ aFrame, /* CPRange */ aRange)
{
var results = [],
lines = aRange ? CTFrameGetLinesForRange(aFrame, aRange) : aFrame.lines;
for (var i = -1, count = lines.length; ++i < count;)
results.push(lines[i].origin);
return results;
}
CTFrameGetLineOrigins.displayName = @"CTFrameGetLineOrigins";
/*!
Returns an array of CTLines for a given range.
Divergent from Cocoa and expensive.
*/
function CTFrameGetLinesForRange(/* CTFrame */ aFrame, /* CPRange */ lhs)
{
var lines = aFrame.lines, results = [];
for (var i = -1, count = lines.length; ++i < count;)
{
var line = lines[i],
rhs = CTLineGetStringRange(line);
if ((CPMaxRange(lhs) < rhs.location || CPMaxRange(rhs) < lhs.location) && result.length)
break;
if (lhs.location >= rhs.location && rhs.location <= CPMaxRange(lhs) && CPMaxRange(rhs) > lhs.location)
results.push(line);
}
return results;
}
CTFrameGetLinesForRange.displayName = @"CTFrameGetLinesForRange";
/*!
Returns a CPRange
This is divergent from Cocoa. It's a convenience method used in CPTextView.
*/
function CTFrameGetRangeForPoint(/* CTFrame */ aFrame, /* CGPoint */ aPoint)
{
var lines = aFrame.lines, y = aPoint.y;
for (var i = -1, count = lines.length; ++i < count;)
{
var line = lines[i],
bounds = CTLineGetImageBounds(line),
lineY = line._startPosition.y;
if (y >= lineY && y < bounds.size.height + lineY)
{
// FIXME: we seem to be doing stuff like this with some frequency;
// Maybe it should be normalized at an earlier point.
var index = CTLineGetStringIndexForPosition(line, aPoint),
range = CTLineGetStringRange(line);
range.location += index;
range.length = 0;
return range;
}
}
}
CTFrameGetRangeForPoint.displayName = @"CTFrameGetRangeForPoint";
/*!
Draws the frame to the graphics context.
*/
function CTFrameDraw(/* CTFrame */ aFrame, /* CGContext */ aContext)
{
var origin = aFrame.path.start,
lines = aFrame.lines;
CGContextSetTextPosition(aContext, origin.x, origin.y);
for (var i = -1, count = lines.length; ++i < count;)
{
var line = lines[i],
alignment = [line.string attribute:@"alignment" atIndex:0 effectiveRange:CPMakeRange(0, 0)],
position = CGContextGetTextPosition(aContext);
if (alignment === CPRightTextAlignment)
line.origin = CGPointMake((aFrame.path.elements[1].x - origin.x * 2) - CTLineGetTypographicBounds(line).width, position.y);
else if (alignment === CPCenterTextAlignment)
line.origin = CGPointMake(((aFrame.path.elements[1].x - origin.x) / 2) - CTLineGetTypographicBounds(line).width / 2, position.y);
else
line.origin = CGPointMake(origin.x, position.y);
CGContextSetTextPosition(aContext, line.origin.x, line.origin.y);
CTLineDraw(line, aContext);
}
}
CTFrameDraw.displayName = @"CTFrameDraw";
+122
View File
@@ -0,0 +1,122 @@
/*
* CTFramesetter.j
* CoreText
*
* Created by Nicholas Small.
* Copyright 2011, 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 "CTFrame.j"
@import "CTTypesetter.j"
/*!
Creates a typesetter with a given CPAttributedString
*/
function CTFramesetterCreateWithAttributedString(/* CPAttributedString */ aString)
{
return {
string: aString,
typesetter: CTTypesetterCreateWithAttributedString(aString)
};
}
CTFramesetterCreateWithAttributedString.displayName = @"CTFramesetterCreateWithAttributedString";
/*!
Creates a CTFrame with a given typesetter, range, path, and attributes
*/
function CTFramesetterCreateFrame(/* CTFramesetter */ aFramesetter, /* CPRange */ aRange, /* CGPath */ aPath, /* CPDictionary */ frameAttributes)
{
if (aFramesetter._cachedFrame && [aFramesetter._cachedAttributes isEqual:frameAttributes])
return aFramesetter._cachedFrame;
var attributedString = aRange ? [aFramesetter.string attributedSubstringFromRange:aRange] : aFramesetter.string,
nonattributedString = [attributedString string],
splitLines = nonattributedString.split(/\n|\r/g),
lines = [];
var index = 0;
for (var i = -1, count = splitLines.length; ++i < count;)
{
var length = splitLines[i].length;
if (i !== count - 1)
++length;
var range = CPMakeRange(index, length),
line = CTLineCreateWithAttributedString([attributedString attributedSubstringFromRange:range]);
line.range = range; // FIXME: a couple hacks to make managing lines in CPTextView easier
line.prevLine = lastLine;
if (lastLine)
lastLine.nextLine = line;
lines.push(line);
index += length;
var lastLine = line;
}
return aFramesetter._cachedFrame = _CTFrameCreate(aPath, frameAttributes, lines);
}
CTFramesetterCreateFrame.displayName = @"CTFramesetterCreateFrame";
/*!
Returns a CTTypesetter
*/
function CTFramesetterGetTypesetter(/* CTFramesetter */ aFramesetter)
{
return aFramesetter.typesetter;
}
CTFramesetterGetTypesetter.displayName = @"CTFramesetterGetTypesetter";
/*!
Returns a CGSize object with the suggested size for a given frame.
*/
function CTFramesetterSuggestFrameSizeWithConstraints(/* CTFramesetter */ aFramesetter, /* CPRange */ aRange, /* CPDictionary */ frameAttributes, /* CGSize */ constraints, /* {CPRange} */ fitRange)
{
var frame = CTFramesetterCreateFrame(aFramesetter, aRange, null, frameAttributes),
lines = CTFrameGetLines(frame),
width = 0.0,
height = 0.0;
for (var i = -1, count = lines.length; ++i < count;)
{
var bounds = CTLineGetTypographicBounds(lines[i]);
// var bounds = CTLineGetImageBounds(lines[i], [[CPGraphicsContext currentContext] graphicsPort]).size;
width = MAX(width, bounds.width);
height += bounds.lineHeight;
// height += bounds.height;
}
return CGSizeMake(width, height);
}
CTFramesetterSuggestFrameSizeWithConstraints.displayName = @"CTFramesetterSuggestFrameSizeWithConstraints";
/*!
Returns the CPAttributedString for a given framesetter
*/
function CTFramesetterGetAttributedString(/* CTFramesetter */ aFramesetter)
{
return aFramesetter.string;
}
CTFramesetterGetAttributedString.displayName = @"CTFramesetterGetAttributedString";
+258
View File
@@ -0,0 +1,258 @@
/*
* CTLine.j
* CoreText
*
* Created by Nicholas Small.
* Copyright 2011, 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 "CTRun.j"
kCTLineTruncationStart = 0;
kCTLineTruncationEnd = 1;
kCTLineTruncationMiddle = 2;
/*!
Creates a new line with a supplied CPAttributedString
*/
function CTLineCreateWithAttributedString(/* CPAttributedString */ aString)
{
var line = {
string: aString,
runs: []
};
_CTLineCreateRuns(line);
return line;
}
CTLineCreateWithAttributedString.displayName = @"CTLineCreateWithAttributedString";
/*!
Creates a new line truncated to a given width.
@param aLine - The input line
@param width - The constraining width
@param truncationToken - The characters to represent the truncation. This is usually an elipsis. If not token is given the string will just clip
FIX ME: Not implemented correctly
*/
function CTLineCreateTruncatedLine(/* CTLine */ aLine, /* float */ width, /* CTLineTruncationType */ truncationType, /* CTLine */ truncationToken)
{
return aLine;
}
CTLineCreateTruncatedLine.displayName = @"CTLineCreateTruncatedLine";
/*!
Returns a CTLine with justified text.
FIX ME: This is not implemented correctly
*/
function CTLineCreateJustifiedLine(/* CTline */ aLine, /* float */ justificationFactor, /* float */ width)
{
return aLine;
}
CTLineCreateJustifiedLine.displayName = @"CTLineCreateJustifiedLine";
/*!
Returns the number of glyphs in a given line.
*/
function CTLineGetGlyphCount(/* CTLine */ aLine)
{
return [aLine.string length];
}
CTLineGetGlyphCount.displayName = @"CTLineGetGlyphCount";
/*!
Returns the array of CTRuns that make up the line.
*/
function CTLineGetGlyphRuns(/* CTLine */ aLine)
{
return aLine.runs;
}
CTLineGetGlyphRuns.displayName = @"CTLineGetGlyphRuns";
/*!
Returns the range for which the CTLine makes up the original string
*/
function CTLineGetStringRange(/* CTLine */ aLine)
{
return CPCopyRange(aLine.range) || CPMakeRange(0, [aLine.string length])
}
CTLineGetStringRange.displayName = @"CTLineGetStringRange";
/*!
No op
*/
function CTLineGetPenOffsetForFlush(/* CTLine */ aLine, /* float */ flushFactor, /* float */ flushWidth)
{
}
CTLineGetPenOffsetForFlush.displayName = @"CTLineGetPenOffsetForFlush";
/*!
Draws the CTLine to the graphics context.
*/
function CTLineDraw(/* CTLine */ aLine, /* CGContext */ aContext)
{
var startPosition = aLine._startPosition = CGContextGetTextPosition(aContext),
height = CTLineGetImageBounds(aLine, aContext).size.height;
// FIXME: This is WRONG. This NEEDS to be in CGContext.
CGContextSetTextPosition(aContext, startPosition.x, startPosition.y + height * 0.5);
var runs = aLine.runs;
for (var i = -1, count = runs.length; ++i < count;)
CTRunDraw(runs[i], aContext);
CGContextSetTextPosition(aContext, startPosition.x, startPosition.y + height);
}
CTLineDraw.displayName = @"CTLineDraw";
/*!
Calcaulates the image bounds for a line.
*/
function CTLineGetImageBounds(/* CTLine */ aLine, /* CGContext */ aContext)
{
if (aLine._imageBounds)
return aLine._imageBounds;
var runs = aLine.runs,
width = 0.0,
height = 0.0;
for (var i = -1, count = runs.length; ++i < count;)
{
var runSize = CTRunGetImageBounds(runs[i], aContext).size;
width += runSize.width;
height = MAX(height, runSize.height);
}
return aLine._imageBounds = CGRectMake(0.0, 0.0, width, height);
}
CTLineGetImageBounds.displayName = @"CTLineGetImageBounds";
/*!
Returns a JSObject: {width: float, ascent: float, descent: float, lineHeight: float}
This method is more expensive than CTLineGetImageBounds.
*/
function CTLineGetTypographicBounds(/* CTLine */ aLine)
{
if (aLine._typographicBounds)
return aLine._typographicBounds;
var runs = aLine.runs,
width = 0.0,
ascent = 0.0,
descent = 0.0,
lineHeight = 0.0;
for (var i = -1, count = runs.length; ++i < count;)
{
var runObject = CTRunGetTypographicBounds(runs[i]);
width += runObject.width;
ascent = MAX(ascent, runObject.ascent);
descent = MAX(descent, runObject.descent);
lineHeight = MAX(lineHeight, runObject.lineHeight);
}
return aLine._typographicBounds = {
width: width,
ascent: ascent,
descent: descent,
lineHeight: lineHeight
};
}
CTLineGetTypographicBounds.displayName = @"CTLineGetTypographicBounds";
/*!
Returns the index of the line based on the original string
*/
function CTLineGetStringIndexForPosition(/* CTLine */ aLine, /* CGPoint */ aPoint)
{
var runs = aLine.runs, x = aPoint.x, index = 0;
for (var i = -1, count = runs.length; ++i < count;)
{
var run = runs[i],
origins = run.glyphOrigins;
for (var j = -1, jcount = origins.length; ++j < jcount;)
{
var origin = origins[j], next;
if (j < jcount - 1)
next = origins[j + 1];
else if (i < count - 1)
next = runs[i + 1].glyphOrigins[0];
else
return index++;
if (x <= (next.x - origin.x) / 2 + origin.x)
return index;
index++;
}
}
}
CTLineGetStringIndexForPosition.displayName = @"CTLineGetStringIndexForPosition";
/*!
Returns the offset corresponding to a string index,
this works well for for movement between adjacent lines or for drawing a custom caret.
*/
function CTLineGetOffsetForStringIndex(/* CTLine */ aLine, /* int */ anIndex, /* float */ secondaryOffset)
{
var runs = aLine.runs;
for (var i = -1, count = runs.length; ++i < count;)
{
var run = runs[i], runRange = run.range;
if (CPLocationInRange(anIndex, runRange))
return run.glyphOrigins[anIndex - runRange.location];
}
}
CTLineGetOffsetForStringIndex.displayName = @"CTLineGetOffsetForStringIndex";
function _CTLineCreateRuns(aLine)
{
var string = aLine.string,
runs = aLine.runs,
rangeEntries = string._rangeEntries;
for (var i = -1, count = rangeEntries.length; ++i < count;)
{
var rangeEntry = rangeEntries[i],
range = rangeEntry.range,
rangeString = [[string string] substringWithRange:range],
attributes = rangeEntry.attributes;
var run = _CTRunCreate(rangeString, attributes);
run.range = range;
runs.push(run);
}
}
_CTLineCreateRuns.displayName = @"_CTLineCreateRuns";
+290
View File
@@ -0,0 +1,290 @@
/*
* CTRun.j
* CoreText
*
* Created by Nicholas Small.
* Copyright 2011, 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
*/
kCTRunStatusNoStatus = 0;
kCTRunStatusRightToLeft = 1 << 0;
kCTRunStatusNonMonotonic = 1 << 1;
kCTRunStatusNonIdentityMatrix = 1 << 2;
/*!
A CTRun represents a span of characters with common attribtues.
*/
function _CTRunCreate(glyphs, attributes)
{
return {
glyphs: glyphs,
attributes: attributes,
status: kCTRunStatusNoStatus
};
}
_CTRunCreate.displayName = @"_CTRunCreate";
/*!
Returns the number of glyphs in the run.
*/
function CTRunGetGlyphCount(/* CTRun */ aRun)
{
return aRun.glyphs.length;
}
CTRunGetGlyphCount.displayName = @"CTRunGetGlyphCount";
/*!
Returns a CPDictionary of attributes for the CTRun
*/
function CTRunGetAttributes(/* CTRun */ aRun)
{
return aRun.attributes;
}
CTRunGetAttributes.displayName = @"CTRunGetAttributes";
/*!
Returns a CTRunStatus
CTRuns have status that can be used to speed up certain operations.
Possible values:
@code
kCTRunStatusNoStatus
kCTRunStatusRightToLeft
kCTRunStatusNonMonotonic
kCTRunStatusNonIdentityMatrix
@endcode
*/
function CTRunGetStatus(/* CTRun */ aRun)
{
return aRun.status || kCTRunStatusNoStatus;
}
CTRunGetStatus.displayName = @"CTRunGetStatus";
/*!
Returns an array of CGGlyphs
FIX ME: Not implemented correctly
*/
function CTRunGetGlyphs(/* CTRun */ aRun, /* CPRange */ aRange)
{
if (!aRun.glyphs)
aRun.glyphs = [];
return aRun.glyphs;
}
CTRunGetGlyphs.displayName = @"CTRunGetGlyphs";
/*!
Returns an array of CGPoints
FIX ME: Not implemented correctly
*/
function CTRunGetPositions(/* CTRun */ aRun, /* CPRange */ aRange)
{
if (!aRun.positions)
aRun.positions = [];
return aRun.positions;
}
CTRunGetPositions.displayName = @"CTRunGetPositions";
/*!
Returns an array of CGSizes
FIX ME: Not implemented correctly
*/
function CTRunGetAdvances(/* CTRun */ aRun, /* CPRange */ aRange)
{
if (!aRun.advances)
aRun.advances = [];
return aRun.advances;
}
CTRunGetAdvances.displayName = @"CTRunGetAdvances";
/*!
Returns an array of indexes.
FIX ME: Not implemented correctly
*/
function CTRunGetStringIndices(/* CTRun */ aRun, /* CPRange */ aRange)
{
if (!aRun.stringIndices)
aRun.stringIndices = [];
return aRun.stringIndices;
}
CTRunGetStringIndices.displayName = @"CTRunGetStringIndices";
/*!
Returns a CPRange containing the location of the run in the parent string
*/
function CTRunGetStringRange(/* CTRun */ aRun)
{
return aRun.range;
}
CTRunGetStringRange.displayName = @"CTRunGetStringRange";
/*!
Returns a JSObject: {width: float, ascender: float, descender: float, lineHeight: float}
More expensive
*/
function CTRunGetTypographicBounds(/* CTRun */ aRun, /* CPRange */ aRange)
{
if (aRun._typographicBounds)
return aRun._typographicBounds;
var attributes = aRun.attributes,
font = [attributes valueForKey:@"font"],
string = _CTRunStringForRange(aRun, aRange);
return aRun._typographicBounds = {
width: [string sizeWithFont:font].width, // FIXME: account for tabs
ascender: [font ascender],
descender: [font descender],
lineHeight: [font defaultLineHeightForFont]
};
}
CTRunGetTypographicBounds.displayName = @"CTRunGetTypographicBounds";
/*!
Returns a CGRect
Cheap
*/
function CTRunGetImageBounds(/* CTRun */ aRun, /* CGContext */ aContext, /* CPRange */ aRange)
{
if (aRun._imageBounds)
return aRun._imageBounds;
_CTRunPrepareDraw(aRun, aContext);
var string = _CTRunStringForRange(aRun, aRange),
width = aContext.measureText(string).width,
height = [CGContextGetFont(aContext) defaultLineHeightForFont];
_CTRunUnprepareDraw(aRun, aContext);
return aRun._imageBounds = CGRectMake(0.0, 0.0, width, height);
}
CTRunGetImageBounds.displayName = @"CTRunGetImageBounds";
// CGAffineTransform
function CTRunGetTextMatrix(/* CTRun */ aRun)
{
}
CTRunGetTextMatrix.displayName = @"CTRunGetTextMatrix";
/*!
Draws the run to the context
*/
function CTRunDraw(/* CTRun */ aRun, /* CGContext */ aContext, /* CPRange */ aRange)
{
_CTRunPrepareDraw(aRun, aContext);
var string = aRange ? [aRun.glyphs substringWithRange:aRange] : aRun.glyphs;
_CTRunDrawShadow(aRun, aContext, string);
var origins = aRun.glyphOrigins = [];
for (var i = -1, count = string.length; ++i < count;)
{
var glyph = string[i];
origins[i] = CGContextGetTextPosition(aContext);
CGContextShowText(aContext, glyph);
}
_CTRunUnprepareDraw(aRun, aContext);
}
CTRunDraw.displayName = @"CTRunDraw";
function _CTRunDrawShadow(aRun, aContext, aString)
{
var attributes = aRun.attributes,
textShadowColor = [attributes valueForKey:@"text-shadow-color"],
textShadowOffset = [attributes valueForKey:@"text-shadow-offset"];
if (textShadowColor && textShadowOffset)
{
var color = CGContextGetFillColor(aContext),
position = CGContextGetTextPosition(aContext);
CGContextSetFillColor(aContext, textShadowColor);
CGContextShowTextAtPoint(aContext, position.x + textShadowOffset.width, position.y + textShadowOffset.height, aString);
CGContextSetFillColor(aContext, color);
CGContextSetTextPosition(aContext, position.x, position.y);
}
}
_CTRunDrawShadow.displayName = @"_CTRunDrawShadow";
function _CTRunPrepareDraw(aRun, aContext)
{
var attributes = aRun.attributes,
font = [attributes valueForKey:@"font"],
color = [attributes valueForKey:@"color"];
if (font)
{
CGContextSelectFont(aContext, font);
aRun._cachedFont = CGContextGetFont(aContext);
}
if (color)
{
CGContextSetFillColor(aContext, color);
aRun._cachedColor = CGContextGetFillColor(aContext);
}
}
_CTRunPrepareDraw.displayName = @"_CTRunPrepareDraw";
function _CTRunUnprepareDraw(aRun, aContext)
{
if (aRun._cachedFont)
{
CGContextSelectFont(aContext, aRun._cachedFont);
aRun._cachedFont = nil;
}
if (aRun._cachedColor)
{
CGContextSetFillColor(aContext, aRun._cachedColor);
aRun._cachedColor = nil;
}
}
_CTRunUnprepareDraw.displayName = @"_CTRunUnprepareDraw";
function _CTRunStringForRange(aRun, aRange)
{
return (!aRange || aRange.length === 0) ? aRun.glyphs : [aRun.glyphs substringWithRange:aRange];
}
_CTRunStringForRange.displayName = @"_CTRunStringForRange";
+60
View File
@@ -0,0 +1,60 @@
/*
* CTTypesetter.j
* CoreText
*
* Created by Nicholas Small.
* Copyright 2011, 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 "CTLine.j"
kCTTypesetterOptionDisableBidiProcessing = @"kCTTypesetterOptionDisableBidiProcessing";
kCTTypesetterOptionForcedEmbeddingLevel = @"kCTTypesetterOptionForcedEmbeddingLevel";
// Returns a CTTypesetter
function CTTypesetterCreateWithAttributedString(/* CPAttributedString */ aString)
{
return CTTypesetterCreateWithAttributedStringAndOptions(aString, nil);
}
// Returns a CTTypesetter
function CTTypesetterCreateWithAttributedStringAndOptions(/* CPAttributedString */ aString, /* CPDictionary */ aDictionary)
{
return {
string: aString,
options: aDictionary
}
}
// Returns a CTLine
function CTTypesetterCreateLine(/* CTTypesetter */ aTypesetter, /* CPRange */ aRange)
{
}
// Returns an index
function CTTypesetterSuggestLineBreak(/* CTTypesetter */ aTypesetter, /* int */ startIndex, /* float */ width)
{
}
// Returns an index
function CTTypesetterSuggestClusterBreak(/* CTTypesetter */ aTypesetter, /* int */ startIndex, /* float */ width)
{
}
+29
View File
@@ -0,0 +1,29 @@
/*
* CoreText.j
* CoreText
*
* Created by Nicholas Small.
* Copyright 2011, 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 "CTFramesetter.j"
@import "CTFrame.j"
@import "CTTypesetter.j"
@import "CTLine.j"
@import "CTRun.j"
@import "CGContextText.j"
+2 -1
View File
@@ -47,6 +47,7 @@ var PrimaryPlatformWindow = NULL;
BOOL _mouseIsDown;
BOOL _mouseDownIsRightClick;
CGPoint _lastMouseEventLocation;
CPWindow _mouseDownWindow;
CPTimeInterval _lastMouseUp;
CPTimeInterval _lastMouseDown;
@@ -103,7 +104,7 @@ var PrimaryPlatformWindow = NULL;
#if PLATFORM(DOM)
_windowLevels = [];
_windowLayers = [CPDictionary dictionary];
_charCodes = {};
#endif
}
+10 -10
View File
@@ -34,13 +34,13 @@
- (id)initWithLevel:(int)aLevel
{
self = [super init];
if (self)
{
_level = aLevel;
_windows = [];
_DOMElement = document.createElement("div");
_DOMElement.style.position = "absolute";
_DOMElement.style.top = "0px";
@@ -48,7 +48,7 @@
_DOMElement.style.width = "1px";
_DOMElement.style.height = "1px";
}
return self;
}
@@ -74,7 +74,7 @@
_windows[index]._index = index;
_windows[index]._DOMElement.style.zIndex = index;
}
aWindow._isVisible = NO;
}
@@ -84,8 +84,8 @@
var count = [_windows count],
zIndex = (anIndex == CPNotFound ? count : anIndex),
isVisible = aWindow._isVisible;
// If the window is already a resident of this layer, remove it.
// If the window is already a resident of this layer, remove it.
if (isVisible)
{
zIndex = MIN(zIndex, aWindow._index);
@@ -93,12 +93,12 @@
}
else
++count;
if (anIndex == CPNotFound || anIndex >= count)
[_windows addObject:aWindow];
else
[_windows insertObject:aWindow atIndex:anIndex];
// Adjust all the affected z-indexes.
for (; zIndex < count; ++zIndex)
{
@@ -112,7 +112,7 @@
CPDOMDisplayServerAppendChild(_DOMElement, aWindow._DOMElement);
aWindow._isVisible = YES;
if ([aWindow isFullBridge])
[aWindow setFrame:[aWindow._platformWindow usableContentFrame]];
}

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