Compare commits

...
Author SHA1 Message Date
Alexandre Wilhelm 675f32b10f Fixed: added the method _isCharacterASeparator. This was added for refactoring purpose 2018-08-10 18:20:42 -07:00
Alexandre WilhelmandGitHub cbb7cc93e9 Merge pull request #2739 from Rosch/origin/bugfix-cpdateformatter-german
FIXED: CPDateFormatter not ready for german dates. Fixes #2736
2018-08-10 18:15:16 -07:00
Alexandre WilhelmandGitHub 8b608c5cce Merge pull request #2745 from daboe01/removed--dead-code-from-nativehost
Removed:  dead code from nativehost
2018-08-10 17:58:03 -07:00
Alexandre WilhelmandGitHub 163fb14d0e Merge pull request #2746 from didierkorthoudt/CPTableView-viewWillMoveToWindow-fix
FIXED: In CPTableView, viewWillMoveToWindow was incorrectly removing an observer on the wrong window
2018-08-10 17:57:43 -07:00
Didier Korthoudt e4f87bd805 CPTableView-viewWillMoveToWindow-fix 2018-08-08 22:06:42 +02:00
Didier Korthoudt 864c7d96f1 Revert "NEW: Added automatic Xcode syntax coloring"
This reverts commit 0a497d8c3f.
2018-08-08 22:05:57 +02:00
daboe01 e35e87fb05 fixed: obsolete code remnants from nativehost 2018-08-08 19:19:58 +02:00
Didier Korthoudt 3246bdbc8b Merge remote-tracking branch 'cappuccino/master' 2018-08-08 11:03:03 +02:00
daboe01 710bb5fe1c Merge remote-tracking branch 'cappuccino/master' 2018-08-08 09:32:07 +02:00
bedaltonandcacaodev 53a52da709 Fixed: _CPObjectAnimator initialize method did not match superclass return (#2743)
* Fixed: _CPObjectAnimator initialize method did not match superclass return

_CPObject animator labeled return type as BOOL, not only is this value not returned, but the super class CPProxy's initialize method returns void. Changed return type to void in _CPObject animator, to match superclass
2018-08-03 08:28:05 +02:00
Martin Carlberg 4afbfc6e57 Revert "Removed: dead code and dom clutter from nativehost (#2608)"
This reverts commit 5bfafaf241.
2018-07-11 09:20:49 +02:00
daboe01 f7aa9efe13 Merge remote-tracking branch 'cappuccino/master' 2018-07-09 22:24:30 +02:00
Rosch 1fce0ee551 fix CPDateformatter for german dates 2018-07-08 09:15:58 +02:00
daboe01andMartin Carlberg ee695f9000 Fixed: CPSearchPanel did not support PredicateBindings (#2699) 2018-07-05 15:44:36 +02:00
daboe01andMartin Carlberg 8f99ebb577 Fixed: optical clutter, link duplications in readme (#2729) 2018-07-05 13:01:41 +02:00
daboe01andMartin Carlberg 5bfafaf241 Removed: dead code and dom clutter from nativehost (#2608) 2018-07-05 11:40:10 +02:00
Kjell NilssonandMartin Carlberg 64e1a2ce4b Fixed: Protocol selector signature spell error (#2734) 2018-07-05 11:25:38 +02:00
Didier Korthoudtandcacaodev 27883c5beb FIXED: This fixes problems with default theme attributes values in CPTableView (#2732) 2018-06-21 16:47:21 +02:00
Didier Korthoudt 2772725fe3 Merge remote-tracking branch 'cappuccino/master' 2018-06-17 08:55:10 +02:00
Didier Korthoudtandcacaodev 3f58a64827 FIXED: Before this PR, images specified in IB could crash the app at Cib loading (#2731) 2018-06-16 19:14:58 +02:00
Didier Korthoudt cb37c7d218 Merge remote-tracking branch 'cappuccino/master' 2018-06-16 12:25:12 +02:00
daboe01 45d951071f Merge remote-tracking branch 'cappuccino/master' 2018-06-12 13:13:57 +02:00
daboe01andMartin Carlberg 2ac60684fa Fixed: CPDateFormatter was agnostic for the German language (#2724) 2018-06-08 14:00:25 +02:00
daboe01andMartin Carlberg af71742110 Fixed: Update README.markdown 2018-06-08 13:57:13 +02:00
daboe01andMartin Carlberg 1adf27427a Fixed: The word Site changed to Application in index.html (#2723) 2018-06-04 13:51:15 +02:00
daboe01 082f78eefa Merge remote-tracking branch 'cappuccino/master' 2018-06-03 19:44:23 +02:00
cacaodevandGitHub a8a9ec0023 Fix typo in CPPredicateEditorTest
Fixes #2714
2018-06-02 08:18:01 +02:00
Didier Korthoudt df4f945bc6 Merge remote-tracking branch 'cappuccino/master' 2018-05-29 12:04:40 +02:00
daboe01andcacaodev ad756a5b86 fixed: some mouse events were not propagated when sheets are open (#2603)
* fixed: mouse dragged was not propagated to parent window when sheet was opened

* better detection for attached sheet
2018-05-29 07:17:41 +02:00
Didier Korthoudtandcacaodev 2ca99ba669 FIXED: Before this PR, CPScroller theme attribute knob-inset was partially used (#2720) 2018-05-29 07:15:47 +02:00
daboe01andcacaodev 6443575114 fixed: nib2cib was susceptible to IB button issue with alternateImage (#2721) 2018-05-28 21:10:40 +02:00
Didier Korthoudtandcacaodev 52a51d81f1 FIXED: Before this PR, legacy scroller won't ever loose its selected theme state (#2718) 2018-05-28 20:56:00 +02:00
Didier Korthoudtandcacaodev 7d20b06e52 FIXED: Before this PR, CPSearchField was handling cursor updates by direct DOM manipulation. This PR uses tracking areas. (#2684) 2018-05-28 20:46:28 +02:00
Didier Korthoudtandcacaodev ad9d8a7200 FIXED: When attaching an externally owned tracking area to a view, view tracking areas were not correctly handled (#2681)
This PR also removes the -removeAllTrackingAreas method.
2018-05-28 20:44:31 +02:00
Didier Korthoudt 44da699343 Merge remote-tracking branch 'cappuccino/master' 2018-05-23 23:49:51 +02:00
cacaodev 0a542f9be9 Revert "FIXED: _CPTableColumnHeaderView was using hard coded values instead of theme values (#2703)"
This reverts commit e27bb4de50.
2018-05-17 05:48:59 +02:00
Didier Korthoudt 8f1601ca55 Merge remote-tracking branch 'cappuccino/master' 2018-05-15 22:03:16 +02:00
Didier Korthoudtandcacaodev ff0ce164da FIXED: CPTabView tabs were not reacting as in modern Cocoa (#2694)
Before this commit, the segments of a tab view were selected at mouse down. Now, they are selected at mouse up and there is a visible feedback when tracking tabs.
2018-05-14 07:10:43 +02:00
Didier Korthoudtandcacaodev 3650c38aa9 FIXED: In CPSearchField, the space between the magnifier and the textfield was hard coded (#2690) 2018-05-13 19:49:18 +02:00
Didier Korthoudtandcacaodev 61d97338e2 FIXED: _CPMenuItemStandardView was bypassing theme for disabled text color (#2695) 2018-05-13 19:48:33 +02:00
Didier Korthoudtandcacaodev e27bb4de50 FIXED: _CPTableColumnHeaderView was using hard coded values instead of theme values (#2703) 2018-05-13 19:47:53 +02:00
Didier Korthoudtandcacaodev 4462d8bf22 CHANGED: CPSegmentedControl code refactoring (#2704) 2018-05-13 19:40:33 +02:00
Didier Korthoudt f23a8ac928 Merge remote-tracking branch 'cappuccino/master' 2018-05-12 01:05:02 +02:00
daboe01 9e1750ee13 Merge remote-tracking branch 'cappuccino/master' 2018-05-08 22:46:19 +02:00
Didier Korthoudtandcacaodev 5cd284cb36 FIXED: CPSearchField menu diverged from modern Cocoa (#2697) 2018-05-07 21:52:06 +02:00
daboe01andcacaodev 5ea58430fe fixed: typo in theme attribute name (#2683) 2018-05-07 20:05:49 +02:00
Didier Korthoudtandcacaodev acfbda0d91 FIXED: CPSearchMenu _updateSearchMenu wasn't disabling autoenabling of menu items (#2693) 2018-05-07 19:57:35 +02:00
Didier Korthoudtandcacaodev 437e5a62f1 FIXED: CPSearchField -(void)resetSearchButton was using valueForThemeAttribute instead of currentValueForThemeAttribute (#2692) 2018-05-07 19:57:01 +02:00
Didier Korthoudtandcacaodev bbb5aea77d FIXED: CPTableView was using hard coded values instead of theme attributes (#2698) 2018-05-07 19:54:46 +02:00
Didier Korthoudt b5d04f84e7 Merge remote-tracking branch 'cappuccino/master' 2018-05-06 20:44:07 +02:00
cacaodevandGitHub 93b12eb14f Revert "FIXED: click to key window in the background did not bring it forward" (#2702)
Fixes #2700
2018-05-06 14:07:25 +02:00
Didier Korthoudt 0aa67c4cf2 Merge remote-tracking branch 'cappuccino/master' 2018-05-05 23:26:35 +02:00
Didier Korthoudtandcacaodev 1c1affac5c FIXED: CPTableHeaderView was faulty using inset.right instead of inset.left 2018-05-05 10:47:24 +02:00
Didier Korthoudt 0919797edc Merge remote-tracking branch 'cappuccino/master' 2018-05-04 23:22:49 +02:00
Didier Korthoudtandcacaodev 94ac8fd837 FIXED: Before this PR, CPButton setImage was also changing the alternate image 2018-05-04 16:16:01 +02:00
cacaodevandGitHub ecc82b5b51 Fixed: Typo CGSizZero() -> CGSizeMakeZero()
In BadgedOutlineView.j from SmartFoldersDemo test application.
2018-05-02 19:38:37 +02:00
daboe01 add021fd67 Merge remote-tracking branch 'cappuccino/master' 2018-04-28 16:35:05 +02:00
Didier Korthoudt 2daf309d7d Merge remote-tracking branch 'cappuccino/master' 2018-04-27 14:15:30 +02:00
Didier KorthoudtandMartin Carlberg 20be4a40ea NEW: Add CSS theming support (#2613) 2018-04-27 09:27:01 +02:00
bedaltonandcacaodev 7de91da87a Fix: rename _placeHolderView and add accessors in CPTabView.j (#2678)
In CPTabView.j on line 706 method is called `[_source
_setPlaceholderView:aValue]; ` this method does not exist, and this
call could possibly be expecting the property `_placeHolderView` to
have an accessor method. To add the correct accessor method the case of
either the method call selector or the variable must change —
`_placeHolderView` vs `_placeholderView`. For this fix I selected the
`_placeholderView` spelling, as opposed to the alternative with the
capitalized “holder” in “placeholder.”

Fixes #2674
2018-04-13 12:09:46 +02:00
cacaodevandMartin Carlberg b8b48b533b Previously, animating frame origin was not working on recent versions of Gecko (Firefox). The format for the matrix value of the transform property was matrix(a,b,c,d,tx,ty) and tx and ty had the "px" suffix. According to this page, tx and ty were accept (#2677)
ed (in my understanding not required) to have this suffix before FireFox
16.

All parameters are now numbers without suffix and this code will work
for all FireFox versions supporting css animations.
2018-04-12 11:25:43 +02:00
daboe01andMartin Carlberg 535f981739 Fixed: TextView bindings wrote data on blur even when not editable (#2582) 2018-04-12 09:25:12 +02:00
cacaodevandGitHub 0404ac0395 Merge pull request #2602 from daboe01/issue2545
FIXED: click to key window in the background did not bring it forward
2018-04-12 09:11:57 +02:00
daboe01 f961625f03 fixed: some events were not propagated to the bridge window 2018-04-11 18:30:47 +02:00
daboe01andMartin Carlberg 7909bae065 Fixed: touch-scrolling did not work (#2612) 2018-04-09 13:19:18 +02:00
bedaltonandMartin Carlberg 7e6e117b17 Formatting: add semi-colon to CPTextContainer.j (#2675) 2018-04-09 12:40:41 +02:00
bedaltonandMartin Carlberg 314e64d7b1 Formatting: add semi-colon to CPTextView.j (#2676) 2018-04-09 12:40:11 +02:00
Alexandre WilhelmandGitHub 77eb6b358f Merge pull request #2626 from daboe01/fix-cptextview-backspace-issue
fixed: backspace did not trigger scrolling properly 927d6d2
2018-04-08 11:37:19 -07:00
Alexandre WilhelmandGitHub 25f86e2542 Merge pull request #2616 from bedalton/add-idea-to-gitignore
New: Add *.idea to .gitignore
2018-04-08 11:36:25 -07:00
Alexandre WilhelmandGitHub 8bc0461463 Merge pull request #2627 from bedalton/formatting-add-semi-colon-cpcolorpicker
Formatting: add missing semi-colon to CPColorPicker.j
2018-04-08 11:35:34 -07:00
Alexandre WilhelmandGitHub c9dd1ea71d Merge pull request #2628 from bedalton/formatting-add-semi-colon-cpdatepicker
Formatting: add missing semi-colons to CPDatePicker.j
2018-04-08 11:35:26 -07:00
Alexandre WilhelmandGitHub 85d3529bc3 Merge pull request #2629 from bedalton/formatting-add-semi-colon-cpdatepickertextfield
Formatting: add semi-colon CPDatePickerTextField.j
2018-04-08 11:35:10 -07:00
Alexandre WilhelmandGitHub 3aac8bb072 Merge pull request #2630 from bedalton/formatting-add-semi-colon-cpevent
Formatting: add missing semi-colons to CPEvent.j
2018-04-08 11:34:59 -07:00
Alexandre WilhelmandGitHub e9a7e21aca Merge pull request #2638 from bedalton/formatting-add-semi-colon-cptableview
Formatting: add semi colon to CPTableView.j
2018-04-08 11:34:47 -07:00
Alexandre WilhelmandGitHub fc0e4da33c Merge pull request #2641 from bedalton/formatting-add-semi-colon-cpwindow
Formatting: add missing semi-colons to CPWindow.j
2018-04-08 11:33:54 -07:00
Alexandre WilhelmandGitHub ef3c1315dd Merge pull request #2642 from bedalton/formatting-add-semi-colon-cpwindowcontroller
Formatting: add semi-colon to CPWindowController.j
2018-04-08 11:33:45 -07:00
Alexandre WilhelmandGitHub 5c12890faf Merge pull request #2643 from bedalton/formatting-add-semi-colon-to-cpfontpanel
Formatting: add semi-colon to CPFrontPanel.j
2018-04-08 11:33:33 -07:00
Alexandre WilhelmandGitHub c4fd5e0999 Merge pull request #2645 from bedalton/formatting-add-semi-colons-cpdatepickercalendar
Formatting: add missing semi-colons to _CPDatePickerCalendar.j
2018-04-08 11:33:24 -07:00
Alexandre WilhelmandGitHub d3c56d635d Merge pull request #2669 from bedalton/formatting-add-semi-colons-cpplatformwindow
Formatting: minor formatting updates in CPPlatformWindow+DOM.j
2018-04-08 11:32:58 -07:00
Alexandre WilhelmandGitHub c53cb49034 Merge pull request #2640 from bedalton/formatting-add-semi-colon-cpview
Formatting: add semi-colon to CPView.j
2018-04-08 11:32:44 -07:00
Alexandre WilhelmandGitHub d38463c5d9 Merge pull request #2631 from bedalton/formatting-add-semi-colon-cpfont
Formatting: add semi-colon to CPFont.j
2018-04-08 11:32:33 -07:00
Alexandre WilhelmandGitHub bc4b424f0e Merge pull request #2632 from bedalton/formatting-add-semi-colon-cpimage
Formatting: add semi-colon to CPImage.j
2018-04-08 11:32:23 -07:00
Alexandre WilhelmandGitHub 6bd4f3b7b4 Merge pull request #2633 from bedalton/formatting-add-semi-colon-cpkeyvaluebinding
Formatting: add missing semi-colon to CPKeyValueBinding
2018-04-08 11:32:13 -07:00
Alexandre WilhelmandGitHub d91d83f115 Merge pull request #2634 from bedalton/formatting-add-semi-colon-cplayoutmanager
Formatting: add missing semi-colon to CPLayoutManager.j
2018-04-08 11:32:02 -07:00
Alexandre WilhelmandGitHub 584b6ab219 Merge pull request #2639 from bedalton/formatting-add-semi-colon-cptokenfield
Formatting: add semi colon to  CPTokenField.j
2018-04-08 11:31:47 -07:00
Alexandre WilhelmandGitHub 04b155dbfb Merge pull request #2635 from bedalton/formatting-add-semi-colon-cpoutlineview
Formatting: add semi-colons to CPOutlineView.j
2018-04-08 11:31:35 -07:00
Alexandre WilhelmandGitHub ddc5488db7 Merge pull request #2636 from bedalton/formatting-add-semi-colon-cpprogressindicator
Formatting: add semi-colons to CPProgressIndicator.j
2018-04-08 11:31:23 -07:00
Alexandre WilhelmandGitHub 5c6906d5fd Merge pull request #2637 from bedalton/formatting-add-semi-colon-cpscrollview
Formatting: add missing semi-colon to CPScrollView.j
2018-04-08 11:31:08 -07:00
Alexandre WilhelmandGitHub 56fee5d286 Merge pull request #2657 from bedalton/formatting-remove-redundant-variable-declaration
Formatting: remove redundant variable in _CPRuleEditorViewSlice.j
2018-04-08 11:29:35 -07:00
Alexandre WilhelmandGitHub c4dcab04b6 Merge pull request #2656 from bedalton/formatting-remove-semi-colon-cplevelindicator
Formatting: Remove semi-colon after method header in CPLevelIndicator
2018-04-08 11:29:17 -07:00
Alexandre WilhelmandGitHub 8dd9a96769 Merge pull request #2655 from bedalton/formatting-update-semi-colons-in-cpimageandtextview
Formatting: fix possible misuse of commas in _CPImageAndTextView.j
2018-04-08 11:28:59 -07:00
Alexandre WilhelmandGitHub 6864015af6 Merge pull request #2654 from bedalton/formatting-declare-variable-in-CPColor
Formatting: formally declared variable before use in CPColor.j
2018-04-08 11:28:46 -07:00
Alexandre WilhelmandGitHub ebaa60e929 Merge pull request #2653 from bedalton/formatting-cptextview
Formatting: add semi-colons and comma to CPTextView.j
2018-04-08 11:28:24 -07:00
Alexandre WilhelmandGitHub ac9962c624 Merge pull request #2644 from bedalton/formatting-add-semi-colon-to-cpmenuitem
Formatting: add missing semi-colons to CPMenuItem.j
2018-04-08 11:27:57 -07:00
Alexandre WilhelmandGitHub ccd1773643 Merge pull request #2646 from bedalton/formatting-add-semi-colons-cphudwindowview
Formatting: add missing semi-colon to _CPHudWindowView.j
2018-04-08 11:27:46 -07:00
Alexandre WilhelmandGitHub ac970ff768 Merge pull request #2647 from bedalton/formatting-add-semi-colons-cpplatformpasteboard
Formatting: add semi-colons to CPPlatformPasteboard.j
2018-04-08 11:27:38 -07:00
Alexandre WilhelmandGitHub 53ff45425d Merge pull request #2648 from bedalton/formatting-add-semi-colons-cptablecolumn
Formatting: add semi-colon to CPTableColumn.j
2018-04-08 11:27:25 -07:00
Alexandre WilhelmandGitHub de435c741f Merge pull request #2649 from bedalton/formatting-add-semi-colons-cptextfield
Formatting: add semi-colons to CPTextField.j
2018-04-08 11:27:12 -07:00
Alexandre WilhelmandGitHub 1dc9a44aec Merge pull request #2650 from bedalton/formatting-add-semi-colons-cptoolbar
Formatting: add semi-colon to CPToolBar.j
2018-04-08 11:26:37 -07:00
Alexandre WilhelmandGitHub 0206379315 Merge pull request #2651 from bedalton/formatting-add-semi-colons-cptypesetter
Formatting: add missing semi-colons to CPTypesetter.j
2018-04-08 11:26:29 -07:00
Alexandre WilhelmandGitHub c39adbbbc5 Merge pull request #2652 from bedalton/formatting-add-semi-colons-to-cprtfparser
Formatting: add semi-colons to _CPRTFParser.j
2018-04-08 11:26:16 -07:00
Alexandre WilhelmandGitHub 061a15d4f7 Merge pull request #2658 from bedalton/formatting-remove-redundant-variable-cpsearchfield
Formatting: removed redundant variable in CPSearchField.j
2018-04-08 11:25:25 -07:00
Alexandre WilhelmandGitHub 7c2518f027 Merge pull request #2659 from bedalton/formatting-add-semi-colons-cpusernotification
Formatting: add semi colons CPUserNotification.j
2018-04-08 11:25:04 -07:00
Alexandre WilhelmandGitHub a07459454b Merge pull request #2660 from bedalton/formatting-add-semi-colons-nib2cib-converter
Formatting: add semi-colons to nib2cib/Converter.j
2018-04-08 11:24:56 -07:00
Alexandre WilhelmandGitHub 752f9d2694 Merge pull request #2661 from bedalton/fix-cpproxy-respondstoselector
Fix: CPProxy respondsToSelector incorrect parameter name
2018-04-08 11:24:42 -07:00
Alexandre WilhelmandGitHub 0a180f9e20 Merge pull request #2662 from bedalton/format-add-semi-colon-cpdateformatter
Format: add semi-colons to CPDateFormatter.j
2018-04-08 11:24:21 -07:00
Alexandre WilhelmandGitHub 6fff2e1c2f Merge pull request #2663 from bedalton/formatting-add-semi-colon-cparray-kvo
Formatting: add semi-colon CPArray+KVO.j
2018-04-08 11:24:07 -07:00
Alexandre WilhelmandGitHub 4266900d2e Merge pull request #2664 from bedalton/formatting-add-semi-colon-cpdictionary
Formatting: add semi-colon to CPDictionary.j
2018-04-08 11:23:47 -07:00
Alexandre WilhelmandGitHub a2a1d84bc0 Merge pull request #2665 from bedalton/formatting-add-semi-colon-cpindexset
Formatting: add semi-colons to CPIndexSet
2018-04-08 11:23:39 -07:00
Alexandre WilhelmandGitHub 7648c562f1 Merge pull request #2666 from bedalton/formatting-add-semi-colon-cpnotificationqueue
Formatting: add semi-colons to CPNotificationQueue.j
2018-04-08 11:23:21 -07:00
Alexandre WilhelmandGitHub 403fd30926 Merge pull request #2667 from bedalton/formatting-add-semi-colon-cppredicate
Formatting: add semi-colon to CPPredicate.j
2018-04-08 11:23:07 -07:00
Alexandre WilhelmandGitHub 17ccddf541 Merge pull request #2668 from bedalton/formatting-add-semi-colon-cptheme
Formatting: add semi-colon to CPTheme.j
2018-04-08 11:22:59 -07:00
Alexandre WilhelmandGitHub c24366fcec Merge pull request #2670 from bedalton/formatting-add-semi-colons-nib2cib-nib2cib
Formatting: add semi-colon to nib2cib/Nib2Cib.j
2018-04-08 11:22:31 -07:00
Alexandre WilhelmandGitHub 9a258a6265 Merge pull request #2671 from bedalton/formatting-add-semi-colon-nscustomerresource
Formatting: add semi colon NSCustomResource.j
2018-04-08 11:22:24 -07:00
Alexandre WilhelmandGitHub 4542ccbdc2 Merge pull request #2672 from bedalton/formatting-add-semi-colon-capp-main
Formatting: add semi-colon capp/main.j
2018-04-08 11:22:01 -07:00
Daniel 41d8ad2b86 Formatting: add semi-colons to capp/main.j 2018-04-07 17:20:00 -07:00
Daniel a3a2ee118e Formatting: add semi-colon to NSCustomResource.j 2018-04-07 17:17:19 -07:00
Daniel f285efc277 Formatting: add semi-colon to Nib2Cib.j 2018-04-07 17:15:36 -07:00
Daniel fbaf87ec6c Formatting: add missing semi-colon in CPTheme.j 2018-04-07 17:03:33 -07:00
Daniel a005a468a7 Formatting: add semi-colons to nib2cib/Converter.j 2018-04-07 16:40:52 -07:00
Daniel c8d01549ba Formatting: add semi-colon to CPUserNotification.j 2018-04-07 16:13:20 -07:00
daniel 23af4505dd Fix: CPProxy uses incorrect variable name in method call
On line 51 of CPProxy, `class_getInstanceMethod` is called with the
variable  `aSelector`, but this variable does not exist in the
context, but a variable named `selector` does. This fix changes the
method parameter from `selector` to `aSelector` to match the parameter
used within the method.
2018-04-07 15:37:19 -07:00
daniel 53cb6a5b3e Formatting: add missing semi-colons to CPNotificationQueue.j 2018-04-07 15:29:27 -07:00
daniel 765384ace1 Formatting: add semi-colons to CPIndexSet.j
Variable assignments terminated in commas instead of semi-colons
2018-04-07 15:26:52 -07:00
daniel d39e3e2f69 Formatting: add semi-colon to CPDictionary.j 2018-04-07 15:22:36 -07:00
daniel d75124066e Formatting: add semi-colons to CPDateFormatter.j 2018-04-07 15:20:08 -07:00
daniel f4400876da Formatting: add semi-colon to CPArray+KVO.j 2018-04-07 14:10:03 -07:00
daniel c222c5127f Formatting: add semi-colon to _CPPredicate.j 2018-04-07 14:07:43 -07:00
daniel 90d04956e6 Merge remote-tracking branch 'cappuccino/master' 2018-04-07 11:34:21 -07:00
cacaodevandGitHub 5d3b918339 Merge pull request #2624 from bedalton/formatting-add-semi-colon-cparraycontroller
Formatting: add semi-colon CPArrayController
2018-04-07 06:53:38 +02:00
cacaodevandGitHub eba0091764 Merge pull request #2623 from bedalton/formatting-add-semi-colon-cpapplication
Formatting: add semi-colon CPApplication
2018-04-07 06:53:13 +02:00
cacaodevandGitHub 7999cbbea3 Merge pull request #2622 from bedalton/formatting-add-semi-colon-cppopoverwindow
Formatting: add semi-colon CPPopoverWindow.j
2018-04-07 06:52:57 +02:00
cacaodevandGitHub cee7987b35 Merge pull request #2621 from bedalton/formatting-add-semi-colon-cptooltip
Formatting: add semi-colon to CPToolTip.j
2018-04-07 06:52:40 +02:00
cacaodevandGitHub d475c08024 Merge pull request #2620 from bedalton/formatting-add-semi-colon-cpdatepickerclock
Formatting: add semi colon CPDatePickerClock.j
2018-04-07 06:52:26 +02:00
cacaodevandGitHub d78f83ae49 Merge pull request #2619 from bedalton/formatting-move-redeclared-variable-in-cgpath
Formatting: remove redeclared variables in CGPath.j
2018-04-07 06:52:12 +02:00
cacaodevandGitHub df694f01e7 Merge pull request #2618 from bedalton/add-semi-colons-to-cgcontextvml
Formatting: add semi-colon to CGContextVML.j
2018-04-07 06:51:55 +02:00
cacaodevandGitHub f5d9cbb11b Merge pull request #2615 from bedalton/add-missing-semi-colon-to-cpkeyvaluebinding
Formatting : add missing semi-colon to CPKeyValueBinding.j
2018-04-07 06:51:35 +02:00
cacaodevandGitHub d802588abe Merge pull request #2617 from bedalton/add-missing-semi-colons-cgcontextcanvas
Formatting: Add missing semi-colons to CGContextCanvas.j
2018-04-07 06:51:01 +02:00
daboe01 927d6d2fc6 fixed: backspace did not trigger scrolling properly 2018-04-05 21:36:32 +02:00
daboe01 bab7595078 Merge remote-tracking branch 'cappuccino/master' 2018-04-05 21:26:43 +02:00
daniel 1ea9a6c57f Formatting: add missing semi-colon to CPWindowController.j 2018-04-04 15:14:06 -07:00
daniel f479d415d8 Formatting: add missing semi-colon in CPView.j 2018-04-04 15:13:03 -07:00
daniel f41e7be726 Formatting: add semi-colons to CPToolbar.j 2018-04-04 15:11:52 -07:00
daniel c1fe28124f Formatting: add semi-colons to CPTokenField 2018-04-04 15:10:17 -07:00
daniel 01a1e506e4 Formatting: add missing semi-colons to CPTextField.j 2018-04-04 15:08:21 -07:00
daniel e61aebb55d Formatting: minor formatting changes for CPTableView.j
Added missing semi-colon on line 3763.
Removed the redundant `var` keyword on line 4910
Removed the second redundant variable `CPTableViewHeaderViewKey` which
was declared with the same name and value twice in the same variable
block.
2018-04-04 15:06:00 -07:00
daniel bae5bafc62 Formatting: add semi-colon to CPTableColumn.j 2018-04-04 14:55:01 -07:00
daniel be6cb266de Merge remote-tracking branch 'cappuccino/master' 2018-04-04 14:50:00 -07:00
daniel 6f72edc2d9 Formatting: removed redundant variable in CPSearchField.j
Variable `searches` is defined in the method selector, and then
redeclared with the `var` keyword two lines later. Removed the
redundant declaration, moving the variable assignment to its own line.
2018-04-04 14:45:13 -07:00
daniel 29f66bdfed Formatting: add missing semi-colon to CPScrollView.j 2018-04-04 14:41:53 -07:00
daniel c1c6f5682c Formatting: add semi-colons to CPProgressIndicator.j 2018-04-04 14:40:46 -07:00
daniel a8a74a0246 Formatting: add semi-colons to CPOutlineView.j 2018-04-04 14:37:34 -07:00
daniel f9b867c3eb Formatting: Remove semi-colon after method header in CPLevelIndicator
On lines 295 and 304, the selector for two method declarations are
followed by a semi-colon. Not sure if this causes problems or not, but
removed anyways.
2018-04-04 14:36:07 -07:00
daniel 6c07f9a048 Formatting: add missing semi-colon to CPKeyValueBinding 2018-04-04 14:33:24 -07:00
daniel 573e0acafa Formatting: add semi-colon to CPImage.j
Variable value assignment terminated in comma, despite not being a
variable list. Replaced comma with semi-colon.
2018-04-04 14:25:59 -07:00
daniel 530c664967 Formatting: add semi-colon to CPFont.j 2018-04-04 14:19:26 -07:00
daniel 12c29c8387 Formatting: add missing semi-colons to CPEvent.j 2018-04-04 14:17:42 -07:00
daniel 6c7f61d90f Formatting: add missing semi-colon to CPColorPicker.j 2018-04-04 14:11:59 -07:00
daniel eb6d8d0bb3 Formatting: formally declared variable before use in CPColor.j
Variable `isVertical` is used throughout the function
`patternColorsFromPattern` in CPColor.j despite never being declared.
In this pull request, the variable is declared formally in the variable
list before its use.
2018-04-04 14:09:28 -07:00
daniel ef462973c7 Formatting: add semi-colon to CPArrayController.j 2018-04-04 13:33:53 -07:00
daniel aa7e49cfde Formatting: add semi-colon to CPApplication.j 2018-04-04 13:32:37 -07:00
daniel 186048676a Formatting: add semi-colon to _CPTooltip.j 2018-04-04 13:31:19 -07:00
daniel 0f40721cff Formatting: add semi-colon to _CPPopoverWindow.j 2018-04-04 13:29:40 -07:00
daniel 3799dd92fd Formatting: fix possible misuse of commas in _CPImageAndTextView.j 2018-04-04 10:50:04 -07:00
daniel 9ea1a2b1de Formatting: minor formatting updates in CPPlatformWindow+DOM.j
Missing semi-colon on line 1425.
Removed redundant `var` modifier on already declared variable on line
947.
Added variable declaration to variable used without declaration on line
970.
Removed redundant `var` modifier on already declared variable
`CPDOMEventGetClickCount` removed var on latter declaration as original
declaration has note stating it is to be declared at top so “so
compressor knows about them.”
2018-04-04 10:46:02 -07:00
daniel d8b27d122e Formatting: add semi-colons to CPPlatformPasteboard.j 2018-04-04 09:41:10 -07:00
daniel 15c3a6eae4 Formatting: add missing semi-colons to CPWindow.j 2018-04-04 09:38:43 -07:00
daniel 4fcc90d53e Formatting: add missing semi-colon to _CPHudWindowView.j 2018-04-04 09:28:31 -07:00
daniel 2619a50976 Formatting: add missing semi-colons to CPTypesetter.j 2018-04-04 09:27:12 -07:00
daniel de116c95d4 Formatting: add missing semi-colon to CPLayoutManager.j 2018-04-04 09:23:38 -07:00
daniel 47594c9b07 Formatting: add missing coma and semi-colons to CPTextField 2018-04-04 09:10:52 -07:00
daniel 1b9098b564 Merge remote-tracking branch 'cappuccino/master' into formatting-cptextview 2018-04-04 09:10:14 -07:00
daniel b0306eac87 Formatting: add semi-colon to CPFrontPanel.j 2018-04-04 09:07:06 -07:00
daniel 125e813d25 Formatting: add semi-colons to _CPRTFParser.j 2018-04-04 09:00:36 -07:00
daniel 8e0d4a70f2 Formatting: remove redundant variable in _CPRuleEditorViewSlice.j 2018-04-03 15:04:55 -07:00
daniel 0556fc68b0 Formatting: add missing semi-colons to CPMenuItem.j 2018-04-03 14:59:14 -07:00
daniel e9e2313159 Formatting: add missing semi-colons to CPDatePicker.j 2018-04-03 14:27:07 -07:00
daniel dbb2f03a43 Formatting: add semi-colon CPDatePickerTextField.j 2018-04-03 14:18:36 -07:00
daniel ed0dc2d887 Formatting: add semi-colon to _CPDatePickerClock.j 2018-04-03 12:59:51 -07:00
daniel 0a93f2d0b0 Formatting: add missing semi-colons to _CPDatePickerCalendar.j 2018-04-03 12:54:39 -07:00
daniel fd581cd65c Formatting: removed variable redeclaration in CGPath.j
Variables `arcStartX` and `arcStartY` are declared on 125 and 126, but
are later redeclared in an `else` statement on lines 135 and 136 with
the same equation and presumably the same value used in the initial
declaration.
Also added missing semi-colon
2018-04-03 12:46:56 -07:00
daniel 36702bc971 Formatting: add missing semi-colon to CGContextVML 2018-04-03 12:15:04 -07:00
daniel 0fc3eb38f1 Formatting: Add semi-colons to CGContextCanvas.j 2018-04-03 12:11:57 -07:00
daniel 73c8e945e9 New: add .idea to .gitignore
Prevent Intellij Idea metadata from being committed to git.
2018-04-03 12:07:01 -07:00
daniel b8420303ba Formatting: add missing semi-colon to CPKeyValueBinding.j 2018-04-03 10:55:17 -07:00
daniel 532bfcf937 Merge remote-tracking branch 'cappuccino/master' 2018-04-03 10:20:07 -07:00
cacaodevandGitHub f6d892023e Merge pull request #2604 from bedalton/overshadowing-variable-in-_CPCibObjectData
Fixed: Variable in if statement overshadows variable in enclosing block
2018-04-03 07:54:11 +02:00
daboe01 7f2977f4af fixed: wording in manual test 2018-04-02 08:33:50 +02:00
cacaodevandGitHub e246a2753b Merge pull request #2610 from daboe01/issue2605
fixed: wrong method invocation to delegate of CALayer (displayLayer:)
2018-03-31 12:35:33 +02:00
daboe01 6d06a26c31 fixed: typo in method invocation 2018-03-26 17:53:38 +02:00
Daniel 7cda21b60f Merge remote-tracking branch 'cappuccino/master' 2018-03-20 13:46:13 -07:00
Daniel 1db740039b Fixed: Variable in if statement overshadows variable in enclosing block
If statement variable ‘instantiatedObject’ on line 229 of
_CPCibObjectData.j overshadows a variable with the same name declared
on line 233 in the enclosing block. Variable is added to array outside
the enclosing if statement.

Refs: #2601
2018-03-20 11:36:19 -07:00
daboe01 df462774aa refactured front detection logic to own method _isFrontmostWindow
fixes travis error
2018-03-20 14:25:42 +01:00
daboe01 f55fa789c4 new: manual test for issue 2545 2018-03-18 22:33:49 +01:00
daboe01 488541f26e fixed: click to key window in the background did not bring it forward 2018-03-18 21:45:25 +01:00
daboe01 b404b1cf50 Merge remote-tracking branch 'cappuccino/master' 2018-03-08 15:43:23 +01:00
Martin CarlbergandGitHub 69370aa806 Merge pull request #2596 from mrcarlberg/triple_click_noneditable_selectable_empty_textfield
Fixed: Crash when triple click an empty CPTextField that is not editable but selectable
2018-03-08 09:17:57 +01:00
daboe01andMartin Carlberg b3ddd85b09 Fixed: Editing text in tableviews throws DOM exceptions under certain conditions in Chrome (#2563)
Previosly, we unflagged ```CPTextFieldInputDidBlur``` and ```CPTextFieldInputResigning``` before
the call to removeChild. This resulted in DOM exceptions in Chrome under certain conditions.
See https://stackoverflow.com/questions/21926083/failed-to-execute-removechild-on-node for
why we need to unflag ```CPTextFieldInputDidBlur``` and ```CPTextFieldInputResigning``` only after removing the element.

This apply to token fields also but with the corresponding flags. Also token fields now have the same behavior as the text field when bluring etc.
2018-03-08 09:17:15 +01:00
Martin Carlberg 033221fd01 Fixed: When triple click in an empty CPTextField that is not editable but selectable this call will crash as _DOMTextElement is nil.
This check will make sure it is not called when no element is present. This is the same way as it is done in other parts of this class.
2018-03-07 11:24:21 +01:00
Didier Korthoudt 1201fa38a8 Merge remote-tracking branch 'cappuccino/master' 2018-03-07 00:05:40 +01:00
Martin CarlbergandGitHub 32059c376e Fixed: Nib2Cib will replace a CPTextFieldCell with a CPTextField as Cappuccino does not use cells. When a binding or connection is made to a CPTextFieldCell the binding / connection will get lost when read as the cell is never stored in the cib file. (#2572)
This fix make sure that the binding / connection is made to the CPTextField instead of the cell by replacing the cell with the text field when reading the xib file. The same mechanism is used in NSButton and NSMatrix.

This fix allows view based TableView bindings from a text field cell to the table cell view in the Interface Builder in Xcode.
2018-03-06 09:09:57 +01:00
Martin CarlbergandGitHub 511d393c78 Merge pull request #2576 from mrcarlberg/cptextview_delegate
New: CPTextView delegate methods added
2018-03-06 09:07:55 +01:00
Martin CarlbergandGitHub 237601cf29 Merge pull request #2579 from mrcarlberg/xml-parser-node
Fixed: The property list test cases can now run on the Node engine.
2018-03-06 09:00:41 +01:00
daboe01andMartin Carlberg 928f14872e Fixed: call to nonexistent method (#2588) 2018-03-06 08:59:36 +01:00
Martin CarlbergandGitHub c6a9adf96c Merge pull request #2556 from daboe01/plainsliderfix
Fixed: legacy scrollers used Aristo1 artwork in Aristo2
2018-03-05 11:06:59 +01:00
Martin CarlbergandGitHub cdd00e0bd4 Merge pull request #2595 from daboe01/cpnumber-unarchiving-fix
Fixed: initWithCoder: called unimplemented method on the coder
2018-03-05 11:04:41 +01:00
Martin CarlbergandGitHub 2503d13402 Merge pull request #2594 from daboe01/CPSavePanel-missing-class-method
Fixed: +proposedFileURLWithDocumentName: was missing
2018-03-05 11:01:18 +01:00
daboe01andMartin Carlberg 2d97970d24 Fixed: numberWithInteger: was erroneously used instead of numberWithInt: (#2587) 2018-03-05 10:50:30 +01:00
Martin CarlbergandGitHub d8945e53ba Merge pull request #2593 from daboe01/CPCoder--remove-bitrot
Fixed: unused and broken code removed from CPCoder
2018-03-05 10:43:41 +01:00
daboe01andMartin Carlberg f18012d07b Fixed: removed erroneous call to sizeValue (#2589) 2018-03-05 10:36:22 +01:00
daboe01 104f8603b9 fixed: initWithCoder: called unimplemented method on the coder 2018-03-04 21:27:08 +01:00
daboe01 19bb083030 fixed: +proposedFileURLWithDocumentName: was missing 2018-03-04 18:40:33 +01:00
daboe01 ae575a19a0 fixed: unused broken code removed from CPCoder 2018-03-04 11:55:34 +01:00
cacaodevandGitHub 5f94d0a5c2 Typo: remove extra semi-colon 2018-02-28 15:33:16 +01:00
Korthoudt Didier f2fe1a7c17 Merge remote-tracking branch 'cappuccino/master' 2018-02-27 23:41:34 +01:00
cacaodevandGitHub 618e6a1604 Merge pull request #2591 from daboe01/_CPFunctionExpression.j-missing-if
fixed: fromObject:(id)object index:(id)anIndex failed to raise if arg…
2018-02-27 15:59:19 +01:00
cacaodevandGitHub cef294513a Merge pull request #2590 from daboe01/CPKeyValueObserving-fix-CPKeyValueChangeReplacement
FIXED: Typo in call to replaceObjectsAtIndexes in CPKeyValueObserving
2018-02-27 15:58:13 +01:00
daboe01 8550abadef fixed: fromObject:(id)object index:(id)anIndex failed to raise if argument was not CPDictionary or CPArray 2018-02-24 15:41:17 +01:00
daboe01 25c8b2d631 fixed: typo in call to replaceObjectsAtIndexes 2018-02-24 14:59:27 +01:00
Martin Carlberg e7b690205e Fixed: The property list test cases can now run on the Node engine.
The xml parser in the Node.js engine is more modern and can handle more cases. Our property list parser does not handle this. This fix makes the test cases for the property lists run on the Node.js engine.
2018-01-15 09:28:39 +01:00
Martin Carlberg 2403f8833a Fixed: Added an application description at the top of the window 2018-01-09 13:43:09 +01:00
Martin Carlberg 9f25743b4d Fixed: Never send CPTextViewDidChangeTypingAttributes notification when selection the same selection again. This is how Cocoa works. 2018-01-09 13:41:34 +01:00
Martin Carlberg f1c76f65cf Fixed: Added some comments on some methods 2018-01-09 13:37:35 +01:00
Martin Carlberg 7b39533410 New: Added manual test application to monitor order and number of calls for CPTextView delegate methods and notifications. 2018-01-08 14:11:55 +01:00
Martin Carlberg 1fe9c39dd5 Fixed: Test cases for the new or changed delegate methods and notifications. 2018-01-08 13:57:53 +01:00
Martin Carlberg 2b7be2e3f1 Fixed: Make sure the delegate methods and notifications are handled in the same way as in the Cooca frameworks.
CPTextViewDidChangeSelectionNotification should not be send if the text view is empty.
CPTextDidBeginEditingNotification is send when an edit is started.
CPTextDidEndEditingNotification is send when an edit is ending.

textShouldBeginEditing: delegate method is called to allow control if edit should start.
textShouldEndEditing: delegate method is called to allow control if edit should end.
2018-01-08 13:56:24 +01:00
Martin Carlberg 1ee9a3f279 Fixed: Check if the correct delegate method is implemented before calling it 2018-01-08 13:47:45 +01:00
Martin Carlberg 679acfb239 Fixed: Register the delegate as an observer on any notification that the delegate implement.
Also make sure we remove the observers if for example the view does not have a superview. This will make sure that the Notification Center is not hanging on to the view and delegate if the view is not used any more. Can cause a memory leak.
2018-01-08 13:44:47 +01:00
Martin Carlberg 3c7ab4b49b Fixed: Make the view aware of some more delegate methods 2018-01-08 13:20:03 +01:00
Martin Carlberg 3f062e1c0a Fixed: Make all method in CPTextDelegate and CPTextViewDelegate protocol optional. 2018-01-08 13:15:31 +01:00
Didier Korthoudt 0a497d8c3f NEW: Added automatic Xcode syntax coloring
In Xcode, Objective-C source files are automatically recognised and the usual syntax coloring is applied. With this PR, Xcode will do so for Objective-J source files.
2017-12-17 20:49:56 +01:00
Korthoudt Didier 462351f485 Merge remote-tracking branch 'cappuccino/master' 2017-12-17 20:06:35 +01:00
Martin CarlbergandGitHub c4cbb631a9 Merge pull request #2561 from mrcarlberg/compile_with_sourcemap
Full support for source map when debugging
2017-12-11 10:52:05 +01:00
Martin Carlberg 76f2d15b1b Fixed: Added the option to only inline message send function without also compress the output javascript file.
This allows us to inline the message send function in DEBUG mode. This is great when stepping into a method in the debugger as the message send function is not a separate function. Also the stack traces in the debugger is much more compact as the message send function is not there.
2017-12-08 14:02:11 +01:00
cacaodevandGitHub 5d63865ae5 Merge pull request #2546 from cacaodev/CPSplitView
CPSplitView -trackDivider: performance
2017-11-08 18:53:22 +01:00
daboe01 ad7c88fb45 Merge remote-tracking branch 'cappuccino/master' 2017-09-27 11:46:45 +02:00
daboe01 1af3877758 FIXED: scroll-knob was slightly too bold 2017-09-27 11:05:59 +02:00
Martin CarlbergandGitHub 146ce3b12b Merge pull request #2544 from FrankReh/pullreq/cleanup/old/unused/ensurePackageUpToDate
Remove: ensurePackageUpToDate() from common.jake
2017-09-26 08:43:41 +02:00
Martin CarlbergandGitHub bf67721ac4 Merge pull request #2548 from cacaodev/CPWindow-live-resize-notifications
CPWindow live resize notifications
2017-09-25 14:04:01 +02:00
Martin CarlbergandGitHub 436f736a8e Merge pull request #2543 from FrankReh/pullreq/cleanup/remove/property/sub_classes
Remove objj_class.sub_classes property
2017-09-22 13:03:54 +02:00
Martin Carlberg 1446e90dd9 Fixed: Use correct naming on function parameter. Also changed som comments to reflect the correct meaning of the parameter 2017-09-18 13:39:28 +02:00
Martin Carlberg 54716c03d1 Fixed: Missed new line when increment tokPos. Now we use the correct skip space function that will take care of things in correct manners. 2017-09-18 13:36:51 +02:00
daboe01 fad5e97e0a Merge remote-tracking branch 'cappuccino/master' into plainsliderfix 2017-09-14 09:10:56 +02:00
Martin Carlberg 8cf79590c5 Fixed: When target was ’self’ in a message send expression the source map was showing the wrong variable. 2017-09-12 13:17:49 +02:00
Martin Carlberg c6aafac6c8 Fixed: Compile Foundation and AppKit frameworks with source maps for the debug version. 2017-09-11 12:50:49 +02:00
Martin Carlberg 94a5995197 New: We now support source maps when compiling both from command line and in browsers.
To add source maps add the ”-S” flag to the Jake file when compiling from command line. In the browser you need to add the compiler option into your index.html file. It should look something like this:
OBJJ_COMPILER_FLAGS = [... , "SourceMap"];

All browsers has support for source maps but currently Chrome works best.
2017-09-11 12:49:59 +02:00
Martin CarlbergandGitHub 74081dc981 Merge pull request #2551 from mrcarlberg/compile_without_gcc
Compile without gcc [+2]
2017-09-11 11:14:44 +02:00
daboe01 7a593b13a7 Merge remote-tracking branch 'cappuccino/master' into plainsliderfix 2017-09-09 10:56:37 +02:00
Martin CarlbergandGitHub 25dc38b2b1 Merge pull request #2558 from daboe01/smartcopypastefixes
Fixed: smart copy/paste did not work properly [+1]
2017-09-08 09:09:26 +02:00
Alexandre WilhelmandGitHub 403b12f7b7 Merge pull request #2550 from cacaodev/CPAnimationContext
FIXED: CPAnimationContext completionHandler was not called under certain circumstances.
2017-09-07 18:21:56 -07:00
Alexandre WilhelmandGitHub cd223be88a Merge pull request #2557 from daboe01/placeholderselectablefix
fixed: cursor blinks for placeholder
2017-09-07 18:21:12 -07:00
Alexandre WilhelmandGitHub a6a3fca1e7 Merge pull request #2559 from daboe01/onpaste-ff-fix
Fixed: CPTextView's onpaste handler used non-standard window.event
2017-09-07 18:20:32 -07:00
daboe01 63815eb5c2 fixed: onpaste handler used window.event (non-standard)
broke paste on FF/win
2017-09-07 19:19:19 +02:00
daboe01 4444264830 formatting 2017-09-04 23:02:50 +02:00
daboe01 255f91f7ca fixed: cornerview looked odd without scroller margins 2017-09-04 22:59:34 +02:00
cacaodevandGitHub 700207d29b Merge pull request #2554 from cacaodev/cptableview-issue#2549
CPTableView: fix invisible dragged rows
2017-08-30 08:35:40 +02:00
daboe01 72d96e9a3b fixed: smart pasting did not work properly 2017-08-29 15:11:29 +02:00
daboe01 a55b6de1b4 removed: unused artwork from aristo2 2017-08-28 23:32:47 +02:00
daboe01 9faac05666 fixed: cursor blinks for placeholder 2017-08-23 23:07:42 +02:00
daboe01 7bf408aba0 fixed: legacy scrollers used aristo1 artwork in aristo2 2017-08-22 22:02:42 +02:00
daboe01 70ee391b33 Merge remote-tracking branch 'origin/master' 2017-08-22 14:40:47 +02:00
cacaodev f5eb1158db Fix issue 2549: table rows where invisible when dragging. 2017-07-28 21:35:24 +02:00
cacaodev 81916d0f45 FIXED: A grouping context does not inherit the completion handler ...
… from the current context.
Also removed CPAnimationContext -copy method. CPAnimationContext is not
CPCopying compliant.

TEST: CPAnimationContextTest ->
testCompletionHandlerWithoutAnimatorWithGrouping2
2017-07-25 12:04:58 +02:00
Alexander Ljungberg 76d77cc244 This will be Cappuccino 0.9.10. 2017-07-11 14:26:57 +01:00
cacaodev 03dccbe613 Add a manual test for the previous fixes.
The tests must be run independently because animations are launched at
the end of the current run loop.
2017-06-30 12:26:15 +02:00
cacaodev 1ccec65619 Add debug information 2017-06-30 12:03:29 +02:00
cacaodev b78e9062a1 CompletionHandlerAgent fire() is a one shot. 2017-06-30 12:03:09 +02:00
cacaodev dc87354702 CPAnimationContext setCompletionHandler: add an equality check 2017-06-30 12:00:08 +02:00
Martin Carlberg 033e8583db Fixed: A more robust prettify message function 2017-06-26 17:59:08 +02:00
Martin Carlberg d46b51fa9a Fixed: In Rhino a function must be declared before it is used even if it is in the same scope. 2017-06-26 17:58:13 +02:00
Martin Carlberg dd1dfdcfeb Fixed: Added a comment on tricky code line 2017-06-26 16:25:44 +02:00
Martin Carlberg c0233c803d Fixed: Removed old print statements for debugging 2017-06-26 16:24:51 +02:00
Martin Carlberg 1fa8c88f6b Fixed: Speed up of objj_msgSend function. Don’t need to use complex check if class is initialized. 2017-06-26 16:23:59 +02:00
Martin Carlberg 195b109a36 New: Added ’#include’ to the preprocessor, compiler and Cappuccino load system. Also a lot of bug fixes in the preprocessor 2017-06-26 16:19:56 +02:00
Martin Carlberg 994ac3fc8e Fixed: Support for more options to the objj tool 2017-06-26 16:04:01 +02:00
Martin Carlberg a8ec5cf5e9 New: Support to create source maps for the frameworks and applications 2017-06-26 16:03:20 +02:00
Martin Carlberg b4263aa3ec New: Make sure we can use String function ’startsWith’ and ’endsWith’ even if an older browser or Javascript engine is used. 2017-06-26 15:50:08 +02:00
Martin Carlberg 6456809a72 Fixed: Use semicolon on last line in #included files. The new preprocessor might think that the statement will continue on the next line.
Due to Javascript don’t need to have semicolon at end of statement there are times when the parser thinks the line continues on the next line.

For example we have a file.js:
var f = function(x)
{
	return x + x;
}

Now in another file we do:
#include file.js
(function(exports) {
a = 42;
})(exports.b)

There will be two different behaviors if the ’file.js’ has a semicolon at the end of the last line. This commit make sure we have the right behavior.
2017-06-26 15:45:02 +02:00
Martin Carlberg 024c0a3186 Fixed: Handle source maps if source-map.js is included from the index.html file.
To create source maps the compiler flag ”SourceMap” has to be added in the OBJJ_COMPILER_FLAGS array in the index.html file.
2017-06-22 11:05:16 +02:00
Martin Carlberg 560b1d48bc Merge branch 'master' of https://github.com/cappuccino/cappuccino 2017-06-22 10:46:53 +02:00
cacaodev bb2d860807 CPViewAnimator: guard in the frame updater function
… in case the transform property value is ‘none’.
2017-06-12 12:46:05 +02:00
cacaodev 6f1c0fa4a8 FIXED: CPAnimationContext completionHandler was not called
Previously, if a context group was not generating any animation (no
calls to animator or non implemented method in the animator proxy), the
completionHandler was not called.
If the end value (frame, frameorigin, frameSize) was equal to the start
value, the completionHandler was not called neither.

This commit makes sure that the completionHandlerAgent counter is
incremented by the count of animations that actually start.
2017-06-12 12:46:05 +02:00
cacaodev 35808e7bde FIXED: uninitialized ivar 2017-06-02 11:15:23 +02:00
cacaodev 1b4eeb35b3 Add a manual test CPWindowLiveResizeTest 2017-06-02 09:44:42 +02:00
cacaodev cee032bbc9 FIXED: send live resize notifications when the window animates
Like in cocoa, these notifications are not sent when a sheet is
displayed.
2017-06-02 09:42:59 +02:00
cacaodevandGitHub 9547b70743 Merge pull request #2542 from FrankReh/pullreq/cleanup/fix/unused/cachedSearchResults
Removed an unused variable: cachedSearchResults.
2017-05-30 19:29:14 +02:00
cacaodevandGitHub 5df8939d84 Merge pull request #2541 from FrankReh/pullreq/cleanup/fix/syntax/protocol_list
Fix aClass.protocol_list syntax
2017-05-30 19:27:53 +02:00
cacaodevandGitHub 0b9c689273 Merge pull request #2540 from FrankReh/pullreq/cleanup/fix/syntax/global-var-key
Make variable local: key
2017-05-30 19:25:25 +02:00
cacaodev ac193cd97a Test: Add liveResize testing in CPWindowResizeStyle manual test
The window title changes during live resize.
2017-05-30 19:06:50 +02:00
cacaodev 7355a60f16 Call _setupDOMDivider when necessary only
Previoulsy, the backgroundColor and url css properties where set at
each drawing pass.
2017-05-30 18:33:08 +02:00
cacaodev fb6f6325b5 CPSplitView: refactor trackDivider: using _dividerAtPoint:
instead of a for loop.
2017-05-23 08:17:16 +02:00
cacaodev 0f767d9dfc CPWindow: add CPWindowWillStartLiveResizeNotification and CPWindowDidEndLiveResizeNotification
Also fixed CPView -(BOOL)inLiveResize
If a view is added during a live resize, it will not receive a
willStart notif.
If a view is removed during a live resize it will not receive a Didend
notif.
2017-05-20 13:52:50 +02:00
cacaodev d1addcab91 CPSplitView: do not track events outside of a divider.
Added private method -_dividerAtIndex:
2017-05-13 19:46:39 +02:00
cacaodev 7a02cd794b Properly catch single-click, double-click, dragging on a divider
Previously, a double-click was also catched as a single-click on mouse
up,
dragging was handled is mouse down before tracking actually begins.

Manual test: added collapse capabilities to all split views.
2017-05-12 11:09:08 +02:00
cacaodev 258cd9209f CPSplitView: exit a loop when the current divider is found 2017-05-12 10:28:47 +02:00
Frank Rehwinkel 700f6022d9 Remove: ensurePackageUpToDate() from common.jake
Some unused code in common.jake that had referred to tusk.  Has not
been used in years.
2017-05-06 13:10:49 -04:00
Frank Rehwinkel a0f6b815e8 Removed an unused variable: cachedSearchResults.
It is polluting the global namespace.

Seven years ago this line was added and even then the variable wasn't
being used but it was a local variable so would have been hard to spot
unless a linter should catch things like that.

Then some four years ago it was accidently converted to a global
variable because the line above it ended in a semicolon rather than
a comma.  'use strict' didn't exist at the time this file was created
and hasn't been added in general yet.
2017-05-04 16:03:11 -04:00
Frank Rehwinkel 54477b8b8f Make variable local: key
This line of code was introduced years ago with a variable that
javascript is happy to add to the global name space.  Clearly it
was meant as a local variable.  Probably a cut and paste error
because other places in the code use the same syntax but there the
value is a local because the var statement for it appeared elsewhere
in the function.

Once code like this is cleaned up to use the new 'let' construct,
as well as 'use strict', mistakes like this will be much less likely
to go uncaught.
2017-05-04 16:01:53 -04:00
Frank Rehwinkel 6183f8d4e9 Fix aClass.protocol_list syntax
A long standing bug that never mattered because each class is
initialized with a protocol_list set to an empty array.  This
is not the case for the protocol objects but there the syntax
was correct already.
2017-05-04 15:58:47 -04:00
Frank Rehwinkel d98e247665 Remove objj_class.sub_classes property
From the first day this class was added to the repo, the sub_classes
property, which is initialized with an empty array, has gone unused.

Removing it.  A little less code.  A little subsequent processing
and memory used.
2017-05-04 15:57:14 -04:00
Martin Carlberg d0cd976246 Fixed: Get class method instead of instance method
When asking a protocol for a specific class method we asked each super protocol for an instance method.

Thanks Frank for finding this!
2017-04-11 12:30:16 +02:00
daboe01 15f6f6a90a Merge remote-tracking branch 'cappuccino/master' 2017-03-18 11:02:38 +01:00
cacaodevandGitHub f18074bf49 Merge pull request #2532 from cacaodev/CPWindowAnimator
New: Optional declarative layout for use in CoreAnimation (css animations).
Code refactor.
2017-03-13 08:34:01 +01:00
cacaodevandGitHub 3f64b74453 Merge pull request #2533 from cacaodev/CPCompatibility-SetFeature
NEW: CPCompatibility: add a function to set a feature externally.
```CPSetPlatformFeature(aFeature, aBool)```
2017-03-13 08:28:51 +01:00
cacaodev 1c86256f83 Add CPCSSAnimationFeature to CPCompatibility constants 2017-03-02 11:21:57 +01:00
cacaodev 98105ad4dc Merge branch 'CPCompatibility-SetFeature' into CPWindowAnimator-copy 2017-03-02 10:57:23 +01:00
cacaodev 6bf2d6c1ab Move css animation creation & frame updaters to CPViewAnimator
Reason: • consistency : animations handled by animator.
• Views can now animate several DOM elements. For example
a view with a nine part image need to animate its sub divs.

• Do not create any css animation when the start and end values are
equal and there is no intermediate values.

+ This commit adds an optional method to CPView
- (CGRect)frameRectOfView:(CPView)aView inSuperviewSize:(CGSize)aSize
Returns the frame of a view given its superview frame. This will allow
views implementing -layoutSubviews to gain an optional declarative
layout. The animation system will use this method to compute the end
value of an animation.
2017-03-02 10:30:09 +01:00
cacaodev cebd51aac1 reduce the number of args in a private method 2017-03-02 10:30:08 +01:00
cacaodev 42b8b3aa75 Ask the animator if periodic frame updates are needed 2017-03-02 10:30:08 +01:00
cacaodev c0eaf79d25 Remove jshashtable.js in favor of Map() 2017-03-02 10:30:07 +01:00
cacaodev fb2fe3eb63 Enable forced frame updates in CPViewAnimator 2017-03-02 10:30:07 +01:00
cacaodev 184d63f7eb Move the FrameUpdater function to CPViewAnimator 2017-03-02 10:30:07 +01:00
cacaodev 14ebd58c96 Move CFRunLoopObserver to CPRunLoop.j as a global function 2017-03-02 10:30:05 +01:00
cacaodev 3edddb8e91 Add CSSAnimation.description() function 2017-03-02 10:30:05 +01:00
cacaodev d2340dff1a Style, whitespace 2017-03-02 10:30:04 +01:00
cacaodev d30c6aec7d Fix label in demo (AutoSize checkbox) 2017-03-02 09:56:47 +01:00
cacaodev 4854b3e08f Fix typo 2017-03-02 09:48:12 +01:00
cacaodev facc748090 NEW: CPCompatibility add a function to set a feature externally.
CPSetPlatformFeature(aFeature, aBool)
2017-03-01 19:10:00 +01:00
cacaodevandGitHub 5c71612e34 Typo 2017-02-10 20:01:57 +01:00
cacaodevandGitHub f00a5fbaf4 Merge pull request #2531 from cacaodev/cptableview-diddragcolumn
FIXED: tableView:didDragTableColumn: was never sent
With tests.
Fixes #2530
2017-02-03 08:13:46 +01:00
cacaodev 34769da9cc FIXED: tableview:didDragTableColumn: was never sent
With manual test.
2017-02-02 09:36:48 +01:00
cacaodev 458e6ed531 FiXED: CPTableColumn description 2017-02-02 09:34:17 +01:00
daboe01 05814e9351 Merge remote-tracking branch 'cappuccino/master' 2017-01-26 19:55:12 +01:00
daboe01 b6c0b1b396 Merge remote-tracking branch 'cappuccino/master' 2017-01-19 20:03:10 +01:00
Martin CarlbergandGitHub 1a299d85b6 Merge pull request #2503 from enquora/master
Fix CPBox drawing artifacts when used in CPSeparator mode
2017-01-19 09:46:33 +01:00
David Richardson 1816274ebe Revert "Fix CPBox drawing artifacts when used in CPSeparator mode"
This reverts commit 7596c66703.
2017-01-17 11:59:26 -07:00
David Richardson b02e4c5308 Handle case when CPBox is used as a separator line having no title
If _titlePosition is correctly set to CPNoTitle value, class already handles removing title view from display.
Previously, _titlePosition was not correctly set, title view was left in place.
With no supplied value for title, outline of title view was rendered with visible artifacts.
2017-01-16 11:23:32 -07:00
Martin CarlbergandGitHub 12ed42e163 Merge pull request #2505 from HTPC-Schrauber/fix-RegEx
Fixed: RegEx for gcc > 4.9
2017-01-16 12:36:57 +01:00
Martin CarlbergandGitHub 6c9c135062 Merge pull request #2525 from daboe01/new-textview-bindings
New: bindings support for CPTextView + dragging improvements
2017-01-16 12:24:56 +01:00
Martin CarlbergandGitHub 6aea0160df Merge pull request #2508 from daboe01/fix-sizing-issue
Fixed: text-sizing by canvas and via DOM sizing differed by 1px
2017-01-16 12:20:06 +01:00
daboe01 30edd9e8dd Merge remote-tracking branch 'cappuccino/master' 2017-01-06 13:05:18 +01:00
David Richardson 7734402e8e Merge branch 'master' of https://github.com/cappuccino/cappuccino into enquora-master 2017-01-05 16:00:51 -07:00
daboe01 ace1332ca5 fixed: semipredicate issue caused typingAttributes being overwritten by placeholder attibutes 2016-12-28 23:16:03 +01:00
daboe01 baa313e8f8 fixed: insertion point was wrong sometimes when dragging beyond last character 2016-12-26 23:30:23 +01:00
daboe01 3d9aa24f3c formatting 2016-12-26 23:18:24 +01:00
daboe01 c287d457d6 formatting 2016-12-26 22:14:12 +01:00
daboe01 7537b27a58 fixed: pboad types were wrong when unarchiving from cib 2016-12-26 22:11:11 +01:00
daboe01 1f560c92fc fixed: dragging pasteboard was not respecting rich vs. plain 2016-12-26 21:49:36 +01:00
daboe01 74cd11c763 minor cleanup 2016-12-26 14:50:33 +01:00
daboe01 ee7d89331b fixed: selection dragging was broken by changes to insertText 2016-12-26 12:50:16 +01:00
daboe01 5b51077823 fixed: changing the selection was possible despite isSelectable returning NO 2016-12-26 12:35:23 +01:00
daboe01 d2f94d1945 formatting 2016-12-26 11:53:49 +01:00
daboe01 0170a099bb formatting 2016-12-26 11:50:25 +01:00
daboe01 2b893d0ea1 fixed: placeholder string was not supported in textview bindings 2016-12-26 11:47:33 +01:00
daboe01 a08da57cbb fixed: reverse setting did not work 2016-12-26 10:56:43 +01:00
daboe01 a313fe5a86 add basic binder + manual test 2016-12-26 09:40:58 +01:00
daboe01 544de699f6 Merge remote-tracking branch 'cappuccino/master' into new-textview-bindings 2016-12-24 20:46:26 +01:00
daboe01 d9d35b7f50 add binder class router 2016-12-24 20:46:12 +01:00
daboe01 7dbec00f0e Merge remote-tracking branch 'cappuccino/master' into new-textview-bindings 2016-12-18 21:07:21 +01:00
Martin CarlbergandGitHub 51b9b40c7e Merge pull request #2515 from daboe01/chrome-rich-paste-fix
fixed: native paste on chrome was not working as robustly as it should [+1]
2016-12-13 09:40:18 +01:00
daboe01 b2383a084a fixed: wrong name in CPTextView manual test 2016-12-12 22:32:00 +01:00
daboe01 61848c5e24 fixed: selection was not properly restored upon undo/redo 2016-12-12 20:29:19 +01:00
Martin CarlbergandGitHub 60b2f7d243 Merge pull request #2513 from daboe01/fix-combobox-scroll-issue
Fixed: legacy scrollers were not clickable under some circumstances
2016-12-12 13:16:01 +01:00
daboe01 d2a5e126ae fixed: native rich text was parsed when pasted into plain textview
+ newline fix in rtf parser
2016-12-11 22:42:43 +01:00
daboe01 9d7d8ddde9 fixed: native rich pasting pasted rich text into plain textviews 2016-12-11 14:05:51 +01:00
Martin CarlbergandGitHub 249ebeb4aa Merge pull request #2517 from daboe01/fix-initial-blinking-on-sheet
Fixed: caret did not blink in empty textview, e.g. when on freshly opened popover
2016-12-10 11:11:13 +01:00
daboe01 378c14d790 formatting 2016-12-09 23:53:08 +01:00
daboe01 30c1093c2f fixed: rich native pasting caused FF to flicker 2016-12-09 23:45:16 +01:00
daboe01 b966c8cb0b formatting 2016-12-09 21:35:42 +01:00
daboe01 38cddf029b fixed: rich native pasting was not using the rtf pasteboard type on chrome 2016-12-09 21:32:21 +01:00
Martin CarlbergandGitHub 6652a27781 Merge pull request #2518 from cacaodev/CPControl-usesSingleLine
New: Allow a text based control to stay on a single line when text wraps.
2016-12-09 15:13:28 +01:00
daboe01andcacaodev 08b067cfc5 fixed: cared was blinking during typing (#2519) 2016-12-04 13:33:24 +01:00
daboe01 4959b84b4c fixed: implicit casting of NULL aWith argument to string in _sizeWithFont:inWidth: 2016-12-02 22:08:48 +01:00
cacaodev d42562fdcb New: Allow a text based control to stay on a single line when wrapping
A private flag have been added in _CPImageAndTextView. It must be set
to YES when it does not make sense for a control to hold multiline text.
This is now the case for all CPSegmentedControl.

Test: In CPSegmentedControlTest, hit « Add Segment with flexible
width » button. The new label should be vertically centered.
2016-12-02 09:10:39 +01:00
Alexandre WilhelmandGitHub 1e0aacd811 Merge pull request #2511 from cacaodev/CPObjet-instancesImplementSelector
New: CPObject -instancesImplementSelector:(SEL)aSelector
2016-11-22 22:44:30 -08:00
daboe01 329469fe84 fixed: _textContainerOrigin.y was not respected when predicting the cared position in empty textview 2016-11-20 22:36:24 +01:00
daboe01 93b0c5a7e5 fixed: font height was nil under certain circumstances 2016-11-20 21:44:08 +01:00
daboe01 9e456fd315 Merge remote-tracking branch 'cappuccino/master' 2016-11-20 15:31:25 +01:00
daboe01andcacaodev 8203c71b03 fixed: CPTextView's needsPanelToBecomeKey did not return YES (#2512)
This is confirmed to conform to cocoa.
2016-11-17 16:43:54 +01:00
daboe01 80d1e9a9a7 fixed: ceiling the sizing width caused subtle issues with CPTextView 2016-11-15 22:43:24 +01:00
daboe01 3c27e57b19 fixed: native rich pasting curly braces crashed chrome 2016-11-15 21:02:04 +01:00
daboe01 b46b2f048d fixed: native paste on chrome was not working as robustly as it should 2016-11-14 23:09:04 +01:00
cacaodev 8d403f579c FIxed: IB connections in CPTabViewNibTest 2016-11-14 22:03:51 +01:00
daboe01 12b274ab43 formatting 2016-11-13 22:55:29 +01:00
daboe01 986cccb800 fixed: legacy scroller was not clickable under some circumstances 2016-11-12 23:03:45 +01:00
cacaodev 5da8728d6c New: CPObject instancesImplementSelector:(SEL)aSelector
Tests if instances of given class implement a selector.

With test.

Note: The naming is from cocoa where this method is semi-public.
2016-11-12 18:30:02 +01:00
daboe01 66c9a1e90a ceil is a better solution than adding one 2016-11-11 23:02:57 +01:00
daboe01 a1925e1d0b fixed: the canvas sizing and DOM sizing differed by 1px 2016-11-08 19:52:45 +01:00
daboe01 da0910b1e5 Merge remote-tracking branch 'cappuccino/master' 2016-11-08 19:34:28 +01:00
Didier Korthoudt 8dbbe34dfc Merge remote-tracking branch 'cappuccino/master' 2016-11-08 15:21:17 +01:00
cacaodev 947d552509 Fix merging 2016-11-07 22:57:33 +01:00
cacaodev 037bc4ea2b Test: demonstrate the new wantsPeriodicFrameUpdates animator property
In Tests/Manual/CPAnimatablePropertyContainerTest/
2016-11-07 22:26:30 +01:00
cacaodev cfbef141d8 CPAnimationContext: Inhibit DOM updates during size animation
Previously, during frame updates, we were writing the css values we
just read before.
Canvas sizing is preserved as it is needed when the view has custom
drawing.
2016-11-07 22:26:30 +01:00
cacaodev 410ad0dc09 Style: print debug logs in debug mode only 2016-11-07 22:26:29 +01:00
cacaodev 3d9b42f0c2 Style: CSSAnimation.j linting
Using default eslint config for js
2016-11-07 22:26:29 +01:00
Didier Korthoudtandcacaodev eeea21c882 Fixed: CPViewAnimator was not giving correct frame information (#2502)
Fixed: When only animating frameSize, there’s no matrix defined. This is now
correctly handled.
New: The animator can explicitly request frames updates when the frameOrigin 
keyPath changes with the new method [animator setWantsPeriodicFramesUpdates:YES]
2016-11-07 22:20:55 +01:00
Maik Opitz d94e5480c9 Merge branch 'fix-RegEx' of https://github.com/HTPC-Schrauber/cappuccino into fix-RegEx 2016-11-03 12:42:05 +00:00
Maik Opitz a5c8e87e6d Removed mistaken triplequotes 2016-11-03 12:33:39 +00:00
Maik Opitz 08f74201b6 RegEx angepasst 2016-11-02 16:21:03 +00:00
Maik Opitz 3a25c683b6 Regex nochmals angepasst 2016-11-02 16:48:10 +01:00
Maik Opitz fb43f8bf1a Regex nochmals angepasst 2016-11-02 16:45:01 +01:00
Maik Opitz bf082600c3 fixed RegEx with newer gcc versions 2016-11-01 15:46:40 +01:00
David Richardson 7596c66703 Fix CPBox drawing artifacts when used in CPSeparator mode
Suppress title positioning when CPBox used as a line or separator - by definition the title is null.
2016-10-31 16:21:46 -06:00
Didier Korthoudt e1bcf6c47e Merge remote-tracking branch 'cappuccino/master' 2016-10-31 16:11:38 +01:00
Alexander Ljungberg ef1d6c78ac Merge branch 'master' of github.com:cappuccino/cappuccino 2016-10-30 21:06:25 +00:00
Alexander Ljungberg f36406af08 Text tweak. 2016-10-30 21:05:54 +00:00
Alexandre WilhelmandGitHub 4b7d215d9d Merge pull request #2498 from daboe01/fixed--font-can-be-nil
Fixed:  font can be nil sometimes
2016-10-30 13:52:03 -07:00
daboe01 e09f12dc0b fixed: accessors for _font were not used sometimes 2016-10-26 19:58:21 +02:00
daboe01 efa7406741 fixed: typing font was nil in sometimes cib-generated textviews 2016-10-26 19:53:59 +02:00
daboe01 5a2181c064 Merge remote-tracking branch 'cappuccino/master' 2016-10-26 19:51:22 +02:00
cacaodev dda81b12da Revert "nib2cib: discard warnings in the nib file."
This reverts commit 4e11152e76.
2016-10-22 08:40:38 +02:00
Martin CarlbergandGitHub c4bf67d133 Merge pull request #2496 from cacaodev/cptabview-initial-selection
Fixed: CPTabView should not allow empty selection
2016-10-21 18:16:31 +02:00
daboe01 f355c8679d Merge remote-tracking branch 'cappuccino/master' 2016-10-21 17:38:56 +02:00
cacaodev 095864de39 Fixed: CPTabView should not allow empty selection
Before this commit, a tab view could have an empty selection with the
following circumstances:
- The tab view was not created in IB
- the Tab View selection had not binding management

With test.
2016-10-21 10:13:47 +02:00
cacaodevandGitHub 0eb196e852 CPTabView: load tab view items asynchronously when possible (#2479)
When an item created with +tabViewItemWithViewController:, the view is loaded asynchronously

Manual test CPTabViewNib have been modified to show a tab view item
managed by a view controller. Any setup happens in
-viewDidAppear: because we cannot use any more the
tabView:didSelectTabViewItem: delegate method.
2016-10-20 17:24:18 +02:00
cacaodevandGitHub 62e5d8d841 Fixed: type declaration 2016-10-20 08:48:01 +02:00
cacaodevandGitHub 2f82fb842d Merge pull request #2495 from daboe01/fixed--typo-in-CPControl-comment
Fixed:  typo in CPControl comment
2016-10-19 08:37:27 +02:00
daboe01 f9fa6abbad fixed: small typo in comment 2016-10-18 21:46:21 +02:00
cacaodevandGitHub 4b55a69150 Merge pull request #2447 from cacaodev/CPAnimationContext-fixes
Fixed: The animation was reverting back to its initial position.
Fixed: custom layout and custom drawing was not animated in Chrome and Firefox.
2016-10-17 22:01:15 +02:00
Martin CarlbergandGitHub 42e12fae24 Merge pull request #2485 from cacaodev/ibtool-warnings
nib2cib: discard warnings in the nib file.
2016-10-17 18:07:59 +02:00
daboe01andcacaodev 2f55d5130a fixed: typo in accessor setHorizontallyResizable: (#2494) 2016-10-16 21:24:30 +02:00
daboe01 cd4b47b397 Merge remote-tracking branch 'cappuccino/master' 2016-10-16 13:20:13 +02:00
daboe01andcacaodev 126cba1e94 Fixed: textsizing was wrong in safari (#2486)
* fixed: color panel creation in font panel init did break text sizing in safari

* fixed: font sizing did not robustly work on safari

* removal of dead code

* fixed: browser sniffing was not using the mechanisms from CPCompatibility.j

* fixed: blink and webkit engines must not be mutually exclusive

* improved documentation
2016-10-16 10:11:10 +02:00
daboe01 e4e894fa54 Merge remote-tracking branch 'cappuccino/master' 2016-10-15 17:10:59 +02:00
Martin CarlbergandGitHub 65f701d459 Merge pull request #2487 from daboe01/fixed--CPTextView-did-not-support-dragging-the-selection
Fixed: CPTextView did not support dragging the selection
2016-10-13 17:22:51 +02:00
Martin CarlbergandGitHub c2b7cc7964 Merge pull request #2302 from ahankinson/fix-cpview-formatting
Formatting: CPView
2016-10-13 16:55:46 +02:00
Martin CarlbergandGitHub 969d1dff2a Merge pull request #2492 from didierkorthoudt/cpview-updateTA-recursive-bug
Fixed: CPView setFrameSize was calling _updateTrackingAreas too often + empty overlappingTA test
2016-10-13 16:07:10 +02:00
Didier Korthoudt e0fab808b9 fix-overlappingTA-could-be-empty 2016-10-08 17:33:21 +02:00
Didier Korthoudt 77031d7082 Fixed: setFrameSize was calling _updateTrackingAreas too often 2016-10-06 22:54:32 +02:00
Didier Korthoudt 5a0f7ea706 Merge remote-tracking branch 'cappuccino/master' 2016-10-06 20:25:25 +02:00
daboe01 9d041c4b62 fixed: unnecessary safety margin for dragview width 2016-10-02 21:28:38 +02:00
daboe01 ec4d29c327 fixed: transaction issue from the undo manager 2016-10-02 10:34:30 +02:00
daboe01 5f8d8988e3 revert: move drag indicator uncoditionally to the right side 2016-10-01 20:21:52 +02:00
daboe01 a31912f710 fixed: insertion marker was off by one 2016-10-01 20:11:25 +02:00
daboe01 e0d42962e7 fixed: wrapping issue when dragging last word 2016-10-01 19:56:35 +02:00
daboe01 47688bf016 formatting 2016-10-01 18:32:19 +02:00
daboe01 39a695959d formatting 2016-10-01 18:29:47 +02:00
daboe01 71d45a67b7 fixed: dragging placeholder did not always look like dragged text 2016-10-01 18:28:44 +02:00
daboe01 8dc1369ba3 fixed: direct DOM manipulation on drag placeholder instead of using capp methods + formatting 2016-09-30 16:03:36 +02:00
daboe01 1206654d98 fixed: drag placeholder was CPTextField instead of CPTextView 2016-09-29 15:41:46 +02:00
daboe01 1492763d0c fixed: par issue in rtf parser 2016-09-28 20:55:30 +02:00
daboe01 285fafc464 rtf parser fix + formatting 2016-09-28 20:34:46 +02:00
daboe01 b15cc59b95 prettify drag placeholder 2016-09-28 19:42:59 +02:00
daboe01 55cfe31dfe fixed: selection did not work directly after aborted drag 2016-09-28 17:36:28 +02:00
daboe01 dafa6e0310 fixed: space escape was missed for rich text pasting 2016-09-28 17:31:39 +02:00
daboe01 4befe17cab fixed: target index in selection dragging was sometimes wrong 2016-09-28 17:24:39 +02:00
daboe01 2217b560cb formatting 2016-09-28 16:21:55 +02:00
daboe01 39d01a1da8 sizing correction for dragging 2016-09-28 16:15:31 +02:00
daboe01 4e14ad7821 basic support of text selection dragging 2016-09-28 15:12:26 +02:00
daboe01 aee5a2cbe4 refactor point conversion to private method _characterIndexFromEvent 2016-09-28 11:55:56 +02:00
daboe01 de2d5aec1a Merge remote-tracking branch 'cappuccino/master' 2016-09-27 19:34:06 +02:00
Martin CarlbergandGitHub bea03de562 Merge pull request #2068 from daboe01/NEW--CPTextView
New: CPTextView, CPTextStorage, CPTextContainer, CPLayoutManager and CPSimpleTypesetter + CPFontPanel + RTF parser/producer [+2]
2016-09-26 09:53:29 +02:00
Martin CarlbergandGitHub 0aeccbb02c Merge pull request #2462 from daboe01/pasteboard-type-fix
fixed: cappuccino pasteboad is always clobbered by system pasteboard
2016-09-26 09:49:41 +02:00
cacaodev 4e11152e76 nib2cib: discard warnings in the nib file. 2016-09-26 09:44:23 +02:00
Alexandre WilhelmandGitHub 5059028e8a Merge pull request #2484 from daboe01/fixed--documentation-of-autoscroll--was-missing
Fixed:  documentation of autoscroll:  was missing
2016-09-25 13:00:21 -07:00
daboe01 070e6cf848 fixed: documentation of autoscroll: was missing 2016-09-24 17:04:12 +02:00
daboe01 4187fe7261 Merge remote-tracking branch 'cappuccino/master' 2016-09-17 17:07:44 +02:00
daboe01 bdec147874 formatting 2016-09-17 16:34:39 +02:00
daboe01 189fc76dad fixed: highspeed typing issue 2016-09-16 23:59:09 +02:00
daboe01 c0a68005d4 fixed: native rich pasting was not working robustly enough in chrome 2016-09-16 23:09:54 +02:00
daboe01 8187e4cdc2 formatting 2016-09-16 19:22:13 +02:00
daboe01 cc98fd4167 fixed: keystroke duplication when shift is pressed immediately after 2016-09-16 19:21:12 +02:00
daboe01 422e014eff fixed ^a and ^e semantics 2016-09-16 18:32:14 +02:00
daboe01 dd4e044608 fixed: various tab related line height issues 2016-09-15 22:26:20 +02:00
daboe01 13fad1ca47 fixed regression: line spacing was odd when small line followed large line 2016-09-15 20:25:28 +02:00
daboe01 70aaa29016 removal of dead code 2016-09-14 22:38:50 +02:00
daboe01 7dcec9afcf fixed: infinite loop due to undo edge case 2016-09-14 22:20:33 +02:00
daboe01 608642fc25 formatting 2016-09-14 22:18:52 +02:00
cacaodevandGitHub dd62c08b09 FIXED: Fix a build error in XcodeCapp (#2480) 2016-09-09 21:03:17 +02:00
daboe01 315fc21eca fixed: setFrameSize: was iterating every character 2016-09-09 21:00:22 +02:00
daboe01 8cfd3aeda9 fixed: sizing cache was not set up correctly 2016-09-09 20:31:53 +02:00
cacaodevandGitHub 6061323c36 Test CPSegmentedControl enabled state (#2481) 2016-09-07 20:56:49 +02:00
cacaodev 17da8b04bf Remove references to CPAnimationTriggerOrderIn 2016-09-05 21:43:54 +02:00
daboe01 3a948406d5 optimisation: _indexOfObject used a method call instead of js property 2016-09-03 10:00:24 +02:00
daboe01 91c52f8ec8 Merge remote-tracking branch 'cappuccino/master' into NEW--CPTextView 2016-09-03 09:40:49 +02:00
daboe01 6076bbb554 Fixed: CPRange was not copied before altering its content 2016-09-02 19:50:57 +02:00
daboe01 f70d3359c4 removed: temporary debugging code 2016-09-01 21:46:41 +02:00
daboe01 2dbfbe36c3 fixed: lineheight and base wrap issue 2016-09-01 21:45:12 +02:00
daboe01 a25bd03566 fixed: container switch semantics 2016-09-01 20:37:35 +02:00
daboe01 109da1c2cc fixed: typsetting the paragraph geometry was not as fast as it could be 2016-09-01 20:08:34 +02:00
daboe01 9a48e25bb1 fixed: container geometry was not cached appropriately 2016-09-01 14:48:51 +02:00
daboe01 a3ade200a9 fixed: textContainers were not cached appropriately 2016-09-01 14:43:10 +02:00
daboe01 eb1901f03d fixed: comparison was not using the characterCode 2016-09-01 13:50:46 +02:00
daboe01 f8c7cdfc28 typesetter optimization: use integer constants instead of strings 2016-09-01 13:31:40 +02:00
daboe01 ea58d84b55 fixed: text sizing was slower than it should be
thanks mrcarlberg for spotting this
2016-09-01 13:25:12 +02:00
Martin CarlbergandGitHub 1360caaa81 Merge pull request #2467 from daboe01/tableview-cell-editing-fix-2-take
Fixed: tableview corruption when clicking on a cell-based control during an editing session
2016-09-01 06:08:14 +02:00
Alexandre WilhelmandGitHub 315a7b9e6a Merge pull request #2476 from daboe01/New-CGContextText
fixed: CoreGraphics does not have basic text drawing support
2016-08-30 17:43:55 -06:00
daboe01 79311d107b fixed: line fragements were searched linearly instead of using binary search 2016-08-27 22:54:09 +02:00
daboe01 77435fcbd7 fixed: void scanning for fragments during typesetting 2016-08-27 14:25:44 +02:00
Alexander Ljungberg 4395c07648 Merge branch 'fix-mobile-text-entry' 2016-08-25 13:28:29 +01:00
Martin CarlbergandGitHub f9cc77382a Merge pull request #2475 from daboe01/daboe01-readme-fix
Fixed: missing requirements for developers...
2016-08-24 16:45:19 +02:00
Martin CarlbergandGitHub e4fce08eff Merge pull request #2477 from daboe01/setTimeout-scrolling-fix
fixed: scrolling events are missed on slower maschines in chrome 52
2016-08-24 16:23:56 +02:00
Alexander Ljungberg 47196cbc55 Typos. 2016-08-19 14:57:57 +01:00
Alexander Ljungberg c0bf301434 Test: full manual test for the iOS hit test bug. 2016-08-19 14:35:44 +01:00
Alexander Ljungberg f6671f8561 Fixed: iOS virtual keyboard broke hit tests.
Without this fix, tapping on the screen while the virtual keyboard of iOS was open, and it had forced scrolling (due to the input being low on the screen), would cause incorrect mouse event locations. So you might tap on a text field below your current field to edit it and something entirely different would get selected.
2016-08-19 14:35:19 +01:00
Alexander Ljungberg 26aab2961b New: iOS Safari virtual keyboard "Done" button support.
Without this change, clicking the done button in iOS Safari would dismiss the virtual keyboard but then it would immediately come back (as we forced a refocus).

The fix is to no longer force a refocus since it turns out we don't need to anymore given another previous fix.
2016-08-19 13:07:43 +01:00
Alexander Ljungberg c233abe3a4 New: -CPEvent subtype. 2016-08-19 12:45:41 +01:00
Alexander Ljungberg beb3646bef New: test which demonstrates a hit test bug in iOS Safari. 2016-08-19 01:15:12 +01:00
Alexander Ljungberg eb8330a420 New: test which demonstrates an iOS virtual keyboard bug. 2016-08-18 23:53:25 +01:00
Alexander Ljungberg 7f3c2176f8 Fix typos. 2016-08-18 23:52:10 +01:00
Alexander Ljungberg 1d0fdd68f4 Formatting. 2016-08-18 23:51:35 +01:00
daboe01 b26c78828e make manual test more explicit 2016-08-17 21:16:16 +02:00
daboe01 85648c7f11 fixed: manual test was missing 2016-08-17 20:10:02 +02:00
daboe01 8588f446aa formatting 2016-08-17 19:17:47 +02:00
daboe01 d723c5c1c7 formatting 2016-08-17 19:16:57 +02:00
daboe01 7897f2489c fixed: setString: altered selection 2016-08-17 19:15:41 +02:00
daboe01 86e2e0a2c3 minor rewording 2016-08-17 19:06:20 +02:00
daboe01 e2349019a3 minor rewording 2016-08-17 19:05:04 +02:00
daboe01 e485044cfb remove mentioning of gcc and clang dependencies 2016-08-17 19:02:34 +02:00
daboe01 72d80e2857 fixed: scrolling events were missed on slower maschines in chrome 52 2016-08-16 20:53:49 +02:00
daboe01 79a4733698 fixed: CoreGraphics does not have basic text drawing support 2016-08-16 20:30:42 +02:00
daboe01 c64e1daa99 minor rewording 2016-08-15 21:21:53 +02:00
daboe01 d6b4933b05 Merge remote-tracking branch 'origin/daboe01-readme-fix' into daboe01-readme-fix
# Conflicts:
#	README.markdown
2016-08-15 21:20:48 +02:00
daboe01 bcf9cee0f8 more details and compiler dependencies 2016-08-15 21:20:19 +02:00
Alexander Ljungberg a2960a7997 Merge pull request #2463 from daboe01/cppasteboad-cleanup
CPPasteboad.j removal of dead code
2016-08-15 14:50:04 +01:00
daboe01andGitHub dac9874895 minor rewording 2016-08-12 17:16:52 +02:00
daboe01andGitHub a4d374ecb6 Fixed: missing requirements for developers...
... in README.markdown
2016-08-12 16:43:42 +02:00
Alexander Ljungberg 3e56c8ed8b Fixed: XcodeCapp nib2cib incorrect vs jake release.
This bug is similar to the previous one in that the effect was the same. If XcodeCapp was used to `nib2cib`, the `NSClasses` setting would be ignored.

The reason for this, apart from the previous bug, was that `nib2cib` needs to be run from the project folder in order to find the main `Info.plist` file.

The fix is to change the CWD to the project folder before building.
2016-08-10 13:23:01 +01:00
Alexander Ljungberg f4c11d14e7 Fixed: nib2cib'ed files different with jake release and jake deploy.
Without this fix, if you ran `nib2cib` on its own on your UI files you could get a different result than what `jake release` or `jake deploy` would produce. In particular the `NSClasses` setting would be ignored unless `jake release` was used.

The reason for this bug was that the main bundle was never loaded and so the `Info.plist` was not read. But when using `jake release` (and deploy) the main bundle and the `Info.plist` gets baked in so it's always automatically loaded.

The fix is to load the main bundle before checking its settings.
2016-08-10 13:22:04 +01:00
Alexander Ljungberg dde805931d New: show successfully loaded NSClasses in nib2cib verbose.
It's helpful to see which ones are loaded when troubleshooting nib2cib.
2016-08-10 13:22:04 +01:00
Alexandre WilhelmandGitHub fedc721432 Merge pull request #2439 from cacaodev/CPView-viewDidAppear
NEW: CPViewController -viewWill/DidAppear & viewWill/didDisappear
2016-08-09 23:06:10 -07:00
Alexandre WilhelmandGitHub b09cb24804 Merge pull request #2473 from enquora/capp
Move XcodeCapp 'Preferences' menuItem to standard position
2016-08-09 22:54:39 -07:00
Alexandre WilhelmandGitHub 80bfeb1a29 Merge pull request #2470 from daboe01/remove-rakefile
Fixed: obsolete file in root directory
2016-08-09 22:54:00 -07:00
David Richardson 63ad51a637 Move XcodeCapp 'Preferences' menuItem to standard position 2016-08-09 11:33:45 -06:00
daboe01 5ee6232bfc fixed: unused file in the root directory 2016-08-05 12:47:49 +02:00
daboe01 b7d399faf7 fixed: bold and italic extraction from dom for native paste 2016-08-01 09:17:05 +02:00
daboe01 28691bb8a0 improved formatting extraction from the dom in native paste operations 2016-08-01 08:50:24 +02:00
daboe01 fd61f35f78 fixed: rtf-color table was not written 2016-07-29 18:49:38 +02:00
daboe01 0505b59781 formatting 2016-07-29 17:32:48 +02:00
daboe01 a3601e5167 preparations for native rich paste 2016-07-29 17:31:40 +02:00
daboe01 99f63ab64d fixed: are double typing issue in webkit browsers 2016-07-29 16:28:17 +02:00
daboe01 bb2a9fe180 formatting 2016-07-24 17:45:26 +02:00
daboe01 e9c7c7ee4c fixed: editing state was deleted after committing a non-text-control 2016-07-24 17:43:45 +02:00
daboe01 ff7d4f237a fixed: hitTest: had side effects 2016-07-24 17:03:00 +02:00
daboe01 8bf9f8057e Merge remote-tracking branch 'cappuccino/master' 2016-07-24 16:44:00 +02:00
daboe01 27b0f531d7 fixed: more support for RTF for Pages.app 2016-07-17 15:19:40 +02:00
daboe01 01e96d3086 fixed: Pages.app rtf did not parse correctly 2016-07-17 15:00:35 +02:00
daboe01 95e7a7c8eb fixed: wrong comparison (for proper null handling) 2016-07-17 07:53:53 +02:00
daboe01 bbc2f4766e fixed: one other reference to _stateUID 2016-07-17 07:33:21 +02:00
Alexandre WilhelmandGitHub 12dde5154f Merge pull request #2461 from cacaodev/CPView-viewDidHide
FIXED: CPView received multiple -viewDidHide/Unhide messages
2016-07-11 07:46:16 -07:00
Alexandre WilhelmandGitHub 5bc3609ad7 Merge pull request #2464 from daboe01/remove-nativehost
Remove nativehost
2016-07-09 19:14:29 -07:00
daboe01 5c1cdea3c6 Removed: Obsoleted Nativehost stuff 2016-07-08 21:34:14 +02:00
daboe01 3da5b3a278 fixed: entering return blocked the nativeinputmanager 2016-07-01 18:26:01 +02:00
daboe01 9f6460ddae prevent certain race conditions in deadkey handling in FF and safari 2016-06-30 19:45:09 +02:00
daboe01 f1dcf85d7b turned off logging in RTF parser 2016-06-26 21:33:17 +02:00
daboe01 7b78edf38f fixed: removed dead code from obsoleted native pasteboard approach 2016-06-26 18:35:25 +02:00
daboe01 4a726a0c75 Merge remote-tracking branch 'cappuccino/master' 2016-06-26 18:27:33 +02:00
daboe01 5afa7e9fc3 fixed: rtf parser did not propagate paragraph style sometimes 2016-06-26 17:05:19 +02:00
daboe01 75c102f304 fixed: rtf-producer colortable dead index issue 2016-06-25 21:23:35 +02:00
daboe01 68f3c10055 fixed: only one color was supported on the pasteboard 2016-06-25 20:49:56 +02:00
daboe01 e9aeda2a34 fixed: _RTFProducer was referencing wrong colortbl entries 2016-06-25 20:09:56 +02:00
daboe01 45c7a110b6 prevent blinking during cursor navigation more robustly 2016-06-22 22:04:10 +02:00
daboe01 e438e6aedb fixed: same pasteboardtype was used for plain and rich text 2016-06-22 20:39:41 +02:00
daboe01 8dd888bcbd fixed: native pasteboard unconditionally overwrites capp-pasteboard 2016-06-21 20:56:56 +02:00
cacaodev 5f12291ac4 Fixed: add missing import 2016-06-20 19:34:00 +02:00
daboe01 e206d78a52 removed unused range parameter from _characterRangeForIndex 2016-06-19 13:51:53 +02:00
daboe01 d94a82b0a7 paragraph selection dragging fix 2016-06-19 13:45:41 +02:00
daboe01 3bee3d1701 improved: paragraph selection via triple click 2016-06-18 22:51:41 +02:00
daboe01 631352e1ef improved FF deadkey detection 2016-06-18 20:36:22 +02:00
daboe01 f2d5dee49e backspace fix 2016-06-18 19:49:11 +02:00
daboe01 2d578c7cd9 Merge remote-tracking branch 'cappuccino/master' 2016-06-18 19:18:41 +02:00
daboe01 b07ff100d1 fixed: function is missing 2016-06-18 19:18:23 +02:00
daboe01 b0c10b2248 Merge remote-tracking branch 'cappuccino/master' into NEW--CPTextView 2016-06-18 19:17:53 +02:00
daboe01 7b8249442d selection fixes 2016-06-18 17:59:26 +02:00
cacaodev 8221339318 Style 2016-06-18 13:40:27 +02:00
cacaodev b773af96b8 FIXED : css display attribute was incorrectly set 2016-06-18 13:40:14 +02:00
daboe01 dbc7808c70 code simplification 2016-06-18 11:58:42 +02:00
daboe01 77c5000f16 selection fix 2016-06-18 11:47:47 +02:00
daboe01 56928b6ca0 formatting 2016-06-18 11:46:10 +02:00
daboe01 8178dfe7bd revert: fixed: word granularity selection was not always correct 2016-06-18 11:43:50 +02:00
daboe01 0db6c667c6 fixed: word granularity selection was not always correct 2016-06-18 11:40:12 +02:00
cacaodev 2b0a642827 FIXED: CPView received multiple -viewDidHide/Unhide messages
FIXED: when a view is hidden by a hidden superview and added to a non
hidden superview, the -viewDidUnhide message is sent.

With test : CPViewTest.j
2016-06-18 11:29:47 +02:00
daboe01 f71c0f8cb8 selection fixes 2016-06-18 11:25:02 +02:00
daboe01 3782372f65 optimisations for native input manager 2016-06-17 18:31:44 +02:00
daboe01 9e35e42030 nativeinputmanager optmisations for safari 2016-06-16 20:36:12 +02:00
daboe01 7a8195e54c fixed: cursor extended selections did not copy in safari 2016-06-15 22:55:48 +02:00
daboe01 b50ee28693 fixed: the native input manager did not get the focus after recent safari update 2016-06-15 20:52:55 +02:00
Martin CarlbergandGitHub e134f910aa Merge pull request #2436 from mrcarlberg/updated_compiler
Fixed: Merged in the parser and compiler that is used in the node objj-runtime
2016-06-14 21:32:28 +02:00
daboe01 17eb6e47eb improve wordBoundaryRegex to recognize numbers 2016-06-12 13:08:10 +02:00
cacaodev 82ce626d8a Underscore prefix on private methods 2016-06-12 10:52:19 +02:00
cacaodev e063ff5e54 Remove CPAnimationTriggerOrderIn partial support. Adds a warning if someone tries to use it. 2016-06-12 10:20:26 +02:00
cacaodev 5aa98966bc Cucapp test for CPView animation
Tests for commits #1, #2, #3 of this PR
2016-06-12 10:12:08 +02:00
cacaodev fca2746a82 Fixed: custom layout and custom drawing was not animated
The bug was appearing with the following conditions:
keypath : frame , frameSize
browsers : Google Chrome, Firefox
2016-06-12 10:12:08 +02:00
cacaodev 7faffc2de7 Use cancelAnimationFrame when available 2016-06-12 10:12:07 +02:00
cacaodev 86a8a9dc85 Fixed: The animation was reverting back to its initial position.
Although the fill-mode property was correctly set to forwards allowing
the final state to persist, the animation-name property was deleted too
early . It was causing the animation to be cancelled and the initial
state restored.
2016-06-12 10:12:07 +02:00
daboe01 c13a0c1c26 fixed: selection semantics differed from macos 2016-06-11 20:53:05 +02:00
daboe01 6ce3c070b8 fixed: selection semantics differed from macos 2016-06-11 20:42:39 +02:00
daboe01 e1cb11da22 fixed: double clicking right to a word selected too much in some cases 2016-06-11 17:16:06 +02:00
daboe01 c628ea34b7 formatting 2016-06-11 17:11:55 +02:00
daboe01 33b7c726f6 fixed: whitespace double-clicking resulted in cross-paragraph selection 2016-06-11 16:40:28 +02:00
daboe01 6f3fd424e1 fixed: umlaute were treated as word bounderies 2016-06-11 16:18:18 +02:00
daboe01 b048ce9c8e formatting 2016-06-09 22:46:59 +02:00
daboe01 6a1040d659 fixed: setTextColor: issue second take 2016-06-09 22:35:50 +02:00
daboe01 fc05c28231 fixed: change in model did not propagate resize 2016-06-09 20:54:09 +02:00
daboe01 5d165bc6df Merge remote-tracking branch 'cappuccino/master' 2016-06-09 19:22:25 +02:00
daboe01 c139b5eabb Merge remote-tracking branch 'cappuccino/master' into NEW--CPTextView 2016-06-09 19:20:38 +02:00
cacaodev d6dd0e551d Revert "FIXED: CPView received multiple -viewDidHide/Unhide messages"
This reverts commit e58420b031.
2016-06-09 10:13:21 +02:00
Alexandre Wilhelm a84a7bb7c3 Merge pull request #2460 from daboe01/fixed-colorpicker-brightness-bar
Fixed: brightness_bar.png was not displayed in CPColorPicker
2016-06-09 00:59:17 -07:00
daboe01 7195ae6e46 Merge remote-tracking branch 'cappuccino/master' into NEW--CPTextView 2016-06-08 20:05:31 +02:00
daboe01 3c70b2f033 fixed: brightness_bar.png was not displayed in CPColorPicker because the size was not initialized 2016-06-08 19:54:44 +02:00
daboe01 c46340a830 Merge remote-tracking branch 'cappuccino/master' into fixed-colorpicker-brightness-bar 2016-06-08 19:45:16 +02:00
daboe01 8d703b1459 fixed: updates to storage were not propageted to the view 2016-06-08 19:23:37 +02:00
Alexandre Wilhelm f1145ef169 Merge pull request #2457 from cacaodev/CPView-viewDidHide
FIXED: CPView received multiple -viewDidHide/Unhide messages
2016-06-07 20:21:52 -07:00
Alexandre Wilhelm a28f9ceeba Merge pull request #2456 from didierkorthoudt/Fixed--right-mouse-clic-during-a-drag-operation-problem
Fixed: right mouse clic during a drag operation cancels it
2016-06-07 20:17:31 -07:00
Alexandre Wilhelm 1927bb4798 Merge pull request #2452 from didierkorthoudt/CPTextField-tracking-area-optimization
Fixed: CPTextField doesn't optimize tracking areas management
2016-06-07 12:07:11 -07:00
daboe01 d4c77f9786 fixed: Setting textColor only changes first lines color 2016-06-07 20:54:11 +02:00
daboe01 021f8d0331 revert fixed: premature optimization 2016-06-05 22:23:26 +02:00
daboe01 e7d25550ee fixed: premature optimization 2016-06-05 22:21:01 +02:00
daboe01 8227276437 fixed: tabstops were accidentally cornercutting relayout 2016-06-05 21:20:50 +02:00
daboe01 38ef76bcdc fixed: fist tabstop was not working correctly 2016-06-02 20:19:00 +02:00
daboe01 7faa0f60b4 fixed: accidental duplication of variable definition 2016-05-28 13:40:30 +02:00
daboe01 faebbb2b8a fixed: font css properties were not considered when assessing visual identity 2016-05-27 23:13:54 +02:00
daboe01 bc9beb1e87 new: render to dom only the visible stuff 2016-05-27 21:24:30 +02:00
daboe01 f161f723d7 fixed: mimetype of rtf 2016-05-27 17:39:51 +02:00
daboe01 6c94550de3 fixed: accidental creation of a global variable 2016-05-27 17:25:19 +02:00
daboe01 b39a45781a fixed: accidental creation of a global variable 2016-05-27 17:23:30 +02:00
Alexandre Wilhelm 9273c9ee10 Merge pull request #2455 from didierkorthoudt/CPColorPanel-platform-window
Fixed: CPColorPanel always opens in main platform window.
2016-05-25 11:36:28 -07:00
daboe01 e6285914b0 Merge remote-tracking branch 'cappuccino/master' into NEW--CPTextView 2016-05-24 11:29:11 +02:00
daboe01 7d2eb83a1b fixed: undo support for fontpanel 2016-05-24 10:56:19 +02:00
daboe01 7e622f1153 undo color: fallback for textcolor 2016-05-24 10:44:09 +02:00
daboe01 9b30a634b1 formatting 2016-05-24 10:42:33 +02:00
daboe01 e897d2ef81 fixed: missing undo support for textcolor 2016-05-24 10:39:23 +02:00
daboe01 f5b177dda8 fixed: passing range directly instead of copy 2016-05-24 10:24:57 +02:00
daboe01 5f51b5d565 revert: no not make copy of range 2016-05-24 10:13:08 +02:00
daboe01 8d7753fb40 formatting 2016-05-24 09:07:41 +02:00
daboe01 4c6f5744d8 fixed: setFont semantics are wrong 2016-05-24 09:07:03 +02:00
daboe01 43eb2932ba fixed: textColor only changes first lines color 2016-05-23 21:42:25 +02:00
daboe01 59de0e7a4a fixed: text sizing did not work for javascript function names 2016-05-23 17:14:13 +02:00
cacaodev 7b204cf910 Documentation for CPViewController -view*Appear methods 2016-05-23 16:06:05 +02:00
cacaodev b587a19a0f NEW: CPViewController -viewWill/DidAppear & -viewWill/DidDisappear
When a view belonging to a CPViewController is hidden, unhidden, added
or removed, its viewController receives the appropriate message.

Added AppKit/CPViewControllerTest.
2016-05-23 16:06:04 +02:00
cacaodev e58420b031 FIXED: CPView received multiple -viewDidHide/Unhide messages
FIXED: when a view is hidden by a hidden superview and added to a non
hidden superview, the -viewDidUnhide message is sent.

With test : CPViewTest.j
2016-05-23 15:39:47 +02:00
Didier Korthoudt 24313d6709 Fixed: right mouse clic during a drag operation cancels it 2016-05-22 22:14:05 +02:00
daboe01 7acb30b981 fixed: text wrapping in textviews from nibs was wrong 2016-05-22 20:33:41 +02:00
Didier Korthoudt 7454620aa2 Fixed: color panel always open in main platform window 2016-05-18 19:43:19 +02:00
Alexandre Wilhelm abb0799817 Merge pull request #2453 from daboe01/tableview-autoscroll
enable autoscrolling for tableview columns
2016-05-18 10:13:36 -07:00
Didier Korthoudt aebd28dbef CPTextField and CPTrackingArea: optimization and cursor management. 2016-05-18 11:09:06 +02:00
daboe01 152db9fb8e fixed: autoscrolling message was commented out 2016-05-17 20:37:33 +02:00
daboe01 980cd520cd fix travis failure 2016-05-15 11:58:22 +02:00
daboe01 373ec8b5a1 Merge remote-tracking branch 'cappuccino/master' into NEW--CPTextView 2016-05-15 11:57:52 +02:00
daboe01 bacb78e9e8 move background color fallbacks to +themeAttributes 2016-05-15 11:51:44 +02:00
cacaodev 333e112e37 Fixed: CPPredicateEditor predicate when the template has a CPFloatAttributeType 2016-05-15 10:06:52 +02:00
Philippe Fuentesandcacaodev 818d5d782f Fixed: date comparisons in CPPredicateEditor (#2449)
CPPredicateEditorRowTemplate has been modified to allow a correct comparision of date objects when using the CPDateAttributeType
Before this correction, the predicate format was using a string representation of a date instead of a date object.
2016-05-14 23:16:10 +02:00
daboe01 8774090086 formatting 2016-05-14 16:27:01 +02:00
daboe01 0ca65c6d61 fix travis 2016-05-14 13:10:37 +02:00
cacaodev c38daac646 Test: test for pr #2449
In CPPredicateEditor, tests that the input predicate is equal to the
output when the right control is editable.
2016-05-14 10:00:44 +02:00
cacaodev c31f5b1d59 Fixed: CPPredicateEditor in OJTest
OJTest is reading theme attributes from the class default. In
CPPredicateEditor implementation, nil check an attribute and change the
default of another attribute to be non null.
2016-05-14 09:57:29 +02:00
daboe01 2320a56a63 revert travis test 2016-05-13 20:51:25 +02:00
daboe01 07bd91b456 travis test 2016-05-13 20:34:24 +02:00
daboe01 803f7c3a4b formatting 2016-05-13 19:39:30 +02:00
cacaodev a1926982c6 Fixed: make CPObject implementsSelector: work with proxies and KVO swizzled classes 2016-05-12 21:43:44 +02:00
daboe01 b3306d50eb move selection color to the themes 2016-05-12 20:17:14 +02:00
Alexandre Wilhelm 3e6e5f95ec Merge pull request #2448 from cacaodev/CPViewController-async
Fixed: CPViewController isViewLoaded property in async mode
2016-05-11 12:20:48 -07:00
daboe01 df71fb42ac remove duplicate code 2016-05-10 22:41:08 +02:00
daboe01 fe81a354a3 formatting 2016-05-10 22:28:35 +02:00
daboe01 67ba2e49c3 workaround for FF crash in very large documents 2016-05-10 22:27:21 +02:00
daboe01 8dec42f295 fix missing font panel in manual test of CPTextView 2016-05-10 20:35:16 +02:00
daboe01 5942553370 make selection handling more mac like 2016-05-10 19:40:27 +02:00
Martin Carlbergandcacaodev ae5d31746e Dependent key paths use a relationship (#2431)
Fixed: When dependent key paths use a relationship, only the first added observer will observe the attribute for the relationship object.

Also, an optimisation on when the willChange… chain is running, there is no need to replace the observers as no new values are set yet. That will be done when the didChange… chain is running.
2016-05-09 22:14:20 +02:00
cacaodev 1c1976abbf Simple cucapp test for the CPViewController isViewLoaded property in async mode 2016-05-09 09:45:18 +02:00
cacaodev b3465ddf89 Fixed: CPViewController -isViewLoaded property was always NO in async mode (loadViewWithCompletionHandler:).
The async mode calls the completionHandler whereas the sync mode calls the -viewDidLoad method.
Both are now run within the will/did change block of the isViewLoaded property.
2016-05-08 23:09:50 +02:00
Alexandre Wilhelm f67fafdb8e Merge pull request #2446 from cacaodev/CPCollectionView-fixes
CPCollectionView content binding & minor code refactor
2016-05-08 11:16:34 -07:00
cacaodev ffcac677e0 Fixed: Manual test SmartFoldersDemo
The sheet was not closing when asked.
2016-05-07 21:14:35 +02:00
cacaodev a9d643aa55 OJTest for CPCollectionView selectionIndexes, CPCollectionViewItem isSelected, CPSelectionIndexesBinding and CPContentBinding. 2016-05-03 21:51:10 +02:00
cacaodev fa3647e8e5 Refactor selection with modern code.
Handle out of range errors when reflecting selection.
2016-05-03 21:50:41 +02:00
cacaodev db839f6d6d Rename _lockResizing to _inLiveResize
_inLiveResize is a CPView flag.
2016-05-03 21:50:20 +02:00
cacaodev 3a85d5b89f CPCollectionView content binding support 2016-05-03 21:50:20 +02:00
cacaodev 1575c2bc10 CPTableView ViewBasedCib test app: a bug in CPBox decoding was crashing the app. Remove the box until this bug is fixed. 2016-05-03 19:09:32 +02:00
cacaodev 57189183d6 Merge pull request #2444 from cacaodev/fixed-deprecated-getPropertyCSSValue
FIXED: in CPAnimationContext, 'Unknown function getPropertyCSSValue' error in chrome
2016-04-24 13:24:12 +02:00
cacaodev 01c5cf98df FIXED: Unknown function getPropertyCSSValue in Chrome
getPropertyCSSValue have been deprecated in chrome. Replacing with
getPropertyValue supported by all browsers.
2016-04-23 10:54:22 +02:00
Martin Carlberg 9ad2995168 Fixed: Some Javascript minifiers will convert ”\u2028” to a string with the actual line separator inside. It is not valid Javascript to have the actual character inside a string literal.
Instead of fixing bugs in different minifiers it is easier to rewrite this small function. The same applies to \u2029
2016-04-07 10:32:47 +02:00
Martin Carlberg 51fc6518e1 Fixed: Removed some trailing white spaces 2016-04-07 10:32:46 +02:00
Martin Carlberg 530db4e904 Fixed: Merged in the same parser and compiler that is used in the objj-runtime that is running on node.
The life will be easier to have the same in both environments.
Warnings and errors now don’t use read only properties for line and column information. So the test cases in Toolstest.j now work in modern JS engines.
It is also easier to set options for the compiler.
2016-04-07 10:32:46 +02:00
Alexandre Wilhelm cd92ebd69c Merge pull request #2437 from mrcarlberg/cpobjectcontroller_set_entity_name_from_code
Fixed: Setting entity name from code does not work
2016-04-06 18:15:23 -07:00
Alexandre Wilhelm 5c58552d91 Merge pull request #2438 from mrcarlberg/cppopupbutton_binding_select_is_done_before_content
Fixed: First popup item is always selected if selected binding value is set before content binding value
2016-04-06 18:14:53 -07:00
Antoine Mercadal 584aebf76b FIXED: used the master of cappuccino-base 2016-04-06 09:55:38 -07:00
Antoine Mercadal 43a2480699 Merge pull request #2430 from herbatnik/master
FIXED: Cursor key binding methods do not fire in IE11 #2365
2016-04-06 08:35:14 -07:00
Martin Carlberg 699503042f Fixed: First item is always selected if selected binding value is set before content binding value.
Test case is provided.
2016-04-05 23:22:29 +02:00
Martin Carlberg 02e71c23de Merge branch 'master' of https://github.com/cappuccino/cappuccino 2016-04-05 23:12:07 +02:00
Martin Carlberg c24c3868bb Merge pull request #2434 from Dogild/TrackingAreaTableViewHeader
Fixed: crash when having a CPTableViewHeader without a CPTableView
2016-04-05 19:49:27 +02:00
Martin Carlberg 5c60819668 Merge pull request #2432 from Dogild/CacheURLRequest
Fixed: cache control was not set properly in CPURLRequest
2016-04-05 19:05:59 +02:00
Martin Carlberg 480a125a20 Fixed: When setting entity name from code the _managedProxy will be null and the name will not be stored 2016-04-05 18:43:32 +02:00
Antoine Mercadal 598a6ebaed Merge pull request #2278 from cacaodev/CPAnimationContext
Animations: CPAnimationContext & animator
2016-04-04 09:57:55 -07:00
Alexandre Wilhelm 185ad5e747 Fixed: crash when having a CPTableViewHeader without a CPTableView
Previously, when having a CPTableViewHeader without a CPTableView, cappuccino just crashed.
We now check if _tableView is set before iterating on the tableview's columns.
2016-04-04 06:48:26 -07:00
Alexander Ljungberg 42d7e4312b Formatting of CPCache. 2016-04-02 01:20:23 +01:00
Alexander Ljungberg 41a741724f New: Sweden / Swedish as a possible locale. 2016-04-01 23:47:13 +01:00
Alexander Ljungberg 087e811586 Bump XcodeCapp copyright year. 2016-04-01 22:44:23 +01:00
Alexander Ljungberg fa07bc143e Fixed: missed some version number bumps in the 0.9.9 release. 2016-04-01 22:25:21 +01:00
Alexander Ljungberg e13f5ed730 Fixed: CPNumber intValue did not return an integer.
We expect this method to return a whole number like in Objective-C. This also goes for the related methods, `shortValue`, `longValue` and `longLongValue`.

Also adds more tests (in addition to the existing, already failing test).
2016-04-01 22:22:03 +01:00
Alexander Ljungberg 48108cebc9 Merge branch '0.9.9' 2016-04-01 01:05:40 +02:00
Alexander Ljungberg ecac17a00a This will be Cappuccino 0.9.9. 2016-03-29 23:32:12 +01:00
Alexandre Wilhelm 3ba215887c Merge pull request #2426 from mrcarlberg/source_url_fix
Fixed: //@ sourceURL=... is deprecated since many years ago.
2016-03-28 23:43:45 -07:00
Alexandre Wilhelm edbc1baf32 Merge pull request #2427 from cacaodev/cpbutton-image-scaling
NEW: nib2cib support for CPButton -imageScaling.
2016-03-28 23:43:22 -07:00
Alexandre Wilhelm 500fa7f314 Fixed: cache control was not set properly in CPURLRequest 2016-03-28 23:32:48 -07:00
Alexandre Wilhelm a10dfa4ab4 Merge pull request #2429 from mrcarlberg/integer_value
Fixed: Added ’integerValue’ method for CPNumber and CPString.
2016-03-27 09:20:12 -07:00
Martin Carlberg b208571ed7 Fixed: Formatting 2016-03-23 10:17:15 +01:00
Martin Carlberg c1ec27045c Fixed: Rhino does not support numbers starting with ’0’ 2016-03-23 09:35:19 +01:00
Martin Carlberg 111b12161c Added: test cases for ’intValue’ and ’integerValue’ methods on CPString and CPNumber 2016-03-23 09:02:09 +01:00
daboe01 d23d18933c altgr fix for recent FF 2016-03-22 20:39:28 +01:00
Marek Kresnicki f0e736962d FIXED: Cursor key binding methods do not fire in IE11 #2365 2016-03-21 11:23:51 +00:00
Alexandre Wilhelm b12d1491d4 Merge pull request #2415 from cacaodev/CPViewController-loadviewAsynchronously
NEW: CPViewController -loadViewAsynchronously:(Function/*view, error*/)
2016-03-20 19:40:20 -07:00
Alexandre Wilhelm 6d1a094b15 Merge pull request #2428 from cacaodev/CPSearchField-indentationLevel
CPSearchField: use CPMenuItem -setIndentationLevel:
2016-03-20 19:35:48 -07:00
daboe01 88d14792a4 do not select all on setString 2016-03-20 20:29:16 +01:00
Martin Carlberg 7780a98abe Fixed: Added ’integerValue’ method for CPNumber and CPString.
This makes the classes more compliant to Cocoa
2016-03-15 22:25:10 +01:00
cacaodev a1248db3e7 CPSearchField: use CPMenuItem -setIndentationLevel: now that it's available. 2016-03-13 16:09:27 +01:00
cacaodev 6fd2d12d3f Merge remote-tracking branch 'cappuccino/master' into CPAnimationContext 2016-03-12 23:29:46 +01:00
cacaodev 9fab52c044 NEW: nib2cib support for CPButton -imageScaling. With manual test CPButtonTest. Fixes #2425. 2016-03-12 22:18:46 +01:00
daboe01 a32f55d64e add fontpanel to manual test 2016-03-09 19:55:50 +01:00
Aparajita Fishman 96d2b001ea Merge branch 'tableview-edit-fix' 2016-03-08 15:04:55 -08:00
Martin Carlberg e38d6c9f9e Fixed: //@ sourceURL=... is deprecated since many years ago.
We have not changed it for support of older browsers.
Chrome version 51 and above writes a warning about it
in the console so it is time now.
2016-03-07 13:44:29 +01:00
Alexandre Wilhelm be129d243b Fixed: refactoring of CPTextView 2016-03-06 21:48:42 -08:00
Alexandre Wilhelm c85355986b Fixed: manual merged with master 2016-03-06 18:47:58 -08:00
Alexandre Wilhelm 310c0e8379 Merge pull request #2423 from mrcarlberg/cpobject_controller_extension
Allow CPObjectController to get more attributes from the xib/cib file.
2016-03-06 18:20:51 -08:00
Martin Carlberg f0dbffe4f8 Fixed: Formatting 2016-03-06 11:14:22 +01:00
Alexandre Wilhelm 598a482538 New: added gitter badge in the README 2016-03-05 13:38:23 -08:00
Alexandre Wilhelm a995f3ab52 Merge pull request #2424 from mrcarlberg/invalid_plist_fix
Does not throw exception if plist is not valid. It will return nil instead
2016-03-05 13:32:15 -08:00
Martin Carlberg ec5454de44 Merge branch 'cpobject_controller_extension' 2016-03-03 15:09:10 +01:00
Martin Carlberg ec55bddbd4 Fixed: Does not throw exception if plist is not valid. It will return nil instead. 2016-03-01 21:45:08 +01:00
Martin Carlberg 808591df56 Fixed: Allow CPObjectController to get more attributes from the xib/cib file. 2016-03-01 21:40:00 +01:00
Alexandre Wilhelm 96ae3da1e0 Merge pull request #2412 from cacaodev/CPArray-arrayByApplyingBlock-replace
Replace loops with the new -arrayByApplyingBlock: method
2016-02-18 20:25:24 -08:00
Alexandre Wilhelm 4f13df69c7 Merge pull request #2419 from Dogild/cappuccino-test-launched
Test: some manual tests were broken
2016-02-18 20:24:36 -08:00
Alexandre Wilhelm 6d305e4a84 Test: some manual tests were broken
This PR fixes the manual tests. We can no launch every manual tests of Cappuccino...
2016-02-13 11:36:42 -08:00
cacaodev d3dab982a1 Remove ignored argument _ in CPColorPanel 2016-02-07 11:54:16 +01:00
cacaodev 2f6adbae3c Documentation for -loadViewWithCompletionHandler:
Also clarified a note in -loadView doc.
2016-02-07 11:19:26 +01:00
cacaodev ccdc1eed5a Rename to loadViewWithCompletionHandler: 2016-02-07 11:17:53 +01:00
cacaodev 65dee154f7 Remove ignored argument _ 2016-02-06 20:39:49 +01:00
Alexandre Wilhelm 662db009de Merge pull request #2418 from mrcarlberg/build_with_space_in_path
Fixed: Allow build in directory with space in path
2016-02-05 12:05:35 -06:00
cacaodev d07d8f6857 _CPBlockExpression: replace loops with arrayByApplyingBlock: method 2016-02-04 21:51:37 +01:00
cacaodev 0327f6b1ea Merge remote-tracking branch 'cappuccino/master' into CPArray-arrayByApplyingBlock-replace 2016-02-04 21:46:10 +01:00
Martin Carlberg 16dea2ee09 Fixed: Allow build in directory with space in path 2016-02-03 17:26:24 +01:00
Alexandre Wilhelm 5e3fe139fc Fixed: @cappuccino is now a link in the README... 2016-02-02 13:05:46 -08:00
Alexandre Wilhelm 55d41fca05 New: added twitter account in the READMA 2016-02-02 13:05:01 -08:00
daboe01 0b7bb29557 setString selection fix 2016-01-26 19:16:12 +01:00
cacaodev 6b683bd02d Merge pull request #2402 from cacaodev/CPExpression-constructors
NEW : CPExpression +expressionForBlock:arguments:
                                   +expressionForConditional:trueExpression:falseExpression:
2016-01-25 10:22:18 +01:00
daboe01 8f1a498953 added credits to andrew 2016-01-24 15:33:21 +01:00
daboe01 293ed9065d fix chrome duplicate key inserts cursor 2016-01-24 15:24:12 +01:00
Aparajita Fishman 8908fb7ee0 Merge pull request #2414 from didierkorthoudt/CPTrackingArea-fixes2
FIXED: CPTrackingArea incorrect handling of view hierarchy updates while processing events
2016-01-23 07:02:03 -08:00
Didier Korthoudt 2877178b34 Formatting: following Aparajita's recommandations 2016-01-21 20:46:37 +01:00
Antoine Mercadal d527139f48 Merge pull request #2416 from didierkorthoudt/CPBox-contentView-incorrect-initWithCoder
FIXED: CPBox contentView incorrect initWithCoder
2016-01-20 15:11:37 -08:00
Didier Korthoudt b3d8180541 FORMATTING: added comment to workaround 2016-01-21 00:10:38 +01:00
Didier Korthoudt 3411c340ab FIXED: incorrect view hierarchy update 2016-01-20 23:50:22 +01:00
Didier Korthoudt 4482089712 FIXED: corrected replaceSubview parameters order 2016-01-20 22:08:10 +01:00
Didier Korthoudt c8ce2343d7 Merge remote-tracking branch 'cappuccino/master' 2016-01-20 21:43:35 +01:00
cacaodev d547d04277 NEW: CPViewController -loadViewAsynchronously:(Function/*view, error*/)
with manual test CPViewControllerTest
2016-01-20 11:54:02 +01:00
Antoine Mercadal 00bdbcf857 FIXED: only set a content view of CPBox if it is not a separator 2016-01-19 16:10:31 -08:00
Antoine Mercadal bf8070c42d Revert "FIXED: Bug introduced by https://github.com/cappuccino/cappuccino/commit/9fba72cbab42145dc585c01efd82ce645373c04e#diff-227ef108401c2160357ae3fc65018c65R620"
This reverts commit ad48381744.
2016-01-19 16:08:59 -08:00
Didier Korthoudt 0f30d7744d FIXED: CPTrackingArea incorrect handling of view hierarchy updates while processing events 2016-01-19 07:07:45 +01:00
cacaodev 095a978120 Replace loops with arrayByApplyingBlock: 2016-01-17 20:54:43 +01:00
cacaodev 1b72646772 Style: remove tabs 2016-01-17 20:54:20 +01:00
Didier Korthoudt a7b129147f Merge remote-tracking branch 'cappuccino/master' 2016-01-17 12:32:31 +01:00
Didier Korthoudt ca9039b8d5 Merge remote-tracking branch 'cappuccino/master' 2016-01-16 18:22:20 +01:00
daboe01 0e17658269 use fraction again in cursorUp 2015-12-31 10:42:33 +01:00
daboe01 87edda5972 more cursor up fixes 2015-12-30 21:16:02 +01:00
daboe01 ab8c3c2b75 granular selection refac 2015-12-30 17:35:14 +01:00
daboe01 44cef002ed make selection upon doubleclick more mac like 2015-12-30 15:41:36 +01:00
daboe01 bc80fe693a formatting 2015-12-30 14:49:06 +01:00
daboe01 1898b51dc2 fix for cursor up issue in multiple newlines 2015-12-30 14:39:41 +01:00
daboe01 a5dcf5958e updated credits section 2015-12-30 11:28:07 +01:00
cacaodev 36c417458d STYLE: replaced expression methods with accessors
Also added methods and documentation for the new methods:
-trueExpression, -falseExpression and -expressionBlock.
Completed documentation for -predicate and -arguments.
2015-12-27 22:08:30 +01:00
cacaodev f1591e593a Coding style 2015-12-27 22:03:35 +01:00
cacaodev 117ac0f5d6 FIXED: replace js Array.map function with capp API
Also fixed BlockExpression description to match a little more with
cocoa impl.
2015-12-27 19:31:05 +01:00
cacaodev e72a42fd2d FIXED: block & conditional expressions: support for CPPredicate -predicateWithSubstitutionVariables: 2015-12-27 19:28:03 +01:00
cacaodev 07b6e2b9f1 CPExpression +expressionForConditional:trueExpression:falseExpression:
Conditional Expression : an expression using different expressions for
evaluation, depending of a predicate result.

Support for predicate parsing: ```TERNARY(predicate, trueExpression,
falseExpression)```

With init, equal, evaluation, parsing tests.
2015-12-27 15:45:03 +01:00
cacaodev 5ab10f4024 NEW: CPExpression +expressionForBlock:arguments:
An expression that returns the result of evaluating a block.

With tests.
2015-12-27 15:44:36 +01:00
Didier Korthoudt b32499f6ec Merge remote-tracking branch 'cappuccino/master' 2015-12-22 18:07:02 +01:00
Didier Korthoudt d9819d8b3d Merge remote-tracking branch 'cappuccino/master' 2015-12-22 08:03:54 +01:00
daboe01 a0cbc5822e speedup for chrome 2015-12-21 20:17:51 +01:00
daboe01 65ffce8db2 sheet fix part 2 2015-11-20 20:45:21 +01:00
daboe01 f241f12ddb fix for textview on sheets 2015-11-19 20:03:36 +01:00
Alexandre Wilhelm 9545e0145f Fixed: conflict with auto-merge in CPTextView 2015-09-30 11:31:32 -07:00
Alexandre Wilhelm 15d3e4023b Merge remote-tracking branch 'origin' into NEW--CPTextView 2015-09-30 11:30:18 -07:00
Alexandre Wilhelm 205e4dedd1 Test: updated test CPTextViewCibTest 2015-09-30 11:30:12 -07:00
Alexandre Wilhelm 324d796aca Fixed: issue with typingAttributes and selectingAttributes when the CPTextView was created from a xib 2015-09-30 11:29:55 -07:00
daboe01 5b31e8e9d8 tighten atomicity in kvb 2015-09-30 19:49:04 +02:00
daboe01 0afb62ee88 formatting 2015-09-30 19:46:18 +02:00
daboe01 1d3a8bcacd fix for moveRight: with non-zero length selection 2015-09-30 12:19:04 +02:00
daboe01 dd187aef08 refactor rich copy: to CPTextView 2015-09-30 12:11:39 +02:00
daboe01 78b2c4d094 kvb fix for editable and selectable 2015-09-30 12:00:12 +02:00
daboe01 83876532d0 fix cursor position in empty textview 2015-09-26 22:56:17 +02:00
daboe01 edc824d05e fix moveLeft line issue 2015-09-26 21:09:06 +02:00
daboe01 9a7869dd40 fix select the text just after you have deleted something 2015-09-26 21:03:58 +02:00
daboe01 1aa247d4da no selection after undo 2015-09-26 20:57:25 +02:00
daboe01 93e8ec7f06 formatting 2015-09-02 09:04:39 +02:00
daboe01 ba1d1c3bac fix for recent FF update 2015-09-02 09:02:04 +02:00
daboe01 fbaff2b75b fix for FF40+ 2015-09-02 09:00:29 +02:00
daboe01 9774e8807b fix disappearing cursor 2015-08-31 23:40:18 +02:00
daboe01 b4dd3a9889 typing at the end fix 2015-07-18 17:44:18 +02:00
daboe01 4510b69798 refacturing 2015-07-14 19:29:46 +02:00
daboe01 84a3ee209a fix cursor up newline issues 2015-07-09 20:45:23 +02:00
Alexandre Wilhelm 4b0fe879cb Test: [[CPApplication alloc] init]; in instance setUp method 2015-07-07 14:46:38 -07:00
Alexandre Wilhelm b87aeffcd8 Test: updated unittest 2015-07-07 14:29:50 -07:00
Alexandre Wilhelm 88aafec6e3 Merge branch 'master' into NEW--CPTextView 2015-07-07 14:29:15 -07:00
Alexandre Wilhelm 2cb6ddf3ca Fixed: document was not wrap in a #if PLATFORM 2015-07-07 11:14:56 -07:00
daboe01 799622a932 Merge remote-tracking branch 'upstream/master' into NEW--CPTextView 2015-07-07 18:24:54 +02:00
daboe01 2283652704 add missing ivar 2015-07-05 22:50:21 +02:00
daboe01 33fb2daabf fix shift selection 2015-07-05 14:19:11 +02:00
daboe01 c79f59ec05 fix manual test title 2015-07-05 14:02:30 +02:00
daboe01 845aaad891 fix keywindow observer mechanics 2015-07-05 08:57:25 +02:00
daboe01 3c0b061220 cursor fixes 2015-07-04 21:18:40 +02:00
daboe01 af7de73f5c fix dom protection 2015-07-04 19:24:52 +02:00
daboe01 1a8a9f0047 make dom protection more stringent 2015-07-04 19:17:22 +02:00
daboe01 a3b4e8db44 fix non-working unit test 2015-07-04 17:42:07 +02:00
daboe01 f9e8875803 merge current master in 2015-07-04 16:46:24 +02:00
daboe01 e4c11d9a88 various fixes 2015-07-03 23:13:57 +02:00
daboe01 6d1d8da101 recursion fix 2015-07-03 22:56:58 +02:00
daboe01 77303e668f fix missing reference 2015-07-03 21:03:28 +02:00
daboe01 72725b91c7 fix undefined constant 2015-07-03 20:56:14 +02:00
daboe01 46f50f55c2 various baseline fixes 2015-07-03 20:03:53 +02:00
daboe01 5e880f6bfa Revert "_textContainer refac preparation"
This reverts commit 80cf88dcc1.
2015-07-03 17:26:20 +02:00
daboe01 80cf88dcc1 _textContainer refac preparation 2015-07-02 19:56:54 +02:00
daboe01 dddc7f348f fix lineheight issue during wrapping 2015-07-02 19:48:12 +02:00
daboe01 ce45f2e114 move to end of line fix 2015-07-02 06:03:05 +02:00
daboe01 d22a7c0a63 FF copy paste fix 2015-07-01 22:52:01 +02:00
daboe01 59162155de caret loc refac 2015-07-01 07:20:17 +02:00
daboe01 0f347cd0b4 revert to capp pasteboard 2015-07-01 05:58:12 +02:00
daboe01 dc50793733 cosmetics 2015-06-29 20:58:33 +02:00
daboe01 b98329f91c end of doc fix 2015-06-29 20:54:43 +02:00
daboe01 587d8fbfa9 fix caret position 2015-06-29 20:19:47 +02:00
daboe01 26a2e9ef53 capture mode for copy/paste 2015-06-29 19:43:23 +02:00
daboe01 e5ca98a1d3 fix baseline cross multiple fragments issue 2015-06-28 21:19:33 +02:00
daboe01 5bd5e9000e fix baseline issue with native input 2015-06-28 21:07:51 +02:00
daboe01 d566642c98 improved baseline support 2015-06-28 17:16:24 +02:00
daboe01 f81ddc60ec simplify baseline code 2015-06-28 16:20:06 +02:00
daboe01 6e0b20c921 prepare baseline support 2015-06-28 16:03:23 +02:00
daboe01 0c308b38c5 move to right end simplification 2015-06-28 15:18:59 +02:00
daboe01 8e0fdf68e4 move left/right of line fix 2015-06-28 12:36:40 +02:00
daboe01 9c7a9b5674 cursor up down fix 2015-06-27 16:13:10 +02:00
daboe01 0a49e31b30 add lastmarker to linefrag 2015-06-27 16:01:42 +02:00
daboe01 9478206202 simplify insertText: 2015-06-27 15:43:10 +02:00
daboe01 c86e6f5b88 fix rare invisibility bug 2015-06-27 13:58:58 +02:00
daboe01 87868acecd formatitng 2015-06-27 13:46:31 +02:00
daboe01 6d877754da focusForClipboard fixes 2015-06-27 13:10:53 +02:00
daboe01 dd5521a07c various native deadkey fixes 2015-06-27 13:03:41 +02:00
daboe01 cca142ce86 smart paste at end fix 2015-06-25 20:48:30 +02:00
daboe01 fa3567cb9f fix arrow down last line 2015-06-25 06:03:02 +02:00
daboe01 7d22230b13 keyboard-selection-extension fix 2015-06-25 05:54:34 +02:00
daboe01 1b7f684ab2 make safari fix more robust 2015-06-24 21:14:24 +02:00
daboe01 fef8f4d29c safari backspace fix 2015-06-23 20:36:57 +02:00
daboe01 0d7e945623 fix native cut 2015-06-22 20:30:44 +02:00
daboe01 13ea8eae77 fix initial platform paste 2015-06-21 14:20:14 +02:00
daboe01 cdb2ef3ac7 prevent dom-flickering 2015-06-20 19:11:05 +02:00
daboe01 f216e0198f harmonize capp and system pasteboards 2015-06-20 13:23:33 +02:00
daboe01 c5c3698f43 make undo work again 2015-06-19 23:26:14 +02:00
daboe01 299d3b9f60 formatting 2015-06-19 22:41:12 +02:00
daboe01 eaaebeaebb refactoring paste 2015-06-19 22:39:41 +02:00
daboe01 2ef2d2b9c5 fix native pasteboard support 2015-06-19 22:31:57 +02:00
daboe01 a856b4027b formatting 2015-06-18 20:30:05 +02:00
daboe01 e2f72ecffc prepare baseline support 2015-06-18 20:23:00 +02:00
daboe01 d888bcd473 deadkey backspace safari fix 2015-06-17 20:10:19 +02:00
daboe01 0bfd5fa9a3 fix missing parameters to _flushRange 2015-06-16 19:04:50 +02:00
daboe01 9c05ccef69 preparations for baseline alignment 2015-06-16 18:59:38 +02:00
daboe01 5281b6df77 increase timeout on FF 2015-06-15 20:49:10 +02:00
daboe01 cd5bb6a309 fix deadkey after deadkey on FF 2015-06-15 20:45:58 +02:00
daboe01 94a44d7af4 remove dead code 2015-06-15 19:50:09 +02:00
daboe01 662050b89f formatting 2015-06-14 21:34:19 +02:00
daboe01 3f7f3140eb rich copy fixes 2015-06-14 21:24:40 +02:00
daboe01 dc11d18161 formatting 2015-06-12 17:32:22 +02:00
daboe01 cde83e9d7d smart paste fix 2015-06-12 17:28:48 +02:00
daboe01 1476fda014 backspace fix 2015-06-12 17:22:55 +02:00
daboe01 7a875f2db4 filter out apple command keys 2015-06-11 23:03:44 +02:00
daboe01 b868f37da5 remove call to super cancelOperation:sender 2015-06-10 06:41:15 +02:00
daboe01 9bef5a62dd formatting 2015-06-09 22:46:47 +02:00
daboe01 d1aff30c9e fix invisible deadkey at beginning of newline 2015-06-09 22:43:31 +02:00
daboe01 a356dafde0 enter deadkey on exit 2015-06-09 21:14:38 +02:00
daboe01 09477384fe illegal deadkey sequence fix 2015-06-09 19:26:41 +02:00
daboe01 6b923542e8 invisibility fix 2015-06-08 21:36:30 +02:00
daboe01 9722cf718c mouse down fix 2015-06-08 20:30:24 +02:00
daboe01 702b973c87 fix Dead key input element leaves margin on right 2015-06-08 20:25:56 +02:00
daboe01 d66bbd95f0 add native support for deadkeys 2015-06-07 21:18:27 +02:00
daboe01 aae498509b typing attributes refactoring 2015-06-07 21:00:25 +02:00
daboe01 4987fb5f15 fontpanel color well fix 2015-06-06 19:03:37 +02:00
daboe01 b1ed299286 fix for paragraph style not being carried forward 2015-06-03 22:13:17 +02:00
daboe01 679ac3e5b1 fix caret height on last line 2015-06-02 23:25:55 +02:00
daboe01 181ef788a3 caret height fix 2015-06-02 22:47:53 +02:00
daboe01 d2caa0953f various caret fixes 2015-06-02 22:23:32 +02:00
daboe01 bd6d5ffbb9 formatting 2015-05-29 23:10:28 +02:00
daboe01 a4e41a57d7 make paragraph selection via triple click more mac like 2015-05-27 07:07:51 +02:00
daboe01 e8bb3864e3 smart delete 2015-05-26 07:37:13 +02:00
daboe01 3cd1066a8d backspace undo fix 2015-05-25 22:10:31 +02:00
daboe01 6494b7ea89 smart cut fix 2015-05-25 21:21:32 +02:00
daboe01 2f5d13ac10 smart paste fix 2015-05-24 22:24:52 +02:00
daboe01 c8e6dca263 small refactoring of string sizing init 2015-05-20 19:42:03 +02:00
daboe01 9dec40eca7 init refactoring + cachekey fix 2015-05-20 05:58:32 +02:00
daboe01 4896043599 fix caching issue with numeric strings 2015-05-19 20:22:55 +02:00
daboe01 5f0ddeedd0 draw caret permantently during editing...
...or cursor navigation
2015-05-17 20:43:18 +02:00
daboe01 e679e760ee backspace fix 2015-05-17 20:23:41 +02:00
cacaodev 1b0aa2a9b1 FIXED: test app merge issue with cib. Regenerated cib. 2015-05-11 10:37:00 +02:00
cacaodev a49c230bb2 FiXED: animatorClass when the receiver is a CPView custom subclass. 2015-05-11 10:34:12 +02:00
cacaodev b65749cf70 FIXED : setObject:nil in test app 2015-05-11 10:32:33 +02:00
cacaodev 0cf54a6a03 Fix a 'duplicate class' build error 2015-05-11 10:31:27 +02:00
cacaodev 4d77277f2d Merge branch 'master' of git://github.com/cappuccino/cappuccino into CPAnimationContext 2015-05-11 08:44:20 +02:00
daboe01 8b81506ed3 fix aWidth usecase 2015-05-11 05:56:52 +02:00
cacaodev 24c6509a61 FIXED: build error 'CPDictionary nil object'
CPViewAnimator : default mapping between css and capp props is now
lazily computed instead of a class var.
This was causing a build error because some values were not ready to be
read.
2015-05-10 19:23:41 +02:00
daboe01 3c32c4160d formatting 2015-05-10 18:03:42 +02:00
daboe01 1f912d86e1 small speed improvement
avoid the covering method send
2015-05-10 17:59:26 +02:00
daboe01 9c93ab0b6d fixed confusion between font an cssString 2015-05-10 15:30:40 +02:00
daboe01 6646a20a5d DOM protection 2015-05-10 15:22:56 +02:00
daboe01 92f471c476 move fontHeight to where it is needed 2015-05-10 15:19:26 +02:00
daboe01 4c7ce97650 measureText return type 2015-05-10 15:16:12 +02:00
daboe01 4d1fc994c0 refactor private sizing method to sizeWithFont: 2015-05-10 15:12:31 +02:00
daboe01 c4310c554e make DOM sizing faster 2015-05-10 13:37:36 +02:00
Alexandre Wilhelm 4ebcf40619 Fixed: make travis happy with DOM elements in CPTextView 2015-05-04 14:03:33 -07:00
Alexandre Wilhelm a884b94ac0 Test: fixe global var in CPTextViewTest.j 2015-05-04 14:02:46 -07:00
Alexandre Wilhelm 194e705982 Test: comment future test for CPTextView 2015-05-01 16:09:08 -07:00
Alexandre Wilhelm c77ec3bf20 Fixed: added coder for delegate of a CPTextView 2015-05-01 16:08:49 -07:00
Alexandre Wilhelm 0a1857249b Test: updated manual test CPTextViewCibTest 2015-05-01 16:08:30 -07:00
cacaodev 03bd5ad426 Fixed merge issue 2015-04-11 19:26:30 +02:00
Alexandre Wilhelm 82d0f62d73 Added unittest for CPTextView 2015-04-08 13:53:10 -07:00
Alexandre Wilhelm 041fce743e New: added new options in nib2cib for CPTextView. It now supports the paragraphStyle, font and textColor 2015-03-31 18:17:57 -07:00
Alexandre Wilhelm ad4904a0ec Added nib2cib options _allowsUndo and _usesFontPanel for CPTextView 2015-03-31 16:38:47 -07:00
Alexandre Wilhelm 42a1bca64d Fixed: style in CPTextView 2015-03-31 16:08:16 -07:00
Alexandre Wilhelm 492a5bbb38 Fixed: memory leaks with delegate of CPTextStorage. Added protocol CPTextStorageDelegate 2015-03-31 15:48:15 -07:00
Alexandre Wilhelm c40ef22c20 New: create class _CPSelectionBox 2015-03-31 15:34:23 -07:00
Alexandre Wilhelm 783aac561a Fixed: capp_lint on AppKit/CPTextView 2015-03-31 15:14:15 -07:00
Alexandre Wilhelm 02245c150c Fixed: small issue due to refactoring 2015-03-31 15:10:59 -07:00
Alexandre Wilhelm 54a93775e4 Merge branch 'NEW--CPTextView' of https://github.com/daboe01/cappuccino into NEW--CPTextView 2015-03-31 15:05:53 -07:00
Alexandre Wilhelm ca778aac70 Merge remote-tracking branch 'origin' into NEW--CPTextView 2015-03-31 15:04:35 -07:00
cacaodev c75f1685c5 _CPObjectAnimator & CPViewAnimator
Make subclassing easier.
For a specific animator, can choose the implementation to invoke by
subclassing - (id) forwardingTargetForSelector:

The pattern for the animator class, if no -(id)animator is implemented,
is now <TargetClass>Animator by default and it searches for a
<TargetSuperClass>Animator if necessary.

NEW: Added support for CPAnimationTriggerOrderIn|Out animated key.
2015-03-31 00:33:28 +02:00
cacaodev db5b103ab3 Merge remote-tracking branch 'upstream/master' into CPAnimationContext 2015-03-30 22:20:46 +02:00
daboe01 b2f1c9e832 moved _CPCaret to the end 2015-03-28 21:06:28 +01:00
daboe01 cff4eebb74 caret refactoring + delegate notification fix 2015-03-28 20:59:17 +01:00
daboe01 a3aab5aeca prevent delegate related memory leaks 2015-03-28 19:59:33 +01:00
daboe01 63e5d8f7ea acceptsFirstResponder cleanup 2015-03-28 19:39:03 +01:00
daboe01 e4df7b10f6 _backgroundColor' is already declared for class CPText in superclass CPView 2015-03-28 15:27:37 +01:00
daboe01 f39a1e7d03 move inherited properties to CPText 2015-03-28 15:22:52 +01:00
daboe01 a473f6aa16 richTextPropery 2015-03-28 15:05:58 +01:00
daboe01 6907c24690 fix access to editable propery 2015-03-28 15:01:33 +01:00
daboe01 ef3d8a9277 fix access to selectable property 2015-03-28 14:59:13 +01:00
cacaodev 1a183b7f17 Merge remote-tracking branch 'upstream/master' into CPAnimationContext 2015-03-27 21:56:08 +01:00
daboe01 ae6bcc2987 improve critically low performance in safari
by means of caching cheap sizing data.
2015-03-24 09:59:58 +01:00
Alexandre Wilhelm ed61e5c7f7 Added test file CPTextViewTest.j 2015-03-23 20:56:40 -07:00
Alexandre Wilhelm 3581ac5ebd Fixed: nib2cib with CPTextView works. Editable, Selectable, RichText, StringValue, BackgroundColor, InsertionPointColor works 2015-03-23 14:50:43 -07:00
Alexandre Wilhelm 1f369b47d7 Added hierarchy for nib2cib of a CPTextView. NSTextViewSharedData is a object to retrieve attributes of the CPTextView 2015-03-23 13:06:22 -07:00
Alexandre Wilhelm 51ec699649 Removed tmp files... 2015-03-20 12:23:38 -07:00
Alexandre Wilhelm ed6be510fb Fixed: first work on nib2cib for the CPTextView. The example does not crash anymore 2015-03-20 12:22:23 -07:00
Alexandre Wilhelm 55f05ba839 Fixed: warnings when compiling 2015-03-20 10:03:42 -07:00
Alexandre Wilhelm 17c9382a21 Merge remote-tracking branch 'origin' into NEW--CPTextView 2015-03-20 09:52:51 -07:00
cacaodev 50a53181dc Merge remote-tracking branch 'origin/CPAnimationContext' into CPAnimationContext
Conflicts:
	AppKit/CoreAnimation/CPViewAnimator.j
	Tests/Manual/CPAnimatablePropertyContainerTest/Resources/MainMenu.cib
	Tests/Manual/CPAnimatablePropertyContainerTest/Resources/MainMenu.xib
2015-03-14 21:31:12 +01:00
cacaodev 36f6fec99f Merge remote-tracking branch 'upstream/master' into CPAnimationContext
Conflicts:
	AppKit/CPView.j
2015-03-14 21:18:18 +01:00
cacaodev e9ae8063db Allow nil completionFunction and fix fallback == nil 2015-03-13 18:52:05 +01:00
cacaodev 9844550d6c Use the translate(x,y) property for frameOrigin animated keyPath
Also adds a startValue arg to the function translating Capp values to
css values (needed for translate because you translate the offset).
CPViewAnimator: when ensuing animations, separate the fallback (the
function executed when animation are not supported) and the completion
function executed when the animation ends.
Cleanup xib in manual test: removed controls.
2015-03-09 21:15:17 +01:00
cacaodev 82fcf08d84 Rename 2015-03-08 21:52:42 +01:00
cacaodev b951624ed3 Merge remote-tracking branch 'origin/CPAnimationContext' into CPAnimationContext
Conflicts:
	AppKit/CoreAnimation/CPAnimationContext.j
	AppKit/CoreAnimation/CPViewAnimator.j
2015-03-07 20:03:05 +01:00
cacaodev 1b21f2d1c7 CPView (Animation) : simplified CSS_DESCRIPTORS.
Now easiest to subclass and not much more verbose.
CPVIEW_PROPERTIES_DESCRIPTOR is, for a given CPView subclass, the
mapping between animated keypaths and css properties and between
animated values and css values.
2015-03-07 19:51:13 +01:00
cacaodev 43ea0effa2 Replace objj FrameUpdater with a js function.
Also uses the native function window.requestAnimationFrame();
Expected improvement: the effective redraws should now happen only when
needed.
browser support = same as css animations.
2015-03-07 19:45:06 +01:00
cacaodev 6df9b95dea Code style. NEW CPView -DOMElementForKeyPath:keyPath:
-DOMElementForKeyPath:keyPath returns the DOMElement animated by the
css Animation. This allow for an element different from the view
_DOMElement to be animated.
2015-03-07 19:38:48 +01:00
cacaodev cd7b9d31c9 Merge remote-tracking branch 'upstream/master' into CPAnimationContext 2015-03-03 23:03:10 +01:00
daboe01 cbb4565a48 timer support for drag-scrolling 2015-03-01 21:16:49 +01:00
daboe01 fc2f5c3615 formatting 2015-02-26 05:55:04 +01:00
daboe01 3a5ac9df10 formatting 2015-02-26 05:53:37 +01:00
daboe01 e8497bb0cc typing attributes fix 2015-02-25 20:20:48 +01:00
daboe01 fa6a5f75af fractional clicking support 2015-02-24 20:39:42 +01:00
daboe01 7b9eb4c87c color well font panel sync 2015-02-24 20:22:03 +01:00
daboe01 c3ab510b57 fix copy paste of curly braces 2015-02-22 20:55:38 +01:00
daboe01 e9efe5bbb7 fix cornercases 2015-02-21 20:01:53 +01:00
daboe01 a7c234b272 smart copy paste 2015-02-21 15:14:50 +01:00
cacaodev 80c8dcacb3 Code Style 2015-02-02 20:15:44 +01:00
cacaodev 0ad2dea722 Merge remote-tracking branch 'upstream/master' into CPAnimationContext 2015-01-30 22:35:01 +01:00
cacaodev dec3c45f6c Merge remote-tracking branch 'upstream/master' into CPAnimationContext 2015-01-29 15:09:08 +01:00
Andrew Hankinson 5736d2c9cc Formatting: CPView
Previously CPView used "==" as an equality checker. This commit changes these to use "===" for consistency.
2015-01-22 13:31:04 -05:00
Andrew Hankinson dc622a9bd5 Merge branch 'refs/heads/master' into NEW--CPTextView 2015-01-14 17:23:50 -05:00
cacaodev 3ddd1d5f21 Added CPAnimatablePropertyContainer protocol 2014-12-19 16:01:49 +01:00
cacaodev ea15f0690c FIXED: compilers warnings in _CPObjectAnimator 2014-12-18 23:40:56 +01:00
Andrew Hankinson 8751ef7439 Fixed: Wrap drawRect method in #if/#endif 2014-12-18 11:04:08 -05:00
Andrew Hankinson 8c393e3144 Fixed: removed self on _DOMElement
Also a bit of formatting.
2014-12-18 09:47:00 -05:00
Andrew Hankinson a3ef2a43ac Fix file modes on CPTextView files
Was 755; now 644
2014-12-17 20:48:29 -05:00
Andrew Hankinson d2b3029f67 Fixed: Removed local declaration of _DOMElement 2014-12-17 20:47:12 -05:00
Andrew Hankinson 3e800ec7c8 Fixing type for DOM Elements
This commit fixes the type for DOM Elements in CPTextView.j
2014-12-17 12:40:24 -05:00
Andrew Hankinson 47d963b585 Fixed: Forward declaration of classes and types
Typedef in the ObjJ compiler introduced a few new warnings in this branch. This commit fixes the warnings by either declaring a type or forward-declaring a class.
2014-12-17 12:39:39 -05:00
Andrew Hankinson 397ae3407e Merge branch 'refs/heads/master' into NEW--CPTextView
Conflicts:
	AppKit/CPControl.j
2014-12-17 12:11:27 -05:00
cacaodev 3f9e2d5d39 CPAnimationContext : add typedef for HashTable 2014-12-09 22:36:37 +01:00
cacaodev 31449552d1 Merge remote-tracking branch 'upstream/master' into CPAnimationContext
Conflicts:
	AppKit/CPView.j
2014-12-09 22:35:29 +01:00
daboe01 5f2fee5a99 redo support added 2014-11-29 18:57:05 +01:00
Andrew Hankinson bd71e779c3 Merge branch 'refs/heads/master' into NEW--CPTextView 2014-10-30 14:35:47 -04:00
daboe01 18d83b8c50 fix range exception when smart-cutting last word 2014-10-20 18:51:26 +02:00
daboe01 49c7e7ce2d style 2014-09-15 20:10:24 +02:00
daboe01 1af7d01d96 fix of resizing regression 2014-09-15 18:20:53 +02:00
daboe01 66c6938df0 changed selection drawing from canvas to DOM
fixes height limitation, is faster and looks better
2014-09-14 21:24:23 +02:00
daboe01 bb9fb04788 make triple clicks behave more apple like 2014-09-13 20:24:27 +02:00
daboe01 f5cf2b2b55 fix selecting last character 2014-09-13 20:13:08 +02:00
daboe01 43169ced69 fix of the fix 2014-09-11 10:45:27 +02:00
daboe01 708844857d make canvas sizing detection more robust 2014-09-11 10:22:50 +02:00
daboe01 ce777348b3 cursor up/down+ frames protection 2014-08-20 23:09:53 +02:00
daboe01 c052325487 various fixes and cleanup 2014-08-20 22:39:15 +02:00
daboe01 ce69410f49 revert of breaking change wrt backspace 2014-08-14 18:21:53 +02:00
daboe01 5f0be0cc7f make storage length zero more tolerant 2014-08-14 14:14:49 +02:00
Andrew Hankinson dca6347ea9 Fixed: Remove lingering references to i
Refs 75e347e8e3
2014-08-14 07:19:53 -04:00
daboe01 94c4db9072 fixed equality operator 2014-08-14 07:17:00 +02:00
Andrew Hankinson 7f63be2cd2 Formatting: Make if statement more readable
The if statement had a lot of sub-clauses. These were factored out into variable assignments.
2014-08-13 19:56:50 -04:00
Andrew Hankinson 1236dea4c5 Fixed: equality operators 2014-08-13 19:47:06 -04:00
Andrew Hankinson c5c46df613 Fixed: typo 2014-08-13 19:44:23 -04:00
Andrew Hankinson a96269150a Fixed: AppKit.j is alphabetized
CPTextView.j was out of alphabetical order. This commit fixes that.
2014-08-13 19:34:56 -04:00
Andrew Hankinson 75e347e8e3 Fixed: obscure use of variables
Previously, the counting variable "i" was used as a variable throughout this method, leading to the value of 'i' becoming unclear as the method progressed.

Additionally, a later loop in this method redeclared 'i', providing more confusion.

This commit renames 'i' to the more descriptive 'targetLine' and uses that in its place. The redeclared value of 'i' was also renamed to "newTargetLine".
2014-08-13 18:15:58 -04:00
daboe01 d641cc5057 fix fussy optimization 2014-08-14 00:12:02 +02:00
daboe01 cf64145ff3 formatting 2014-08-12 16:06:49 +02:00
daboe01 195eca6b09 typesetter early exit in flushing fix 2014-08-12 15:48:31 +02:00
daboe01 b0ef077e48 fix typesetter nil bug 2014-08-12 15:12:19 +02:00
daboe01 e40a698d1a fixed accessor 2014-08-12 10:37:05 +02:00
daboe01 69c34b1b27 formatting 2014-08-12 08:33:28 +02:00
daboe01 4700c2583d fix acessor names 2014-08-12 08:29:28 +02:00
daboe01 6cf79a3c73 size should not be smaller than clipview 2014-08-06 13:31:31 +02:00
daboe01 2c110f7796 fixed: display error at bottom in case of resizing 2014-08-06 13:17:35 +02:00
daboe01 aebea0b57f Update CPTypesetter.j 2014-08-04 13:27:42 +02:00
daboe01 8684455ea5 make canvas sizing validity detection more robust 2014-08-04 13:22:38 +02:00
daboe01 7cbb103376 fix selecting last newline error 2014-07-31 20:35:29 +02:00
daboe01 9cf8ec5dd7 formatting 2014-07-20 19:55:49 +02:00
daboe01 f5187b1533 _characterRangeForUn...: ternary operator 2014-07-20 11:44:03 +02:00
daboe01 6230a65a79 removed useless unit test 2014-07-20 11:24:22 +02:00
Alexandre Wilhelm f13c96839e Fixed synthax in CPTextView 2014-07-19 19:07:08 -07:00
Alexandre Wilhelm 776f68c9dd Fixed style in CPTextView 2014-07-19 18:46:25 -07:00
Alexandre Wilhelm 714ed89a4c Merged 2014-07-19 16:58:59 -07:00
daboe01 0b2b29b7cf removed unit test 2014-07-12 14:09:59 +02:00
Alexandre Wilhelmanddaboe01 a41c0a0519 Fixed: Update test CPTextViewCibTest 2014-07-12 14:03:32 +02:00
Alexandre Wilhelmanddaboe01 026e28114e Added : added default NSTextView for nib2cib 2014-07-12 14:03:32 +02:00
Alexandre Wilhelmanddaboe01 0840719289 Added: added CPTextViewCibTest 2014-07-12 14:03:32 +02:00
daboe01 aad875e113 make the plain look as white as in cocoa 2014-07-12 14:03:32 +02:00
Alexandre Wilhelmanddaboe01 6b059d94ba Fixed: reduce size of the test of CPTextView 2014-07-12 14:03:32 +02:00
Alexandre Wilhelmanddaboe01 39eeaea7e7 Fixed: circular import with CPText
Previously CPText was in CPTextView.j, now it is in CPText.j.
It fixes some other circular import as well, fixes some global var to import.
Fixed some code style.
2014-07-12 14:03:32 +02:00
daboe01 81a8e91180 fix cut with empty selection 2014-07-12 13:58:39 +02:00
Alexandre Wilhelmanddaboe01 4fc6f6f59b Fixed: refactoring delegate methods 2014-07-12 13:58:39 +02:00
Alexandre Wilhelmanddaboe01 dd2f573f27 Fixed: changed a bit the readability of the file 2014-07-12 13:58:39 +02:00
Alexandre Wilhelmanddaboe01 ff8ddc431b New: Added protocol CPTextViewDelegate 2014-07-12 13:58:38 +02:00
daboe01 d703945aa3 corrected inheritance 2014-07-12 13:58:38 +02:00
Alexandre Wilhelmanddaboe01 f4aba5f9ea New: Added protocol CPTextDelegate 2014-07-12 13:58:38 +02:00
Alexandre Wilhelmanddaboe01 393113c3e3 Fixed: capp_lint 2014-07-12 13:58:38 +02:00
Alexandre Wilhelmanddaboe01 f2db18820a Fixed: CPLog.error is used instead of abstract exception 2014-07-12 13:58:38 +02:00
daboe01 e04d300e18 next try 2014-07-12 13:58:38 +02:00
daboe01 685f836f41 another try 2014-07-12 13:58:38 +02:00
daboe01 d4f5ad641a more dom protection 2014-07-12 13:58:38 +02:00
daboe01 007d437ee8 dom projection 2014-07-12 13:58:38 +02:00
daboe01 00e380e8d8 more dom protection 2014-07-12 13:58:38 +02:00
daboe01 56749d9494 protecting document access with PLATFORM(DOM) 2014-07-12 13:58:38 +02:00
daboe01 cf10d37c90 automated tests and cleanup 2014-07-12 13:58:38 +02:00
daboe01 f9de34e36d font panel fix 2014-07-12 13:58:38 +02:00
daboe01 aa889be140 formatting 2014-07-12 13:58:38 +02:00
daboe01 6da6838bde beginning/end of line navigation + cleanup 2014-07-12 13:58:37 +02:00
daboe01 07a0be303f smart cutting+cleanup 2014-07-12 13:58:37 +02:00
daboe01 ddbe0af290 fix <cr> issue 2014-07-12 13:58:37 +02:00
daboe01 e71f0f44a4 fix relayouting optimization bug 2014-07-12 13:58:37 +02:00
daboe01 39f3bc7100 better workaorund for chrome bug 2014-07-12 13:58:37 +02:00
daboe01 211a145e58 stability improvement 2014-07-12 13:58:37 +02:00
daboe01 d2339b915f spooky chrome fix 2014-07-12 13:58:37 +02:00
daboe01 24c2651745 reverting erroneous patch 2014-07-12 13:58:37 +02:00
daboe01 36e95b93b4 typesetter fix 2014-07-12 13:58:37 +02:00
daboe01 e7a44e0b15 removed debugging code 2014-07-12 13:58:37 +02:00
daboe01 fbdb21ac72 style 2014-07-12 13:58:37 +02:00
daboe01 c9522cf6ae more style 2014-07-12 13:58:37 +02:00
daboe01 7bf9d334ad style 2014-07-12 13:58:37 +02:00
daboe01 422ff93dcd added support for setWidthTracksTextView: 2014-07-12 13:58:37 +02:00
daboe01 eee1ea7a09 fontmanager fix 2014-07-12 13:58:36 +02:00
daboe01 b90e482add typo 2014-07-12 13:58:36 +02:00
daboe01 875b51720b more missing prototypes 2014-07-12 13:58:36 +02:00
daboe01 5272d4f9e3 style 2014-07-12 13:58:36 +02:00
daboe01 c980f4f6e3 prototypes+style 2014-07-12 13:58:36 +02:00
daboe01 89525330c4 formatting+prototypes 2014-07-12 13:58:36 +02:00
daboe01 806db24c0e formatting+ fix prototypes 2014-07-12 13:58:36 +02:00
daboe01 ba7d6df5a4 formatting 2014-07-12 13:58:36 +02:00
daboe01 112301e0e0 formatting 2014-07-12 13:58:36 +02:00
daboe01 c07065e457 more formatting 2014-07-12 13:58:36 +02:00
daboe01 b9e1afae17 formatting 2014-07-12 13:58:36 +02:00
daboe01 549b4a9ebf formatting 2014-07-12 13:58:36 +02:00
daboe01 fa9a3fb7c4 formatting 2014-07-12 13:58:36 +02:00
daboe01 ccb15f278a formatting 2014-07-12 13:58:36 +02:00
daboe01 f0fb4b8842 formatting 2014-07-12 13:58:35 +02:00
daboe01 dacaf293b2 fix of circular imports 2014-07-12 13:58:35 +02:00
daboe01 627d0e4e6f fix circular imports 2014-07-12 13:58:35 +02:00
daboe01 f32b9e26e0 eliminate warnings + style 2014-07-12 13:58:35 +02:00
daboe01 db2b1a0a35 typos 2014-07-12 13:58:35 +02:00
daboe01 f734a60c62 manual test 2014-07-12 13:58:35 +02:00
daboe01 9aa815c1ed CPTextView commit 2014-07-12 13:58:35 +02:00
cacaodev e0772500c9 Merge remote-tracking branch 'upstream/master' into CPAnimationContext
Conflicts:
	AppKit/CPView.j
2014-06-11 20:24:46 +02:00
Alexandre Wilhelm 718f79775e Fixed: Update test CPTextViewCibTest 2014-06-04 16:30:05 -07:00
Alexandre Wilhelm 4261c1768a Added : added default NSTextView for nib2cib 2014-06-04 16:29:45 -07:00
Alexandre Wilhelm 01603185c3 Added: added CPTextViewCibTest 2014-06-04 15:00:12 -07:00
daboe01 f1adf24f3b make the plain look as white as in cocoa 2014-06-04 18:34:46 +02:00
Alexandre Wilhelm 856765a775 Fixed: reduce size of the test of CPTextView 2014-06-03 21:15:21 -07:00
Alexandre Wilhelm 075da34cdb Fixed: circular import with CPText
Previously CPText was in CPTextView.j, now it is in CPText.j.
It fixes some other circular import as well, fixes some global var to import.
Fixed some code style.
2014-06-03 21:05:04 -07:00
daboe01 5ce543002d fix cut with empty selection 2014-06-02 20:39:53 +02:00
Alexandre Wilhelm 700b1c50af Fixed: refactoring delegate methods 2014-05-30 12:27:43 -07:00
Alexandre Wilhelm 9e1c363a0a Fixed: changed a bit the readability of the file 2014-05-30 12:04:51 -07:00
Alexandre Wilhelm bbe3065f19 Merge branch 'NEW--CPTextView' of https://github.com/daboe01/cappuccino into NEW--CPTextView 2014-05-30 11:37:50 -07:00
Alexandre Wilhelm 1716a0ebca New: Added protocol CPTextViewDelegate 2014-05-30 11:37:37 -07:00
daboe01 ed66339e94 corrected inheritance 2014-05-30 20:36:14 +02:00
Alexandre Wilhelm 441774e61c New: Added protocol CPTextDelegate 2014-05-30 11:27:31 -07:00
Alexandre Wilhelm c6fd14afd2 Fixed: capp_lint 2014-05-30 11:12:29 -07:00
Alexandre Wilhelm 27ed9ca7fd Merge branch 'NEW--CPTextView' of https://github.com/daboe01/cappuccino into NEW--CPTextView 2014-05-30 10:58:29 -07:00
Alexandre Wilhelm 50fda906bd Fixed: CPLog.error is used instead of abstract exception 2014-05-30 10:49:10 -07:00
daboe01 6c7c60037b next try 2014-05-30 19:44:37 +02:00
daboe01 91a429ea77 another try 2014-05-30 19:19:15 +02:00
daboe01 2dbe01e90a more dom protection 2014-05-30 18:52:00 +02:00
daboe01 3d7dd41223 dom projection 2014-05-30 17:17:28 +02:00
daboe01 91495c8595 more dom protection 2014-05-29 20:37:27 +02:00
daboe01 c3e997168a protecting document access with PLATFORM(DOM) 2014-05-29 20:31:55 +02:00
daboe01 c3e6f4f7b6 automated tests and cleanup 2014-05-29 16:27:07 +02:00
daboe01 e600ec95ed font panel fix 2014-05-25 09:27:54 +02:00
daboe01 cbd5853389 formatting 2014-05-24 19:32:25 +02:00
daboe01 4e3a086993 beginning/end of line navigation + cleanup 2014-05-24 08:53:53 +02:00
daboe01 5f23dfb034 smart cutting+cleanup 2014-05-23 21:46:59 +02:00
daboe01 99f59490a3 fix <cr> issue 2014-05-23 13:14:29 +02:00
daboe01 4a44b35ea5 fix relayouting optimization bug 2014-04-18 17:17:01 +02:00
daboe01 47aafe9042 better workaorund for chrome bug 2014-04-18 13:28:51 +02:00
daboe01 53d94a1d3d stability improvement 2014-04-18 00:41:33 +02:00
daboe01 5dd3c7c8e8 spooky chrome fix 2014-04-18 00:36:18 +02:00
daboe01 0c2a13f27f reverting erroneous patch 2014-04-17 14:26:01 +02:00
daboe01 da0d3133df typesetter fix 2014-04-17 11:11:53 +02:00
daboe01 7abd9a3db9 removed debugging code 2014-04-17 10:03:24 +02:00
daboe01 98b9f57e0e style 2014-04-17 10:00:50 +02:00
daboe01 e064ccd585 more style 2014-04-17 09:59:36 +02:00
daboe01 b5a63ed3fc style 2014-04-17 09:58:04 +02:00
daboe01 147edddb90 added support for setWidthTracksTextView: 2014-04-17 09:55:25 +02:00
cacaodev 4b8a91fb8c Merge remote-tracking branch 'upstream/master' into CPAnimationContext
Conflicts:
	AppKit/CPCompatibility.j
2014-02-21 20:39:35 +01:00
daboe01 4fb677ed23 fontmanager fix 2014-02-19 20:55:05 +01:00
daboe01 4f0bd7f461 typo 2014-02-18 20:08:39 +01:00
daboe01 01eecdb698 more missing prototypes 2014-02-18 20:07:29 +01:00
daboe01 5ca41a6fff style 2014-02-15 19:47:50 +01:00
daboe01 e4f71420fc prototypes+style 2014-02-15 12:43:09 +01:00
daboe01 d5456ed1db formatting+prototypes 2014-02-14 18:09:04 +01:00
daboe01 e3335c5843 formatting+ fix prototypes 2014-02-14 18:05:45 +01:00
daboe01 067e6bf93d formatting 2014-02-12 18:00:11 +01:00
daboe01 13dc31dc1f formatting 2014-02-12 07:14:49 +01:00
daboe01 7f6bf21270 more formatting 2014-02-12 07:13:21 +01:00
daboe01 d647258856 formatting 2014-02-12 05:59:34 +01:00
daboe01 1eb7ed5e9c formatting 2014-02-11 22:04:39 +01:00
daboe01 e78f1b05a7 formatting 2014-02-11 20:33:47 +01:00
daboe01 e45140b7ea formatting 2014-02-10 21:28:25 +01:00
daboe01 41747a7a04 formatting 2014-02-10 21:25:56 +01:00
daboe01 e448430d8a fix of circular imports 2014-02-10 21:07:57 +01:00
daboe01 394b1a1602 fix circular imports 2014-02-10 06:02:28 +01:00
daboe01 85abd5a8c3 eliminate warnings + style 2014-02-09 11:00:25 +01:00
daboe01 b9e0eb5b76 typos 2014-02-08 21:14:56 +01:00
daboe01 a8eae73b66 manual test 2014-02-08 20:46:04 +01:00
daboe01 9edd8d6f66 CPTextView commit 2014-02-08 20:43:15 +01:00
cacaodev e5d883f97e CAKeyframeAnimation
CPAnimatablePropertyContainer protocol (CPView)
CPAnimationContext
_CPObjectAnimator CPViewAnimator
CSS Animations wrapper

CPAnimatablePropertyContainerTest : animations of views with custom Layout / Regular Layout / Custom DrawRect: / No DrawRect: / Subviews / No Subviews and combinations of these situations.
controls animation (text field, button, popup, slider ...). They animate their size via their action.
2013-04-13 16:29:43 +02:00
453 changed files with 36714 additions and 19382 deletions
+1
View File
@@ -17,3 +17,4 @@ Tests/Manual/**/*.xcodeproj
*.sublime-project
*.sublime-workspace
*.tm_properties
*.idea
+3
View File
@@ -27,6 +27,7 @@
@import "CPAccordionView.j"
@import "CPAlert.j"
@import "CPAnimation.j"
@import "CPAnimationContext.j"
@import "CPAppearance.j"
@import "CPApplication.j"
@import "CPArrayController.j"
@@ -100,6 +101,7 @@
@import "CPTabView.j"
@import "CPText.j"
@import "CPTextField.j"
@import "CPTextView.j"
@import "CPTokenField.j"
@import "CPToolbar.j"
@import "CPToolbarItem.j"
@@ -107,6 +109,7 @@
@import "CPTreeNode.j"
@import "CPUserDefaultsController.j"
@import "CPView.j"
@import "CPViewAnimator.j"
@import "CPViewAnimation.j"
@import "CPViewController.j"
@import "CPVisualEffectView.j"
+1 -1
View File
@@ -216,7 +216,7 @@ var CPApplicationDelegate_applicationShouldTerminate_ = 1 << 0,
}
if ([_delegate respondsToSelector:@selector(applicationShouldTerminate:)])
_implementedDelegateMethods |= CPApplicationDelegate_applicationShouldTerminate_
_implementedDelegateMethods |= CPApplicationDelegate_applicationShouldTerminate_;
if ([_delegate respondsToSelector:@selector(applicationShouldTerminateMessage:)])
_implementedDelegateMethods |= CPApplicationDelegate_applicationShouldTerminateMessage_
+1 -1
View File
@@ -563,7 +563,7 @@
*/
- (BOOL)setSelectionIndexes:(CPIndexSet)indexes
{
[self _selectionWillChange]
[self _selectionWillChange];
var r = [self __setSelectionIndexes:indexes avoidEmpty:NO];
[self _selectionDidChange];
return r;
+21 -2
View File
@@ -598,7 +598,8 @@ var CPBoxTypeKey = @"CPBoxTypeKey",
CPBoxBorderTypeKey = @"CPBoxBorderTypeKey",
CPBoxTitle = @"CPBoxTitle",
CPBoxTitlePosition = @"CPBoxTitlePosition",
CPBoxTitleView = @"CPBoxTitleView";
CPBoxTitleView = @"CPBoxTitleView",
CPBoxContentView = @"CPBoxContentView";
@implementation CPBox (CPCoding)
@@ -615,8 +616,25 @@ var CPBoxTypeKey = @"CPBoxTypeKey",
_titlePosition = [aCoder decodeIntForKey:CPBoxTitlePosition];
_titleView = [aCoder decodeObjectForKey:CPBoxTitleView] || [CPTextField labelWithTitle:_title];
_contentView = [self subviews][0];
if (_boxType != CPBoxSeparator)
{
// FIXME: we have a problem with CIB decoding here.
// We should be able to simply add : _contentView = [self subviews][0]
// but first box subview seems to be malformed (badly decoded).
// For example, when deployed, this view doesn't have its _trackingAreas array initialized.
// As a (temporary) workaround, we encode/decode the _contentView property. We then transfer the subview hierarchy
// and replace the first (and only) box subview with this _contentView
_contentView = [aCoder decodeObjectForKey:CPBoxContentView] || [[CPView alloc] initWithFrame:[self bounds]];
var malformedContentView = [self subviews][0];
[_contentView setSubviews:[malformedContentView subviews]];
[self replaceSubview:malformedContentView with:_contentView];
}
else
{
_titlePosition = CPNoTitle;
}
[self setAutoresizesSubviews:YES];
[_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable];
@@ -635,6 +653,7 @@ var CPBoxTypeKey = @"CPBoxTypeKey",
[aCoder encodeObject:_title forKey:CPBoxTitle];
[aCoder encodeInt:_titlePosition forKey:CPBoxTitlePosition];
[aCoder encodeObject:_titleView forKey:CPBoxTitleView];
[aCoder encodeObject:_contentView forKey:CPBoxContentView];
}
@end
+1 -1
View File
@@ -378,7 +378,7 @@ CPButtonImageOffset = 3.0;
- (void)setImage:(CPImage)anImage
{
[self setValue:anImage forThemeAttribute:@"image"];
[self setValue:anImage forThemeAttribute:@"image" inState:CPThemeStateNormal];
}
- (CPImage)image
+43 -24
View File
@@ -31,6 +31,7 @@
@import "CPDragServer_Constants.j"
@import "CPPasteboard.j"
@import "CPView.j"
@import "CPKeyValueBinding.j"
@class _CPCollectionViewDropIndicator
@@ -55,7 +56,7 @@ var CPCollectionViewDelegate_collectionView_acceptDrop_index_dropOperation_
- (CPData)collectionView:(CPCollectionView)collectionView dataForItemsAtIndexes:(CPIndexSet)indices forType:(CPString)aType;
- (CPDragOperation)collectionView:(CPCollectionView)collectionView validateDrop:(id)draggingInfo proposedIndex:(CPInteger)proposedDropIndex dropOperation:(CPCollectionViewDropOperation)proposedDropOperation;
- (CPMenu)collectionView:(CPCollectionView)collectionView menuForItemAtIndex:(CPInteger)anIndex;
- (CPView)collectionView:(CPCollectionView)collectionView dragginViewForItemsAtIndexes:(CPIndexSet)indexes withEvent:(CPEvent)event offset:(CGPoint)dragImageOffset;
- (CPView)collectionView:(CPCollectionView)collectionView draggingViewForItemsAtIndexes:(CPIndexSet)indexes withEvent:(CPEvent)event offset:(CGPoint)dragImageOffset;
- (void)collectionView:(CPCollectionView)collectionView didDoubleClickOnItemAtIndex:(int)index;
@end
@@ -132,7 +133,6 @@ var HORIZONTAL_MARGIN = 2;
CGSize _storedFrameSize;
BOOL _uniformSubviewsResizing @accessors(property=uniformSubviewsResizing);
BOOL _lockResizing;
CPInteger _currentDropIndex;
CPDragOperation _currentDragOperation;
@@ -140,6 +140,14 @@ var HORIZONTAL_MARGIN = 2;
_CPCollectionViewDropIndicator _dropView;
}
+ (Class)_binderClassForBinding:(CPString)aBinding
{
if (aBinding == CPContentBinding)
return [_CPCollectionViewContentBinder class];
return [super _binderClassForBinding:aBinding];
}
- (id)initWithFrame:(CGRect)aFrame
{
self = [super initWithFrame:aFrame];
@@ -182,7 +190,7 @@ var HORIZONTAL_MARGIN = 2;
_needsMinMaxItemSizeUpdate = YES;
_uniformSubviewsResizing = NO;
_lockResizing = NO;
_inLiveResize = NO;
_currentDropIndex = -1;
_currentDragOperation = CPDragOperationNone;
@@ -384,14 +392,7 @@ var HORIZONTAL_MARGIN = 2;
_isSelectable = isSelectable;
if (!_isSelectable)
{
var index = CPNotFound,
itemCount = [_items count];
// Be wary of invalid selection ranges since setContent: does not clear selection indexes.
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) != CPNotFound && index < itemCount)
[_items[index] setSelected:NO];
}
[self _applySelectionToItems:NO];
}
/*!
@@ -445,22 +446,15 @@ var HORIZONTAL_MARGIN = 2;
{
if (!anIndexSet)
anIndexSet = [CPIndexSet indexSet];
if (!_isSelectable || [_selectionIndexes isEqual:anIndexSet])
return;
var index = CPNotFound,
itemCount = [_items count];
// Be wary of invalid selection ranges since setContent: does not clear selection indexes.
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) !== CPNotFound && index < itemCount)
[_items[index] setSelected:NO];
[self _applySelectionToItems:NO];
_selectionIndexes = anIndexSet;
var index = CPNotFound;
while ((index = [_selectionIndexes indexGreaterThanIndex:index]) !== CPNotFound)
[_items[index] setSelected:YES];
[self _applySelectionToItems:YES];
var binderClass = [[self class] _binderClassForBinding:@"selectionIndexes"];
[[binderClass getBinding:@"selectionIndexes" forObject:self] reverseSetValueFor:@"selectionIndexes"];
@@ -525,14 +519,14 @@ var HORIZONTAL_MARGIN = 2;
- (void)resizeWithOldSuperviewSize:(CGSize)oldBoundsSize
{
if (_lockResizing)
if (_inLiveResize)
return;
_lockResizing = YES;
_inLiveResize = YES;
[self tile];
_lockResizing = NO;
_inLiveResize = NO;
}
- (void)tile
@@ -972,6 +966,20 @@ var HORIZONTAL_MARGIN = 2;
return frame;
}
- (void)_applySelectionToItems:(BOOL)select
{
var numberOfItems = [_items count];
[_selectionIndexes enumerateIndexesUsingBlock:function(idx, stop)
{
if (idx < numberOfItems)
[[_items objectAtIndex:idx] setSelected:select];
else {
stop(YES);
}
}];
}
@end
@implementation CPCollectionView (DragAndDrop)
@@ -1586,3 +1594,14 @@ var CPCollectionViewMinItemSizeKey = @"CPCollectionViewMinItemSizeK
}
@end
@implementation _CPCollectionViewContentBinder : CPBinder
{
}
- (void)setValue:(id)aValue forBinding:(CPString)aBinding
{
[_source setContent:aValue];
}
@end
+241 -5
View File
@@ -100,8 +100,11 @@ var cachedBlackColor,
+ (CPDictionary)themeAttributes
{
return @{
@"alternate-selected-control-color": [CPNull null],
@"secondary-selected-control-color" : [CPNull null]
@"alternate-selected-control-color": [CPNull null],
@"secondary-selected-control-color": [CPNull null],
@"selected-text-background-color": [CPNull null],
@"selected-text-inactive-background-color": [CPNull null],
@"css-based": NO
};
}
@@ -498,6 +501,16 @@ var cachedBlackColor,
return [[CPColor alloc] _initWithCSSString: aString];
}
+ (CPColor)selectedTextBackgroundColor
{
return [[self _cachedThemeColor] valueForThemeAttribute:@"selected-text-background-color"] || [CPColor colorWithHexString:"99CCFF"];
}
+ (CPColor)_selectedTextBackgroundColorUnfocussed
{
return [[self _cachedThemeColor] valueForThemeAttribute:@"selected-text-inactive-background-color"] || [CPColor colorWithHexString:"CCCCCC"];
}
/* @ignore */
- (id)_initWithCSSString:(CPString)aString
{
@@ -864,9 +877,221 @@ url("data:image/png;base64,BASE64ENCODEDDATA") // if there is a pattern image
@end
#pragma mark -
#pragma mark CSS Theming
// The code below adds support for CSS theming with 100% compatibility with current theming system.
// The idea is to extend CPColor (and CPImage) with CSS components and adapt low level UI components to
// support this new kind of CPColor/CPImage. See CPImageView, CPView and _CPImageAndTextView.
//
// To create a CPColor that uses CSS, simply use the new class method :
// + (CPColor)colorWithCSSDictionary:(CPDictionary)aDictionary beforeDictionary:(CPDictionary)beforeDictionary afterDictionary:(CPDictionary)afterDictionary
// where beforeDictionary & afterDictionary are related to ::before & ::after pseudo-elements.
// If you don't need them, just use the simplified class method :
// + (CPColor)colorWithCSSDictionary:(CPDictionary)aDictionary
//
// Example :
// buttonCssColor = [CPColor colorWithCSSDictionary:@{
// @"background-color": A3ColorBackgroundWhite,
// @"border-color": A3ColorActiveBorder,
// @"border-style": @"solid",
// @"border-width": @"1px",
// @"border-radius": @"3px",
// @"box-sizing": @"border-box"
// }
// beforeDictionary:@{
// @"background-color": @"rgb(225,225,225)",
// @"bottom": @"3px",
// @"content": @"''",
// @"position": @"absolute",
// @"right": @"21px",
// @"top": @"3px",
// @"width": @"1px"
// }
// afterDictionary:@{
// @"content": @"''",
// @"bottom": @"3px",
// @"right": @"6px",
// @"top": @"1px",
// @"position": @"absolute",
// @"height": @"14px",
// @"width": @"9px",
// @"margin": @"2px 0px 2px 0px",
// @"background-image": @"url(%%packed.png)",
// @"background-position": @"0px -64px",
// @"background-repeat": @"no-repeat",
// @"background-size": @"100px 400px"
// }];
//
// Remark : Please note the special URL of the background image used in this example : url(%%packed.png)
// During theme loading, "%%" will be replaced by the path to the theme blend resources folder.
// Typically, a CSS theme will use some (rare) images all packed together in a single image resource (see packed.png in Aristo3 theme)
//
// Also, please note that if you don't use one of the CSS components, you can either set it to nil (best solution) or to an empty dictionary, like :
// aCssColor = [CPColor colorWithCSSDictionary:@{} beforeDictionary:nil afterDictionary:@{ ... }];
//
// You can use -(BOOL)isCSSBased to determine how to cope with it in your code.
// -(BOOL)hasCSSDictionary, -(BOOL)hasCSSBeforeDictionary and -(BOOL)hasCSSAfterDictionary are convience methods you can use.
//
// Remark : -(void)restorePreviousCSSState and -(DOMElement)applyCSSColorForView are meant to be used by low level UI widgets (like CPView) to implement
// CSS theme support.
@implementation CPColor (CSSTheming)
{
CPDictionary _cssDictionary @accessors(property=cssDictionary);
CPDictionary _cssBeforeDictionary @accessors(property=cssBeforeDictionary);
CPDictionary _cssAfterDictionary @accessors(property=cssAfterDictionary);
}
+ (CPColor)colorWithCSSDictionary:(CPDictionary)aDictionary
{
return [[CPColor alloc] _initWithCSSDictionary:aDictionary beforeDictionary:nil afterDictionary:nil];
}
+ (CPColor)colorWithCSSDictionary:(CPDictionary)aDictionary beforeDictionary:(CPDictionary)beforeDictionary afterDictionary:(CPDictionary)afterDictionary
{
return [[CPColor alloc] _initWithCSSDictionary:aDictionary beforeDictionary:beforeDictionary afterDictionary:afterDictionary];
}
- (id)_initWithCSSDictionary:(CPDictionary)aDictionary beforeDictionary:(CPDictionary)beforeDictionary afterDictionary:(CPDictionary)afterDictionary
{
self = [super init];
if (self)
{
_cssDictionary = aDictionary;
_cssBeforeDictionary = beforeDictionary;
_cssAfterDictionary = afterDictionary;
_components = [0.0, 0.0, 0.0, 1.0];
_theme = [CPTheme defaultTheme];
_themeState = CPThemeStateNormal;
[self _loadThemeAttributes];
}
return self;
}
- (BOOL)isCSSBased
{
return !!(_cssDictionary || _cssBeforeDictionary || _cssAfterDictionary);
}
- (BOOL)hasCSSDictionary
{
return ([_cssDictionary count] > 0);
}
- (BOOL)hasCSSBeforeDictionary
{
return ([_cssBeforeDictionary count] > 0);
}
- (BOOL)hasCSSAfterDictionary
{
return ([_cssAfterDictionary count] > 0);
}
- (void)restorePreviousCSSState:(CPArrayRef)aPreviousStateRef forDOMElement:(DOMElement)aDOMElement
{
#if PLATFORM(DOM)
var aPreviousState = @deref(aPreviousStateRef);
for (var i = 0, count = aPreviousState.length; i < count; i++)
aDOMElement.style[aPreviousState[i][0]] = aPreviousState[i][1];
@deref(aPreviousStateRef) = @[];
#endif
}
- (DOMElement)applyCSSColorForView:(CPView)aView onDOMElement:(DOMElement)aDOMElement styleNode:(DOMElement)aStyleNode previousState:(CPArrayRef)aPreviousStateRef
{
#if PLATFORM(DOM)
var aPreviousState = @deref(aPreviousStateRef);
[_cssDictionary enumerateKeysAndObjectsUsingBlock:function(aKey, anObject, stop)
{
[aPreviousState addObject:@[aKey, aDOMElement.style[aKey]]];
aDOMElement.style[aKey] = anObject;
}];
if ([self hasCSSBeforeDictionary] || [self hasCSSAfterDictionary])
{
// We need to create a unique class name
var styleClassName = @".CP" + [aView UID],
styleContent = @"";
if ([self hasCSSBeforeDictionary])
{
styleContent += styleClassName + @"::before { ";
[_cssBeforeDictionary enumerateKeysAndObjectsUsingBlock:function(aKey, anObject, stop)
{
styleContent += aKey + ": " + anObject + "; ";
}];
styleContent += "} ";
}
if ([self hasCSSAfterDictionary])
{
styleContent += styleClassName + @"::after { ";
[_cssAfterDictionary enumerateKeysAndObjectsUsingBlock:function(aKey, anObject, stop)
{
styleContent += aKey + ": " + anObject + "; ";
}];
styleContent += "} ";
}
var styleDescription = document.createTextNode(styleContent);
if (!aStyleNode)
{
aStyleNode = document.createElement("style");
aView._DOMElement.insertBefore(aStyleNode, aView._DOMElement.firstChild);
aStyleNode.appendChild(styleDescription);
}
else
{
aStyleNode.replaceChild(styleDescription, aStyleNode.firstChild);
}
[aView setDOMClassName:@"CP"+[aView UID]];
}
else
{
// no before/after so remove aStyleNode if existing
if (aStyleNode)
{
aView._DOMElement.removeChild(aStyleNode);
aStyleNode = nil;
}
}
// Return actualised values
@deref(aPreviousStateRef) = aPreviousState;
return aStyleNode;
#endif
}
@end
#pragma mark -
/// @cond IGNORE
var CPColorComponentsKey = @"CPColorComponentsKey",
CPColorPatternImageKey = @"CPColorPatternImageKey";
var CPColorComponentsKey = @"CPColorComponentsKey",
CPColorPatternImageKey = @"CPColorPatternImageKey",
CPColorCssDictionaryKey = @"CPColorCssDictionaryKey",
CPColorCssBeforeDictionaryKey = @"CPColorCssBeforeDictionaryKey",
CPColorCssAfterDictionaryKey = @"CPColorCssAfterDictionaryKey";
/// @endcond
@implementation CPColor (CPCoding)
@@ -879,6 +1104,10 @@ var CPColorComponentsKey = @"CPColorComponentsKey",
{
if ([aCoder containsValueForKey:CPColorPatternImageKey])
self = [self _initWithPatternImage:[aCoder decodeObjectForKey:CPColorPatternImageKey]];
else if ([aCoder containsValueForKey:CPColorCssDictionaryKey])
self = [self _initWithCSSDictionary:[aCoder decodeObjectForKey:CPColorCssDictionaryKey]
beforeDictionary:[aCoder decodeObjectForKey:CPColorCssBeforeDictionaryKey]
afterDictionary:[aCoder decodeObjectForKey:CPColorCssAfterDictionaryKey]];
else
self = [self _initWithRGBA:[aCoder decodeObjectForKey:CPColorComponentsKey]];
@@ -895,6 +1124,12 @@ var CPColorComponentsKey = @"CPColorComponentsKey",
{
if (_patternImage)
[aCoder encodeObject:_patternImage forKey:CPColorPatternImageKey];
else if (_cssDictionary)
{
[aCoder encodeObject:_cssDictionary forKey:CPColorCssDictionaryKey];
[aCoder encodeObject:_cssBeforeDictionary forKey:CPColorCssBeforeDictionaryKey];
[aCoder encodeObject:_cssAfterDictionary forKey:CPColorCssAfterDictionaryKey];
}
else
[aCoder encodeObject:_components forKey:CPColorComponentsKey];
@@ -1235,7 +1470,8 @@ var patternColorsFromPattern = function(pattern, attributes, imageFactory)
bottomHeight,
centerWidthHeight,
centerIsNil,
numParts;
numParts,
isVertical;
// positions are mandatory
if (pattern.indexOf("{position}") < 0)
+5 -6
View File
@@ -483,13 +483,12 @@ var CPColorPanelSwatchesCookie = "CPColorPanelSwatchesCookie";
];
}
var cookieValue = eval(cookieValue),
result = [];
var cookieValue = eval(cookieValue);
for (var i = 0; i < cookieValue.length; i++)
result.push([CPColor colorWithHexString:cookieValue[i]]);
return result;
return [cookieValue arrayByApplyingBlock:function(value)
{
return [CPColor colorWithHexString:value];
}];
}
- (CPArray)saveColorList
+3 -2
View File
@@ -125,7 +125,8 @@
_brightnessSlider = [[CPSlider alloc] initWithFrame:CGRectMake(0, (aFrame.size.height - 34), aFrame.size.width, 15)];
[_brightnessSlider setValue:15.0 forThemeAttribute:@"track-width"];
[_brightnessSlider setValue:[CPColor colorWithPatternImage:[[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPColorPicker class]] pathForResource:@"brightness_bar.png"]]] forThemeAttribute:@"track-color"];
var brightnessImage = [[CPImage alloc] initWithContentsOfFile:[[CPBundle bundleForClass:[CPColorPicker class]] pathForResource:@"brightness_bar.png"] size:CGSizeMake(272, 20)];
[_brightnessSlider setValue:[CPColor colorWithPatternImage:brightnessImage] forThemeAttribute:@"track-color"];
[_brightnessSlider setMinValue:0.0];
[_brightnessSlider setMaxValue:100.0];
@@ -246,7 +247,7 @@
_blackWheelImage = new Image();
_blackWheelImage.src = path;
_blackWheelImage.style.opacity = "0";
_blackWheelImage.style.filter = "alpha(opacity=0)"
_blackWheelImage.style.filter = "alpha(opacity=0)";
_blackWheelImage.style.position = "absolute";
_DOMElement.appendChild(_wheelImage);
+2
View File
@@ -255,6 +255,8 @@ var _CPColorWellDidBecomeExclusiveNotification = @"_CPColorWellDidBecomeExclusiv
var colorPanel = [CPColorPanel sharedColorPanel];
[colorPanel setPlatformWindow:[[self window] platformWindow]];
[colorPanel setColor:_color];
[colorPanel orderFront:self];
}
+2 -4
View File
@@ -1142,11 +1142,9 @@ var CPComboBoxTextSubview = @"text",
// Directly nuke _items, [_items removeAll] will trigger an extra call to setContent
_items = [];
var values = [];
[anArray enumerateObjectsUsingBlock:function(object)
var values = [anArray arrayByApplyingBlock:function(object)
{
values.push([object description]);
return [object description];
}];
[self addItemsWithObjectValues:values];
+49 -16
View File
@@ -26,11 +26,12 @@
// Browser Engines
CPUnknownBrowserEngine = 0;
CPGeckoBrowserEngine = 1;
CPInternetExplorerBrowserEngine = 2;
CPKHTMLBrowserEngine = 3;
CPOperaBrowserEngine = 4;
CPWebKitBrowserEngine = 5;
CPGeckoBrowserEngine = 1 << 0;
CPInternetExplorerBrowserEngine = 1 << 1;
CPKHTMLBrowserEngine = 1 << 2;
CPOperaBrowserEngine = 1 << 3;
CPWebKitBrowserEngine = 1 << 4; // Safari + Chrome
CPBlinkBrowserEngine = 1 << 5; // Recent Chrome
// Operating Systems
CPMacOperatingSystem = 0;
@@ -80,18 +81,27 @@ CPFileAPIFeature = 31;
CPAltEnterTextAreaFeature = 32;
CPCSSAnimationFeature = 33;
/*
When an absolutely positioned div (CPView) with an absolutely positioned canvas in it (CPView with drawRect:) moves things on top of the canvas (subviews) don't redraw correctly. E.g. if you have a bunch of text fields in a CPBox in a sheet which animates in, some of the text fields might not be visible because the CPBox has a canvas at the bottom and the box moved form offscreen to onscreen. This bug is probably very related: https://bugs.webkit.org/show_bug.cgi?id=67203
*/
*/
CPCanvasParentDrawErrorsOnMovementBug = 1 << 0;
// The paste event is only sent if an input or textarea has focus.
CPJavaScriptPasteRequiresEditableTarget = 1 << 1;
CPJavaScriptPasteRequiresEditableTarget = 1 << 1;
// Redirecting the focus of the browser on keydown to an input for Cmd-V or Ctrl-V makes the paste fail.
CPJavaScriptPasteCantRefocus = 1 << 2;
/*
Safari calculates incorrect text size unless you set the canvas font even if it is already set
You can see the bug after disabling the workaround and opening any panel while typing.
You can use the font panel in the manual test for CPTextView.
Look out for a displaced cursor, i.e. after typing letters of small width, such as the 'i'.
https://bugs.webkit.org/show_bug.cgi?id=150224
*/
CPTextSizingAlwaysNeedsSetFontBug = 1 << 3;
var USER_AGENT = "",
PLATFORM_ENGINE = CPUnknownBrowserEngine,
@@ -110,15 +120,15 @@ if (typeof window !== "undefined" && typeof window.navigator !== "undefined")
// Opera
if (typeof window !== "undefined" && window.opera)
{
PLATFORM_ENGINE = CPOperaBrowserEngine;
PLATFORM_ENGINE |= CPOperaBrowserEngine;
PLATFORM_FEATURES[CPJavaScriptCanvasDrawFeature] = YES;
}
// Internet Explorer
else if (typeof window !== "undefined" && window.attachEvent) // Must follow Opera check.
else if (typeof window !== "undefined" && (window.attachEvent || (!(window.ActiveXObject) && "ActiveXObject" in window))) // Must follow Opera check.
{
PLATFORM_ENGINE = CPInternetExplorerBrowserEngine;
PLATFORM_ENGINE |= CPInternetExplorerBrowserEngine;
// Features we can only be sure of with IE (no known independent tests)
PLATFORM_FEATURES[CPVMLFeature] = YES;
@@ -136,10 +146,10 @@ else if (typeof window !== "undefined" && window.attachEvent) // Must follow Ope
PLATFORM_FEATURES[CPJavaScriptClipboardAccessFeature] = YES;
}
// WebKit
// Safari + Chrome (WebKit and Blink)
else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
{
PLATFORM_ENGINE = CPWebKitBrowserEngine;
PLATFORM_ENGINE |= CPWebKitBrowserEngine;
// Features we can only be sure of with WebKit (no known independent tests)
PLATFORM_FEATURES[CPCSSRGBAFeature] = YES;
@@ -179,7 +189,10 @@ else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
PLATFORM_BUGS |= CPJavaScriptPasteRequiresEditableTarget;
// https://bugs.webkit.org/show_bug.cgi?id=39689
PLATFORM_BUGS |= CPJavaScriptPasteCantRefocus;
PLATFORM_BUGS |= CPTextSizingAlwaysNeedsSetFontBug;
}
else if ((window.chrome || (window.Intl && Intl.v8BreakIterator)) && 'CSS' in window)
PLATFORM_ENGINE |= CPBlinkBrowserEngine;
// Assume this bug was introduced around Safari 5.1/Chrome 16. This could probably be tighter.
if (majorVersion > 533)
@@ -189,13 +202,13 @@ else if (USER_AGENT.indexOf("AppleWebKit/") != -1)
// KHTML
else if (USER_AGENT.indexOf("KHTML") != -1) // Must follow WebKit check.
{
PLATFORM_ENGINE = CPKHTMLBrowserEngine;
PLATFORM_ENGINE |= CPKHTMLBrowserEngine;
}
// Gecko
else if (USER_AGENT.indexOf("Gecko") !== -1) // Must follow KHTML check.
{
PLATFORM_ENGINE = CPGeckoBrowserEngine;
PLATFORM_ENGINE |= CPGeckoBrowserEngine;
PLATFORM_FEATURES[CPJavaScriptCanvasDrawFeature] = YES;
@@ -286,7 +299,7 @@ function CPPlatformHasBug(aBug)
function CPBrowserIsEngine(anEngine)
{
return PLATFORM_ENGINE === anEngine;
return PLATFORM_ENGINE & anEngine;
}
function CPBrowserIsOperatingSystem(anOperatingSystem)
@@ -322,6 +335,14 @@ else
CPRedoKeyEquivalentModifierMask = CPControlKeyMask;
}
/*!
Sets a feature with the given value.
*/
function CPSetPlatformFeature(aFeature, aBool)
{
PLATFORM_FEATURES[aFeature] = aBool;
}
/*!
Return the properly prefixed JS property for the given name. E.g. in a webkit browser,
CPBrowserStyleProperty('transition') -> WebkitTransition
@@ -369,6 +390,18 @@ function CPBrowserStyleProperty(aProperty)
r = candidates[PLATFORM_STYLE_JS_PROPERTIES['transform']] || nil;
break;
case 'animationend':
var candidates = {
'WebkitAnimation' : 'webkitAnimationEnd',
'MozAnimation' : 'animationend',
'OAnimation' : 'oAnimationEnd',
'msAnimation' : 'MSAnimationEnd',
'animation' : 'animationend'
};
r = candidates[PLATFORM_STYLE_JS_PROPERTIES['animation']] || nil;
break;
default:
var prefixes = ["Webkit", "Moz", "O", "ms"],
strippedProperty = aProperty.split('-').join(' '),
+14 -7
View File
@@ -25,7 +25,7 @@
@import "CPFont.j"
@import "CPShadow.j"
@import "CPView.j"
@import "CPText.j"
@import "CPKeyValueBinding.j"
@import "CPTrackingArea.j"
@@ -169,7 +169,7 @@ var CPControlBlackColor = [CPColor blackColor];
}
/*!
Reverse set the binding iff the CPContinuouslyUpdatesValueBindingOption is set.
Reverse set the binding if the CPContinuouslyUpdatesValueBindingOption is set.
*/
- (void)_continuouslyReverseSetBinding
{
@@ -1057,14 +1057,21 @@ var CPControlBlackColor = [CPColor blackColor];
@end
@implementation CPControl (CPTrackingArea)
{
CPTrackingArea _controlTrackingArea;
}
- (void)updateTrackingAreas
{
[self removeAllTrackingAreas];
[self addTrackingArea:[[CPTrackingArea alloc] initWithRect:CGRectMakeZero()
options:CPTrackingMouseEnteredAndExited | CPTrackingActiveInKeyWindow | CPTrackingInVisibleRect
owner:self
userInfo:nil]];
if (_controlTrackingArea)
[self removeTrackingArea:_controlTrackingArea];
_controlTrackingArea = [[CPTrackingArea alloc] initWithRect:CGRectMakeZero()
options:CPTrackingMouseEnteredAndExited | CPTrackingActiveInKeyWindow | CPTrackingInVisibleRect
owner:self
userInfo:nil];
[self addTrackingArea:_controlTrackingArea];
[super updateTrackingAreas];
}
@end
+3 -3
View File
@@ -352,8 +352,8 @@ CPEraDatePickerElementFlag = 0x0100;
if (_implementedCDatePickerDelegateMethods & CPDatePicker_validateProposedDateValue_timeInterval)
{
// constrain timeInterval also
var aStartDateRef = function(x){if (typeof x == 'undefined') return aDateValue; aDateValue = x;}
var aTimeIntervalRef = function(x){if (typeof x == 'undefined') return aTimeInterval; aTimeInterval = x;}
var aStartDateRef = function(x){if (typeof x == 'undefined') return aDateValue; aDateValue = x;};
var aTimeIntervalRef = function(x){if (typeof x == 'undefined') return aTimeInterval; aTimeInterval = x;};
[_delegate datePicker:self validateProposedDateValue:aStartDateRef timeInterval:aTimeIntervalRef];
}
@@ -694,7 +694,7 @@ var CPDatePickerModeKey = @"CPDatePickerModeKey",
[aCoder encodeInt:_datePickerStyle forKey:CPDatePickerStyleKey];
[aCoder encodeInt:_datePickerElements forKey:CPDatePickerElementsKey];
[aCoder encodeObject:_minDate forKey:CPMinDateKey];
[aCoder encodeObject:_maxDate forKey:CPMaxDateKey]
[aCoder encodeObject:_maxDate forKey:CPMaxDateKey];
[aCoder encodeObject:_dateValue forKey:CPDateValueKey];;
[aCoder encodeObject:_textFont forKey:CPTextFontKey];
[aCoder encodeObject:_locale forKey:CPLocaleKey];
+10 -10
View File
@@ -85,7 +85,7 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
{
if (self = [super initWithFrame:aFrame])
{
_datePicker = aDatePicker
_datePicker = aDatePicker;
[self _init];
}
@@ -435,7 +435,7 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
break;
default:
return CPShortWeekDayNameArrayEn
return CPShortWeekDayNameArrayEn;
break;
}
}
@@ -464,7 +464,7 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
break;
default:
return CPShortMonthNameArrayEn
return CPShortMonthNameArrayEn;
break;
}
@@ -526,11 +526,11 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
var dayLabel = _dayLabels[i];
[dayLabel setStringValue:dayNames[i]];
[dayLabel sizeToFit]
[dayLabel sizeToFit];
[dayLabel setFrameOrigin:CGPointMake(sizeTileWidth * (i + 1) - sizeTileWidth / 2 - [dayLabel frameSize].width / 2, 23)];
if (i == 0)
firstDayTileX = sizeTileWidth * (i + 1) - sizeTileWidth / 2 - [dayLabel frameSize].width / 2
firstDayTileX = sizeTileWidth * (i + 1) - sizeTileWidth / 2 - [dayLabel frameSize].width / 2;
}
// Title
@@ -769,7 +769,7 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
tileDate = [[tile date] copy],
selected = NO;
[tileDate _resetToMidnight]
[tileDate _resetToMidnight];
if (aStartDate)
selected = tileDate >= aStartDate && tileDate <= endDate;
@@ -845,7 +845,7 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
// Very usefull to avoid to have a line of two pixels instead one
if (!isBorderPair)
y += 0.5
y += 0.5;
CGContextMoveToPoint(context, 0, y);
CGContextAddLineToPoint(context, [self bounds].size.width, y);
@@ -857,7 +857,7 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
// Very usefull to avoid to have a line of two pixels instead one
if (!isBorderPair)
x += 0.5
x += 0.5;
CGContextMoveToPoint(context, x, 0);
CGContextAddLineToPoint(context, x, [self bounds].size.height);
@@ -869,7 +869,7 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
// Very usefull to avoid to have a line of two pixels instead one
if (!isBorderPair)
y += 0.5
y += 0.5;
CGContextMoveToPoint(context, 0, y);
CGContextAddLineToPoint(context, [self bounds].size.width, y);
@@ -897,7 +897,7 @@ var CPShortWeekDayNameArrayEn = [@"Mo", @"Tu", @"We", @"Th", @"Fr", @"Sa", @"Su"
_clickDate = [dateTile copy];
_dragDate = nil;
_indexDayTile = -1;
_eventDragged = nil
_eventDragged = nil;
_datePicker._invokedByUserEvent = YES;
+1 -1
View File
@@ -142,7 +142,7 @@ var RADIANS = Math.PI / 180;
if ([_datePicker _isAmericanFormat])
{
if (dateValue.getHours() > 11)
[_PMAMTextField setStringValue:@"PM"]
[_PMAMTextField setStringValue:@"PM"];
else
[_PMAMTextField setStringValue:@"AM"];
+1 -1
View File
@@ -80,7 +80,7 @@ var CPZeroKeyCode = 48,
{
if (self = [super initWithFrame:aFrame])
{
_datePicker = aDatePicker
_datePicker = aDatePicker;
[self _init];
}
return self;
+18 -8
View File
@@ -28,7 +28,6 @@
@import "CPCompatibility.j"
@import "CGGeometry.j"
@import "CPText.j"
@import "CPTrackingArea.j"
@class CPTextField
@@ -36,6 +35,9 @@
@class CPGraphicsContext
@global CPApp
@global CPNewlineCharacter
@global CPCarriageReturnCharacter
@global CPEnterCharacter
@typedef DOMEvent
@typedef CPEventType
@@ -64,7 +66,7 @@ var _CPEventPeriodicEventPeriod = 0,
CPWindow _window;
Number _windowNumber;
CPString _characters;
CPString _charactersIgnoringModifiers
CPString _charactersIgnoringModifiers;
BOOL _isARepeat;
unsigned _keyCode;
DOMEvent _DOMEvent;
@@ -83,7 +85,7 @@ var _CPEventPeriodicEventPeriod = 0,
BOOL _suppressCappuccinoCut;
BOOL _suppressCappuccinoPaste;
#endif
CPTrackingArea _trackingArea;
}
@@ -146,7 +148,7 @@ var _CPEventPeriodicEventPeriod = 0,
/*!
Creates a new mouse tracking event.
@param anEventType the event type
@param aPoint the location of the cursor in the window specified by \c aWindowNumber
@param modifierFlags a bitwise combination of the modifiers specified in the CPEvent globals
@@ -232,7 +234,7 @@ var _CPEventPeriodicEventPeriod = 0,
{
if ((anEventType != CPMouseEntered) && (anEventType != CPMouseExited) && (anEventType != CPCursorUpdate))
[CPException raise:CPInternalInconsistencyException reason:"Invalid event type"];
if (self = [self _initWithType:anEventType])
{
_location = CGPointCreateCopy(aPoint);
@@ -243,7 +245,7 @@ var _CPEventPeriodicEventPeriod = 0,
_trackingArea = aTrackingArea;
_window = [CPApp windowWithWindowNumber:aWindowNumber];
}
return self;
}
@@ -336,6 +338,14 @@ var _CPEventPeriodicEventPeriod = 0,
return _type;
}
/*!
Returns the subtype of the event.
*/
- (CPEventType)subtype
{
return _subtype;
}
/*!
Returns the event's associated window.
*/
@@ -632,8 +642,8 @@ var _CPEventPeriodicEventPeriod = 0,
- (CPTrackingArea)trackingArea
{
if ((_type !== CPMouseEntered) && (_type !== CPMouseExited) && (_type !== CPCursorUpdate))
[CPException raise:CPInternalInconsistencyException format:@"You can't call trackingArea for events of type %#x", _type]
[CPException raise:CPInternalInconsistencyException format:@"You can't call trackingArea for events of type %#x", _type];
return _trackingArea;
}
+39 -1
View File
@@ -24,6 +24,7 @@
@import <Foundation/CPBundle.j>
@import "CPView.j"
@import "CPFontDescriptor.j"
CPFontDefaultSystemFontFace = @"Arial, sans-serif";
CPFontDefaultSystemFontSize = 12;
@@ -162,7 +163,7 @@ following:
if (normalizedFaces === _CPFontSystemFontFace)
return;
[self _invalidateSystemFontCache]
[self _invalidateSystemFontCache];
_CPFontSystemFontFace = aFace;
}
@@ -433,6 +434,43 @@ following:
@end
@implementation CPFont(DescriptorAdditions)
- (id)_initWithFontDescriptor:(CPFontDescriptor)fontDescriptor
{
var aName = [fontDescriptor objectForKey: CPFontNameAttribute] ,
aSize = [fontDescriptor pointSize],
isBold = [fontDescriptor symbolicTraits] & CPFontBoldTrait,
isItalic = [fontDescriptor symbolicTraits] & CPFontItalicTrait;
return [self _initWithName:aName size:aSize bold:isBold italic:isItalic system:NO];
}
+ (CPFont)fontWithDescriptor:(CPFontDescriptor)fontDescriptor size:(float)aSize
{
var aName = [fontDescriptor objectForKey: CPFontNameAttribute],
isBold = [fontDescriptor symbolicTraits] & CPFontBoldTrait,
isItalic = [fontDescriptor symbolicTraits] & CPFontItalicTrait;
return [self _fontWithName:aName size:aSize || [fontDescriptor pointSize] bold:isBold italic:isItalic];
}
- (CPFontDescriptor)fontDescriptor
{
var traits = 0;
if ([self isBold])
traits |= CPFontBoldTrait;
if ([self isItalic])
traits |= CPFontItalicTrait;
return [[CPFontDescriptor fontDescriptorWithName:_name size:_size] fontDescriptorWithSymbolicTraits:traits];
}
@end
var CPFontNameKey = @"CPFontNameKey",
CPFontSizeKey = @"CPFontSizeKey",
CPFontIsBoldKey = @"CPFontIsBoldKey",
+208 -1
View File
@@ -22,9 +22,12 @@
@import <Foundation/CPObject.j>
@import "CPControl.j"
@import "CPFont.j"
@import "CPFontDescriptor.j"
@global CPApp
@class CPFontPanel
CPItalicFontMask = 1 << 0;
CPBoldFontMask = 1 << 1;
@@ -41,7 +44,20 @@ CPUnitalicFontMask = 1 << 24;
var CPSharedFontManager = nil,
CPFontManagerFactory = Nil;
CPFontManagerFactory = nil,
CPFontPanelFactory = nil;
/*
modifyFont: sender's tag
*/
CPNoFontChangeAction = 0;
CPViaPanelFontAction = 1;
CPAddTraitFontAction = 2;
CPSizeUpFontAction = 3;
CPSizeDownFontAction = 4;
CPHeavierFontAction = 5;
CPLighterFontAction = 6;
CPRemoveTraitFontAction = 7;
/*!
@ingroup appkit
@@ -59,6 +75,8 @@ var CPSharedFontManager = nil,
BOOL _multiple @accessors(getter=isMultiple, setter=setMultiple:);
CPDictionary _activeChange;
unsigned _fontAction;
}
// Getting the Shared Font Manager
@@ -83,6 +101,15 @@ var CPSharedFontManager = nil,
{
CPFontManagerFactory = aClass;
}
/*!
Sets the class that will be used to create the application's
Font panel.
*/
+ (void)setFontPanelFactory:(Class)aClass
{
CPFontPanelFactory = aClass;
}
- (id)init
{
@@ -210,6 +237,7 @@ var CPSharedFontManager = nil,
{
var tag = [sender tag];
_activeChange = tag === nil ? @{} : @{ @"addTraits": tag };
_fontAction = CPAddTraitFontAction;
[self sendAction];
}
@@ -219,6 +247,185 @@ var CPSharedFontManager = nil,
return [CPApp sendAction:_action to:_target from:self];
}
/*!
This method open the font panel, create it if necessary.
@param sender The object that sent the message.
*/
- (CPFontPanel)fontPanel:(BOOL)createIt
{
var panel = nil,
panelExists = [CPFontPanelFactory sharedFontPanelExists];
if ((panelExists) || (!panelExists && createIt))
panel = [CPFontPanelFactory sharedFontPanel];
return panel;
}
/*!
Convert a font to have the specified Font traits. The font is unchanged expect for the specified Font traits.
Using CPUnboldFontMask or CPUnitalicFontMask will respectively remove Bold and Italic traits.
@param aFont The font to convert.
@param fontTrait The new font traits mask.
@result The converted font or \c aFont if the conversion failed.
*/
- (CPFont)convertFont:(CPFont)aFont toHaveTrait:(CPFontTraitMask)fontTrait
{
var attributes = [[[aFont fontDescriptor] fontAttributes] copy],
symbolicTrait = [[aFont fontDescriptor] symbolicTraits];
if (fontTrait & CPBoldFontMask)
symbolicTrait |= CPFontBoldTrait;
if (fontTrait & CPItalicFontMask)
symbolicTrait |= CPFontItalicTrait;
if (fontTrait & CPUnboldFontMask) /* FIXME: this only change CPFontSymbolicTrait what about CPFontWeightTrait */
symbolicTrait &= ~CPFontBoldTrait;
if (fontTrait & CPUnitalicFontMask)
symbolicTrait &= ~CPFontItalicTrait;
if (fontTrait & CPExpandedFontMask)
symbolicTrait |= CPFontExpandedTrait;
if (fontTrait & CPSmallCapsFontMask)
symbolicTrait |= CPFontSmallCapsTrait;
if (![attributes containsKey:CPFontTraitsAttribute])
[attributes setObject:[CPDictionary dictionaryWithObject:[CPNumber numberWithUnsignedInt:symbolicTrait]
forKey:CPFontSymbolicTrait]
forKey:CPFontTraitsAttribute];
else
[[attributes objectForKey:CPFontTraitsAttribute] setObject:[CPNumber numberWithUnsignedInt:symbolicTrait]
forKey:CPFontSymbolicTrait];
return [[aFont class] fontWithDescriptor:[CPFontDescriptor fontDescriptorWithFontAttributes:attributes] size:0.0];
}
/*!
Convert a font to not have the specified Font traits. The font is unchanged expect for the specified Font traits.
@param aFont The font to convert.
@param fontTrait The font traits mask to remove.
@result The converted font or \c aFont if the conversion failed.
*/
- (CPFont)convertFont:(CPFont)aFont toNotHaveTrait:(CPFontTraitMask)fontTrait
{
var attributes = [[[aFont fontDescriptor] fontAttributes] copy],
symbolicTrait = [[aFont fontDescriptor] symbolicTraits];
if ((fontTrait & CPBoldFontMask) || (fontTrait & CPUnboldFontMask)) /* FIXME: see convertFont:toHaveTrait: about CPFontWeightTrait */
symbolicTrait &= ~CPFontBoldTrait;
if ((fontTrait & CPItalicFontMask) || (fontTrait & CPUnitalicFontMask))
symbolicTrait &= ~CPFontItalicTrait;
if (fontTrait & CPExpandedFontMask)
symbolicTrait &= ~CPFontExpandedTrait;
if (fontTrait & CPSmallCapsFontMask)
symbolicTrait &= ~CPFontSmallCapsTrait;
if (![attributes containsKey:CPFontTraitsAttribute])
[attributes setObject:[CPDictionary dictionaryWithObject:[CPNumber numberWithUnsignedInt:symbolicTrait]
forKey:CPFontSymbolicTrait]
forKey:CPFontTraitsAttribute];
else
[[attributes objectForKey:CPFontTraitsAttribute] setObject:[CPNumber numberWithUnsignedInt:symbolicTrait]
forKey:CPFontSymbolicTrait];
return [[aFont class] fontWithDescriptor:[CPFontDescriptor fontDescriptorWithFontAttributes:attributes] size:0.0];
}
/*!
Convert a font to have specified size. The font is unchanged expect for the specified size.
@param aFont The font to convert.
@param aSize The new font size.
@result The converted font or \c aFont if the conversion failed.
*/
- (CPFont)convertFont:(CPFont)aFont toSize:(float)aSize
{
var descriptor = [aFont fontDescriptor];
return [[aFont class] fontWithDescriptor: descriptor size:aSize]
}
- (void)orderFrontFontPanel:(id)sender
{
[[self fontPanel:YES] orderFront:sender];
}
- (void)modifyFont:(id)sender
{
_fontAction = [sender tag];
[self sendAction];
if (_selectedFont)
[self setSelectedFont:[self convertFont:_selectedFont] isMultiple:NO];
}
/*!
This method causes the receiver to send its action message.
@param sender The object that sent the message. (a Font panel)
*/
- (void)modifyFontViaPanel:(id)sender
{
_fontAction = CPViaPanelFontAction;
if (_selectedFont)
[self setSelectedFont:[self convertFont:_selectedFont] isMultiple:NO];
[self sendAction];
}
/*!
Convert a font according to current font changes, provided by the object that initiated the font change.
@param aFont The font to convert.
@result The converted font or \c aFont if the conversion failed.
*/
- (CPFont)convertFont:(CPFont)aFont
{
var newFont = nil;
switch (_fontAction)
{
case CPNoFontChangeAction:
newFont = aFont;
break;
case CPViaPanelFontAction:
newFont = [[self fontPanel:NO] panelConvertFont:aFont];
break;
case CPAddTraitFontAction:
newFont = aFont;
if (!_activeChange)
break;
var addTraits = [_activeChange valueForKey:@"addTraits"];
if (addTraits)
newFont = [self convertFont:aFont toHaveTrait:addTraits];
break;
case CPSizeUpFontAction:
newFont = [self convertFont:aFont toSize:[aFont size] + 1.0]; /* any limit ? */
break;
case CPSizeDownFontAction:
if ([aFont size] > 1)
newFont = [self convertFont:aFont toSize:[aFont size] - 1.0];
/* else CPBeep() :-p */
break;
default:
CPLog.trace(@"-[" + [self className] + " " + _cmd + "] unsupported font action: " + _fontAction + " aFont unchanged");
newFont = aFont;
break;
}
return newFont;
}
@end
var _CPFontDetectSpan,
+6 -5
View File
@@ -70,11 +70,12 @@ CPGradientDrawsAfterEndingLocation = kCGGradientDrawsAfterEndLocation;
{
if (self = [super init])
{
var cgColors = [],
count = [someColors count],
colorSpace = [aColorSpace CGColorSpace] || CGColorSpaceCreateDeviceRGB;
for (var i = 0; i < count; i++)
cgColors.push(CGColorCreate(colorSpace, [someColors[i] components]));
var colorSpace = [aColorSpace CGColorSpace] || CGColorSpaceCreateDeviceRGB,
cgColors = [someColors arrayByApplyingBlock:function(color)
{
return CGColorCreate(colorSpace, [color components])
}];
_gradient = CGGradientCreateWithColors(colorSpace, cgColors, someLocations);
}
+4 -4
View File
@@ -43,10 +43,10 @@ function CPDrawTiledRects(
if (sides.length != grays.length)
[CPException raise:CPInvalidArgumentException reason:@"sides (length: " + sides.length + ") and grays (length: " + grays.length + ") must have the same length."];
var colors = [];
for (var i = 0; i < grays.length; ++i)
colors.push([CPColor colorWithCalibratedWhite:grays[i] alpha:1.0]);
var colors = [grays arrayByApplyingBlock:function(gray)
{
return [CPColor colorWithCalibratedWhite:gray alpha:1.0];
}];
return CPDrawColorTiledRects(boundsRect, clipRect, sides, colors);
}
+219 -2
View File
@@ -246,7 +246,7 @@ function CPAppKitImage(aFilename, aSize)
var canvas = document.createElement("canvas"),
ctx = canvas.getContext("2d");
canvas.width = _image.width,
canvas.width = _image.width;
canvas.height = _image.height;
ctx.drawImage(_image, 0, 0);
@@ -509,6 +509,212 @@ function CPAppKitImage(aFilename, aSize)
@end
#pragma mark -
#pragma mark CSS Theming
// The code below adds support for CSS theming with 100% compatibility with current theming system.
// The idea is to extend CPImage (and CPColor) with CSS components and adapt low level UI components to
// support this new kind of CPColor/CPImage. See CPImageView, CPView and _CPImageAndTextView.
//
// To create a CPImage that uses CSS, simply use the new class method :
// + (CPImage)imageWithCSSDictionary:(CPDictionary)aDictionary beforeDictionary:(CPDictionary)beforeDictionary afterDictionary:(CPDictionary)afterDictionary size:(CGSize)aSize
// where beforeDictionary & afterDictionary are related to ::before & ::after pseudo-elements.
// If you don't need them, just use the simplified class method :
// + (CPImage)imageWithCSSDictionary:(CPDictionary)aDictionary size:(CGSize)aSize
//
// Examples :
// regularImageNormal = [CPImage imageWithCSSDictionary:@{
// @"border-color": A3ColorActiveBorder,
// @"border-style": @"solid",
// @"border-width": @"1px",
// @"border-radius": @"50%",
// @"box-sizing": @"border-box",
// @"background-color": A3ColorBackgroundWhite,
// @"transition-duration": @"0.35s",
// @"transition-property": @"all",
// @"transition-timing-function": @"ease"
// }
// size:CGSizeMake(16,16)];
//
// imageSearch = [CPImage imageWithCSSDictionary:@{
// @"background-image": @"url(%%packed.png)",
// @"background-position": @"-16px -32px",
// @"background-repeat": @"no-repeat",
// @"background-size": @"100px 400px"
// }
// size:CGSizeMake(16,16)];
//
// Remark : Please note the special URL of the background image used in this example : url(%%packed.png)
// During theme loading, "%%" will be replaced by the path to the theme blend resources folder.
// Typically, a CSS theme will use some (rare) images all packed together in a single image resource (see packed.png in Aristo3 theme)
//
// Also, please note that if you don't use one of the CSS components, you can either set it to nil (best solution) or to an empty dictionary, like :
// aCssImage = [CPImage imageWithCSSDictionary:@{} beforeDictionary:nil afterDictionary:@{ ... }];
//
// You can use -(BOOL)isCSSBased to determine how to cope with it in your code.
// -(BOOL)hasCSSDictionary, -(BOOL)hasCSSBeforeDictionary and -(BOOL)hasCSSAfterDictionary are convience methods you can use.
//
// Remark : -(DOMElement)applyCSSImageForView is meant to be used by low level UI widgets (like CPImageView and _CPImageAndTextView) to implement CSS theme support.
//
// In some circumstances, you may have to clear a CSS image. You can do this easily by replacing your current image with the special dummy empty CSS image :
// [CPImage dummyCSSImageOfSize:CGSizeMake(someWidth, someHeight)]
@implementation CPImage (CSSTheming)
{
CPDictionary _cssDictionary @accessors(property=cssDictionary);
CPDictionary _cssBeforeDictionary @accessors(property=cssBeforeDictionary);
CPDictionary _cssAfterDictionary @accessors(property=cssAfterDictionary);
}
+ (CPImage)imageWithCSSDictionary:(CPDictionary)aDictionary size:(CGSize)aSize
{
return [[CPImage alloc] initWithCSSDictionary:aDictionary beforeDictionary:nil afterDictionary:nil size:aSize];
}
+ (CPImage)imageWithCSSDictionary:(CPDictionary)aDictionary beforeDictionary:(CPDictionary)beforeDictionary afterDictionary:(CPDictionary)afterDictionary size:(CGSize)aSize
{
return [[CPImage alloc] initWithCSSDictionary:aDictionary beforeDictionary:beforeDictionary afterDictionary:afterDictionary size:aSize];
}
+ (CPImage)dummyCSSImageOfSize:(CGSize)aSize
{
// This is used to clear a previous CSS image
return [[CPImage alloc] initWithCSSDictionary:@{} beforeDictionary:nil afterDictionary:nil size:aSize];
}
- (id)initWithCSSDictionary:(CPDictionary)aDictionary beforeDictionary:(CPDictionary)beforeDictionary afterDictionary:(CPDictionary)afterDictionary size:(CGSize)aSize
{
self = [super init];
if (self)
{
_size = CGSizeMakeCopy(aSize);
_filename = @"CSS image";
_loadStatus = CPImageLoadStatusCompleted;
_cssDictionary = aDictionary;
_cssBeforeDictionary = beforeDictionary;
_cssAfterDictionary = afterDictionary;
}
return self;
}
- (BOOL)isCSSBased
{
return !!(_cssDictionary || _cssBeforeDictionary || _cssAfterDictionary);
}
- (BOOL)hasCSSDictionary
{
return ([_cssDictionary count] > 0);
}
- (BOOL)hasCSSBeforeDictionary
{
return ([_cssBeforeDictionary count] > 0);
}
- (BOOL)hasCSSAfterDictionary
{
return ([_cssAfterDictionary count] > 0);
}
- (DOMElement)applyCSSImageForView:(CPView)aView onDOMElement:(DOMElement)aDOMElement styleNode:(DOMElement)aStyleNode previousState:(CPArrayRef)aPreviousStateRef
{
#if PLATFORM(DOM)
// First, restore previous CSS styling before applying the new one
var aPreviousState = @deref(aPreviousStateRef);
for (var i = 0, count = aPreviousState.length; i < count; i++)
aDOMElement.style[aPreviousState[i][0]] = aPreviousState[i][1];
aPreviousState = @[];
// Then apply new CSS styling
[_cssDictionary enumerateKeysAndObjectsUsingBlock:function(aKey, anObject, stop)
{
[aPreviousState addObject:@[aKey, aDOMElement.style[aKey]]];
aDOMElement.style[aKey] = anObject;
}];
if (_cssBeforeDictionary || _cssAfterDictionary)
{
// We need to create a unique class name
var styleClassName = @".CP" + [aView UID],
styleContent = @"";
if (_cssBeforeDictionary)
{
styleContent += styleClassName + @"::before { ";
[_cssBeforeDictionary enumerateKeysAndObjectsUsingBlock:function(aKey, anObject, stop)
{
styleContent += aKey + ": " + anObject + "; ";
}];
styleContent += "} ";
}
if (_cssAfterDictionary)
{
styleContent += styleClassName + @"::after { ";
[_cssAfterDictionary enumerateKeysAndObjectsUsingBlock:function(aKey, anObject, stop)
{
styleContent += aKey + ": " + anObject + "; ";
}];
styleContent += "} ";
}
var styleDescription = document.createTextNode(styleContent);
if (!aStyleNode)
{
aStyleNode = document.createElement("style");
aView._DOMElement.insertBefore(aStyleNode, aView._DOMElement.firstChild);
aStyleNode.appendChild(styleDescription);
}
else
{
aStyleNode.replaceChild(styleDescription, aStyleNode.firstChild);
}
[aView setDOMClassName:@"CP"+[aView UID]];
}
else
{
// no before/after so remove aStyleNode if existing
if (aStyleNode)
{
aView._DOMElement.removeChild(aStyleNode);
aStyleNode = nil;
}
}
// Return actualised values
@deref(aPreviousStateRef) = aPreviousState;
return aStyleNode;
#endif
}
@end
var CPImageCSSDictionaryKey = @"CPImageCSSDictionaryKey",
CPImageCSSBeforeDictionaryKey = @"CPImageCSSBeforeDictionaryKey",
CPImageCSSAfterDictionaryKey = @"CPImageCSSAfterDictionaryKey";
#pragma mark -
@implementation CPImage (CPCoding)
/*!
@@ -518,7 +724,10 @@ function CPAppKitImage(aFilename, aSize)
*/
- (id)initWithCoder:(CPCoder)aCoder
{
return [self initWithContentsOfFile:[aCoder decodeObjectForKey:@"CPFilename"] size:[aCoder decodeSizeForKey:@"CPSize"]];
if ([aCoder containsValueForKey:CPImageCSSDictionaryKey])
return [self initWithCSSDictionary:[aCoder decodeObjectForKey:CPImageCSSDictionaryKey] beforeDictionary:[aCoder decodeObjectForKey:CPImageCSSBeforeDictionaryKey] afterDictionary:[aCoder decodeObjectForKey:CPImageCSSAfterDictionaryKey] size:[aCoder decodeSizeForKey:@"CPSize"]];
else
return [self initWithContentsOfFile:[aCoder decodeObjectForKey:@"CPFilename"] size:[aCoder decodeSizeForKey:@"CPSize"]];
}
/*!
@@ -529,6 +738,14 @@ function CPAppKitImage(aFilename, aSize)
{
[aCoder encodeObject:_filename forKey:@"CPFilename"];
[aCoder encodeSize:_size forKey:@"CPSize"];
// CSS Styling
if ([self isCSSBased])
{
[aCoder encodeObject:_cssDictionary forKey:CPImageCSSDictionaryKey];
[aCoder encodeObject:_cssBeforeDictionary forKey:CPImageCSSBeforeDictionaryKey];
[aCoder encodeObject:_cssAfterDictionary forKey:CPImageCSSAfterDictionaryKey];
}
}
@end
+33 -6
View File
@@ -98,10 +98,32 @@ var CPImageViewEmptyPlaceholderImage = nil;
- (void)_createDOMImageElement
{
#if PLATFORM(DOM)
if (_DOMImageElement)
return;
var image = [self objectValue],
isCSSBasedImage = [image isCSSBased],
isIMGImageElement = _DOMImageElement && (_DOMImageElement.nodeName == "IMG");
_DOMImageElement = document.createElement("img");
// First, check if we need to destroy a current DOM image element. This is the case if :
// - we have one but not the right one (that is a DIV but needing an IMG, and vice versa)
if (_DOMImageElement)
{
if ((isIMGImageElement && isCSSBasedImage) || (!isIMGImageElement && !isCSSBasedImage))
{
// OK, destroy it
_DOMElement.removeChild(_DOMImageElement);
_DOMImageElement = nil;
// CSS styling cleaning
_cssStylePreviousState = @[];
_cssStyleNode = nil;
}
else
return;
}
_DOMImageElement = document.createElement(isCSSBasedImage ? "div" : "img");
_DOMImageElement.style.position = "absolute";
_DOMImageElement.style.left = "0px";
_DOMImageElement.style.top = "0px";
@@ -150,10 +172,15 @@ var CPImageViewEmptyPlaceholderImage = nil;
var newImage = [self objectValue];
#if PLATFORM(DOM)
if (!_DOMImageElement)
[self _createDOMImageElement];
[self _createDOMImageElement];
_DOMImageElement.src = newImage ? [newImage filename] : [CPImageViewEmptyPlaceholderImage filename];
if ([newImage isCSSBased])
_cssStyleNode = [newImage applyCSSImageForView:self
onDOMElement:_DOMImageElement
styleNode:_cssStyleNode
previousState:@ref(_cssStylePreviousState)];
else
_DOMImageElement.src = newImage ? [newImage filename] : [CPImageViewEmptyPlaceholderImage filename];
#endif
var size = [newImage size];
+2 -1
View File
@@ -857,7 +857,7 @@ var CPBindingOperationAnd = 0,
- (id)initWithName:(CPString)aName
{
if (self = [super init])
_name = aName
_name = aName;
return self;
}
@@ -918,6 +918,7 @@ CPTextColorBinding = @"textColor";
CPTitleBinding = @"title";
CPToolTipBinding = @"toolTip";
CPValueBinding = @"value";
CPAttributedStringBinding = @"attributedString";
CPValueURLBinding = @"valueURL";
CPValuePathBinding = @"valuePath";
CPDataBinding = @"data";
+2 -2
View File
@@ -292,7 +292,7 @@ CPRatingLevelIndicatorStyle = 3;
[self setNeedsLayout];
}
- (void)setWarningValue:(double)warningValue;
- (void)setWarningValue:(double)warningValue
{
if (_warningValue === warningValue)
return;
@@ -301,7 +301,7 @@ CPRatingLevelIndicatorStyle = 3;
[self setNeedsLayout];
}
- (void)setCriticalValue:(double)criticalValue;
- (void)setCriticalValue:(double)criticalValue
{
if (_criticalValue === criticalValue)
return;
+2 -2
View File
@@ -505,7 +505,7 @@ CPOffState
if (_submenu)
{
[_submenu setSupermenu:_menu];
[_submenu setTitle:[self title]]
[_submenu setTitle:[self title]];
[self setTarget:_menu];
[self setAction:@selector(submenuAction:)];
@@ -843,7 +843,7 @@ CPControlKeyMask
[item setTarget:_target];
[item setAction:_action];
[item setEnabled:_isEnabled];
[item setHidden:_isHidden]
[item setHidden:_isHidden];
[item setTag:_tag];
[item setState:_state];
[item setImage:_image];
+2 -1
View File
@@ -55,6 +55,7 @@
@"menu-item-selection-color": [CPNull null],
@"menu-item-text-shadow-color": [CPNull null],
@"menu-item-text-color": [CPNull null],
@"menu-item-disabled-text-color": [CPColor lightGrayColor],
@"menu-item-default-off-state-image": [CPNull null],
@"menu-item-default-off-state-highlighted-image": [CPNull null],
@"menu-item-default-on-state-image": [CPNull null],
@@ -124,7 +125,7 @@
- (CPColor)textColor
{
if (![_menuItem isEnabled])
return [CPColor lightGrayColor];
return [self valueForThemeAttribute:@"menu-item-disabled-text-color"];
if (_highlighted)
return [CPColor whiteColor];
+105 -3
View File
@@ -27,6 +27,9 @@
@import "CPController.j"
@import "CPKeyValueBinding.j"
@class _CPManagedProxy
@class CPPredicate;
/*!
@class
@@ -47,6 +50,9 @@
BOOL _isEditable;
BOOL _automaticallyPreparesContent;
BOOL _usesLazyFetching @accessors(getter=usesLazyFetching, setter=setUsesLazyFetching:);
BOOL _isUsingManagedProxy;
_CPManagedProxy _managedProxy;
CPCountedSet _observedKeys;
}
@@ -179,6 +185,52 @@
return _automaticallyPreparesContent;
}
/*!
Sets the entity name the controller handles.
@param CPString newEntityName - The new entity name.
*/
- (void)setEntityName:(CPString)newEntityName
{
if (!_managedProxy)
{
_managedProxy = [[_CPManagedProxy alloc] init];
_isUsingManagedProxy = YES;
}
[_managedProxy setEntityName:newEntityName];
}
/*!
Returns the entity name.
@return CPString - The name of the entity.
*/
- (CPString)entityName
{
return [_managedProxy entityName];
}
/*!
Sets the predicate used to fetch content.
@param CPPredicate newPredicate - The fetch predicate.
*/
- (void)setFetchPredicate:(CPPredicate)newPredicate
{
[_managedProxy setFetchPredicate:newPredicate];
}
/*!
Returns the fetch predicate.
@return CPPredicate - The predicate used to fetch content.
*/
- (CPPredicate)fetchPredicate
{
return [_managedProxy fetchPredicate];
}
/*!
Overridden by a subclass that require control over the creation of new objects.
*/
@@ -189,6 +241,7 @@
/*!
Sets the object class when creating new objects.
@param Class - the class of new objects that will be created.
*/
- (void)setObjectClass:(Class)aClass
@@ -363,7 +416,10 @@
var CPObjectControllerContentKey = @"CPObjectControllerContentKey",
CPObjectControllerObjectClassNameKey = @"CPObjectControllerObjectClassNameKey",
CPObjectControllerIsEditableKey = @"CPObjectControllerIsEditableKey",
CPObjectControllerAutomaticallyPreparesContentKey = @"CPObjectControllerAutomaticallyPreparesContentKey";
CPObjectControllerAutomaticallyPreparesContentKey = @"CPObjectControllerAutomaticallyPreparesContentKey",
CPObjectControllerUsesLazyFetchingKey = @"CPObjectControllerUsesLazyFetchingKey",
CPObjectControllerIsUsingManagedProxyKey = @"CPObjectControllerIsUsingManagedProxyKey",
CPObjectControllerManagedProxyKey = @"CPObjectControllerManagedProxyKey";
@implementation CPObjectController (CPCoding)
@@ -374,12 +430,18 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
if (self)
{
var objectClassName = [aCoder decodeObjectForKey:CPObjectControllerObjectClassNameKey],
objectClass = CPClassFromString(objectClassName);
objectClass = CPClassFromString(objectClassName),
content = [aCoder decodeObjectForKey:CPObjectControllerContentKey];
[self setObjectClass:objectClass || [CPMutableDictionary class]];
[self setEditable:[aCoder decodeBoolForKey:CPObjectControllerIsEditableKey]];
[self setAutomaticallyPreparesContent:[aCoder decodeBoolForKey:CPObjectControllerAutomaticallyPreparesContentKey]];
[self setContent:[aCoder decodeObjectForKey:CPObjectControllerContentKey]];
[self setUsesLazyFetching:[aCoder decodeBoolForKey:CPObjectControllerUsesLazyFetchingKey]];
_isUsingManagedProxy = [aCoder decodeBoolForKey:CPObjectControllerIsUsingManagedProxyKey];
_managedProxy = [aCoder decodeObjectForKey:CPObjectControllerManagedProxyKey];
if (content != nil)
[self setContent:content];
_observedKeys = [[CPCountedSet alloc] init];
}
@@ -398,6 +460,11 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
[aCoder encodeBool:[self isEditable] forKey:CPObjectControllerIsEditableKey];
[aCoder encodeBool:[self automaticallyPreparesContent] forKey:CPObjectControllerAutomaticallyPreparesContentKey];
[aCoder encodeBool:[self usesLazyFetching] forKey:CPObjectControllerUsesLazyFetchingKey];
[aCoder encodeBool:_isUsingManagedProxy forKey:CPObjectControllerIsUsingManagedProxyKey];
if (_managedProxy)
[aCoder encodeObject:_managedProxy forKey:CPObjectControllerManagedProxyKey];
}
- (void)awakeFromCib
@@ -825,3 +892,38 @@ var CPObjectControllerContentKey = @"CPObjectControllerCo
}
@end
@implementation _CPManagedProxy : CPObject
{
CPString _entityName @accessors(getter=entityName, setter=setEntityName:);
CPPredicate _fetchPredicate @accessors(getter=fetchPredicate, setter=setFetchPredicate:);
}
@end
var CPManagedProxyEntityNameKey = @"CPManagedProxyEntityNameKey",
CPManagedProxyFetchPredicateKey = @"CPManagedProxyFetchPredicateKey";
@implementation _CPManagedProxy (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
if (self)
{
[self setEntityName:[aCoder decodeObjectForKey:CPManagedProxyEntityNameKey]];
[self setFetchPredicate:[aCoder decodeObjectForKey:CPManagedProxyFetchPredicateKey]];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[aCoder encodeObject:[self entityName] forKey:CPManagedProxyEntityNameKey];
[aCoder encodeObject:[self fetchPredicate] forKey:CPManagedProxyFetchPredicateKey];
}
@end
+2 -2
View File
@@ -1923,7 +1923,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
while (index !== CPNotFound)
{
[items addObject:[_outlineView itemAtRow:index]]
[items addObject:[_outlineView itemAtRow:index]];
index = [theIndexes indexGreaterThanIndex:index];
}
@@ -1957,7 +1957,7 @@ var CPOutlineViewCoalesceSelectionNotificationStateOff = 0,
- (void)_parentItemForDropOperation:(CPTableViewDropOperation)theDropOperation row:(CPInteger)theRow offset:(CGPoint)theOffset
{
if (theDropOperation === CPTableViewDropAbove)
return [_outlineView _parentItemForUpperRow:theRow - 1 andLowerRow:theRow atMouseOffset:theOffset]
return [_outlineView _parentItemForUpperRow:theRow - 1 andLowerRow:theRow atMouseOffset:theOffset];
return [_outlineView itemAtRow:theRow];
}
+3 -69
View File
@@ -44,6 +44,8 @@ CPStringPboardType = @"CPStringPboardType";
CPURLPboardType = @"CPURLPboardType";
CPImagesPboardType = @"CPImagesPboardType";
CPVideosPboardType = @"CPVideosPboardType";
CPRTFPboardType = @"CPRTFPboardType";
_CPSmartPboardType = @"_CPSmartPboardType";
UTF8PboardType = @"public.utf8-plain-text";
@@ -51,8 +53,7 @@ UTF8PboardType = @"public.utf8-plain-text";
CPImagePboardType = @"CPImagePboardType";
var CPPasteboards = nil,
supportsNativePasteboard = NO;
var CPPasteboards = nil;
/*!
@ingroup appkit
@@ -68,8 +69,6 @@ var CPPasteboards = nil,
unsigned _changeCount;
CPString _stateUID;
CPWebScriptObject _nativePasteboard;
}
/*
@@ -83,9 +82,6 @@ var CPPasteboards = nil,
[self setVersion:1.0];
CPPasteboards = @{};
if (typeof window.cpPasteboardWithName !== "undefined")
supportsNativePasteboard = YES;
}
/*!
@@ -128,12 +124,6 @@ var CPPasteboards = nil,
_provided = @{};
_changeCount = 0;
if (supportsNativePasteboard)
{
_nativePasteboard = window.cpPasteboardWithName(aName);
[self _synchronizePasteboard];
}
}
return self;
@@ -163,15 +153,6 @@ var CPPasteboards = nil,
[_owners setObject:anOwner forKey:type];
}
if (_nativePasteboard)
{
var nativeTypes = [types copy];
if ([types containsObject:CPStringPboardType])
nativeTypes.push(UTF8PboardType);
_nativePasteboard.addTypes_(nativeTypes);
}
return ++_changeCount;
}
@@ -182,12 +163,6 @@ var CPPasteboards = nil,
@return the pasteboard's change count
*/
- (unsigned)declareTypes:(CPArray)types owner:(id)anOwner
{
[self _declareTypes:types owner:anOwner updateNativePasteboard:YES];
}
/*! @ignore */
- (unsigned)_declareTypes:(CPArray)types owner:(id)anOwner updateNativePasteboard:(BOOL)shouldUpdate
{
[_types setArray:types];
@@ -201,16 +176,6 @@ var CPPasteboards = nil,
[_owners setObject:anOwner forKey:_types[count]];
}
if (_nativePasteboard && shouldUpdate)
{
var nativeTypes = [types copy];
if ([types containsObject:CPStringPboardType])
nativeTypes.push(UTF8PboardType);
_nativePasteboard.declareTypes_(nativeTypes);
_changeCount = _nativePasteboard.changeCount();
}
return ++_changeCount;
}
@@ -273,7 +238,6 @@ var CPPasteboards = nil,
*/
- (CPArray)types
{
[self _synchronizePasteboard];
return _types;
}
@@ -312,36 +276,6 @@ var CPPasteboards = nil,
return nil;
}
- (void)_synchronizePasteboard
{
if (_nativePasteboard && _nativePasteboard.changeCount() > _changeCount)
{
var nativeTypes = [_nativePasteboard.types() copy];
if ([nativeTypes containsObject:UTF8PboardType])
nativeTypes.push(CPStringPboardType);
[self _declareTypes:nativeTypes owner:self updateNativePasteboard:NO];
_changeCount = _nativePasteboard.changeCount();
}
}
/*! @ignore
method provided for integration with native pasteboard
*/
- (void)pasteboard:(CPPasteboard)aPasteboard provideDataForType:(CPString)aType
{
if (aType === CPStringPboardType)
{
var string = _nativePasteboard.stringForType_(UTF8PboardType);
[self setString:string forType:CPStringPboardType];
[self setString:string forType:UTF8PboardType];
}
else
[self setString:_nativePasteboard.stringForType_(aType) forType:aType];
}
/*!
Returns the property list for the specified data type
@param aType the requested data type
+27 -12
View File
@@ -361,15 +361,10 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
*/
- (CPArray)itemTitles
{
var titles = [],
items = [self itemArray],
index = 0,
count = [items count];
for (; index < count; ++index)
titles.push([items[index] title]);
return titles;
return [[self itemArray] arrayByApplyingBlock:function(item)
{
return [item title];
}];
}
/*!
@@ -852,7 +847,17 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
{
var count = [aValue count],
options = [_info objectForKey:CPOptionsKey],
offset = [self _getInsertNullOffset];
offset = [self _getInsertNullOffset],
selectedBindingInfo = [_source infoForBinding:CPSelectedObjectBinding],
selectedObject = nil;
if (selectedBindingInfo)
{
var destination = [selectedBindingInfo objectForKey:CPObservedObjectKey],
keyPath = [selectedBindingInfo objectForKey:CPObservedKeyPathKey];
selectedObject = [destination valueForKeyPath:keyPath];
}
if (count + offset != [_source numberOfItems])
{
@@ -863,9 +868,19 @@ CPPopUpButtonStatePullsDown = CPThemeState("pulls-down");
for (var i = 0; i < count; i++)
{
var item = [[CPMenuItem alloc] initWithTitle:@"" action:NULL keyEquivalent:nil];
[self _setValue:[aValue objectAtIndex:i] forItem:item withOptions:options];
var item = [[CPMenuItem alloc] initWithTitle:@"" action:NULL keyEquivalent:nil],
itemValue = [aValue objectAtIndex:i];
[self _setValue:itemValue forItem:item withOptions:options];
[_source addItem:item];
// Select this item if it is the one selected by the selected object binding
// This is needed if the selected object binding is set before the items
// from the content binding
if (itemValue === selectedObject)
{
[_source setSelectedIndex:[_source numberOfItems] - 1];
}
}
}
else
+4 -4
View File
@@ -463,13 +463,13 @@ var CPProgressIndicatorSpinningStyleColors = [];
var midX = CGRectGetMidX(rect),
midY = CGRectGetMidY(rect),
endAngle = Math.PI * 2 * (([self doubleValue] - [self minValue]) / ([self maxValue] - [self minValue])) - Math.PI / 2,
radius = MIN(rect.size.width / 2, rect.size.height / 2)
radius = MIN(rect.size.width / 2, rect.size.height / 2);
CGContextBeginPath(context);
CGContextSetLineWidth(context, borderSize);
CGContextSetFillColor(context, [self currentValueForThemeAttribute:@"circular-color"])
CGContextSetFillColor(context, [self currentValueForThemeAttribute:@"circular-color"]);
CGContextMoveToPoint(context, midX, midY);
CGContextAddArc(context, midX, midY, radius, 3 * Math.PI / 2, endAngle, YES)
CGContextAddArc(context, midX, midY, radius, 3 * Math.PI / 2, endAngle, YES);
CGContextAddLineToPoint(context, midX, midY);
CGContextClosePath(context);
CGContextFillPath(context);
@@ -478,7 +478,7 @@ var CPProgressIndicatorSpinningStyleColors = [];
else if ([self doubleValue] == [self maxValue])
{
CGContextBeginPath(context);
CGContextSetFillColor(context, [self currentValueForThemeAttribute:@"circular-color"])
CGContextSetFillColor(context, [self currentValueForThemeAttribute:@"circular-color"]);
CGContextAddEllipseInRect(context, rect);
CGContextClosePath(context);
CGContextFillPath(context);
@@ -471,9 +471,11 @@ CPTransformableAttributeType = 1800;
var value;
if (attributeType >= CPInteger16AttributeType && attributeType <= CPFloatAttributeType)
value = [aView intValue];
value = [aView floatValue];
else if (attributeType == CPBooleanAttributeType)
value = [aView state];
else if (attributeType == CPDateAttributeType)
value = [aView dateValue];
else
value = [aView stringValue];
+1 -1
View File
@@ -146,7 +146,7 @@ var CPRuleEditorItemPBoardType = @"CPRuleEditorItemPBoardType",
@"slice-top-border-color": [CPNull null],
@"slice-bottom-border-color": [CPNull null],
@"slice-last-bottom-border-color": [CPNull null],
@"font": [CPNull null],
@"font": [CPFont systemFontOfSize:12],
@"font-color": [CPNull null],
@"add-image": [CPNull null],
@"remove-image": [CPNull null],
@@ -209,8 +209,7 @@
- (void)_reconfigureSubviews
{
var ruleItems,
criteria,
var criteria,
repObject,
menuItem,
ruleView,
@@ -366,11 +365,12 @@
count = [_ruleOptionViews count],
sliceFrame = [self frame],
image = [_ruleEditor _imageAdd],
imageSize = image ? [image size] : CGSizeMake(0,0),
buttonFrame = CGRectMake(CGRectGetWidth(sliceFrame) - [image size].width - [self _rowButtonsRightHorizontalPadding], ([_ruleEditor rowHeight] - [image size].height) / 2 - 1, [image size].width, [image size].height);
buttonFrame = CGRectMake(CGRectGetWidth(sliceFrame) - imageSize.width - [self _rowButtonsRightHorizontalPadding], ([_ruleEditor rowHeight] - imageSize.height) / 2 - 1, imageSize.width, imageSize.height);
[_addButton setFrame:buttonFrame];
buttonFrame.origin.x -= [image size].width + [self _rowButtonsInterviewHorizontalPadding];
buttonFrame.origin.x -= imageSize.width + [self _rowButtonsInterviewHorizontalPadding];
[_subtractButton setFrame:buttonFrame];
if (widthChanged)
+5
View File
@@ -35,6 +35,11 @@
CPArray _allowedFileTypes @accessors(property=allowedFileTypes);
}
+ (CPURL)proposedFileURLWithDocumentName:(CPString)aDocumentName
{
return [CPURL URLWithString:aDocumentName];
}
+ (id)savePanel
{
return [[CPSavePanel alloc] init];
+1 -1
View File
@@ -1253,7 +1253,7 @@ Notifies the delegate when the scroll view has finished scrolling.
}
if (_timerScrollersHide)
[_timerScrollersHide invalidate]
[_timerScrollersHide invalidate];
_timerScrollersHide = [CPTimer scheduledTimerWithTimeInterval:CPScrollViewFadeOutTime target:self selector:@selector(_hideScrollers:) userInfo:nil repeats:NO];
}
+11 -9
View File
@@ -316,7 +316,7 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
// The ordering of these tests is important. We check the knob and
// page rects first since they may overlap with the arrows.
if (![self hasThemeState:CPThemeStateSelected])
if (![self hasThemeState:CPThemeStateSelected] && ![self hasThemeState:CPThemeStateScrollViewLegacy])
return CPScrollerNoPart;
if (CGRectContainsPoint([self rectForPart:CPScrollerKnob], aPoint))
@@ -380,9 +380,10 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
effectiveIncrementLineHeight = incrementLineSize.height + trackInset.bottom,
slotSize = height - effectiveDecrementLineHeight - effectiveIncrementLineHeight,
minimumKnobLength = [self currentValueForThemeAttribute:"minimum-knob-length"],
knobVerticalInset = knobInset.top + knobInset.bottom,
knobWidth = width - knobInset.left - knobInset.right,
knobHeight = MAX(minimumKnobLength, (slotSize * _knobProportion)),
knobLocation = effectiveDecrementLineHeight + (slotSize - knobHeight) * [self floatValue];
knobHeight = MAX(minimumKnobLength, ((slotSize - knobVerticalInset) * _knobProportion)),
knobLocation = effectiveDecrementLineHeight + (slotSize - knobHeight - knobVerticalInset) * [self floatValue] + knobInset.top;
_partRects[CPScrollerDecrementPage] = CGRectMake(0.0, effectiveDecrementLineHeight, width, knobLocation - effectiveDecrementLineHeight);
_partRects[CPScrollerKnob] = CGRectMake(knobInset.left, knobLocation, knobWidth, knobHeight);
@@ -409,9 +410,10 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
effectiveIncrementLineWidth = incrementLineSize.width + trackInset.right,
slotSize = width - effectiveDecrementLineWidth - effectiveIncrementLineWidth,
minimumKnobLength = [self currentValueForThemeAttribute:"minimum-knob-length"],
knobWidth = MAX(minimumKnobLength, (slotSize * _knobProportion)),
knobHorizontalInset = knobInset.left + knobInset.right,
knobWidth = MAX(minimumKnobLength, ((slotSize - knobHorizontalInset) * _knobProportion)),
knobHeight = height - knobInset.top - knobInset.bottom,
knobLocation = effectiveDecrementLineWidth + (slotSize - knobWidth) * [self floatValue];
knobLocation = effectiveDecrementLineWidth + (slotSize - knobWidth - knobHorizontalInset) * [self floatValue] + knobInset.left;
_partRects[CPScrollerDecrementPage] = CGRectMake(effectiveDecrementLineWidth, 0.0, knobLocation - effectiveDecrementLineWidth, height);
_partRects[CPScrollerKnob] = CGRectMake(knobLocation, knobInset.top, knobWidth, knobHeight);
@@ -460,9 +462,6 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
*/
- (void)fadeOut
{
if ([self hasThemeState:CPThemeStateScrollViewLegacy])
return;
[_animationScroller startAnimation];
}
@@ -765,7 +764,10 @@ CPThemeStateScrollerKnobDark = CPThemeState("scroller-knob-dark");
if (_timerFadeOut)
[_timerFadeOut invalidate];
_timerFadeOut = [CPTimer scheduledTimerWithTimeInterval:1.2 target:self selector:@selector(_performFadeOut:) userInfo:nil repeats:NO];
if ([self hasThemeState:CPThemeStateScrollViewLegacy])
[self unsetThemeState:CPThemeStateSelected];
else
_timerFadeOut = [CPTimer scheduledTimerWithTimeInterval:1.2 target:self selector:@selector(_performFadeOut:) userInfo:nil repeats:NO];
}
+143 -39
View File
@@ -34,8 +34,7 @@ CPSearchFieldRecentsMenuItemTag = 1001;
CPSearchFieldClearRecentsMenuItemTag = 1002;
CPSearchFieldNoRecentsMenuItemTag = 1003;
var CPAutosavedRecentsChangedNotification = @"CPAutosavedRecentsChangedNotification",
RECENT_SEARCH_PREFIX = @" ";
var CPAutosavedRecentsChangedNotification = @"CPAutosavedRecentsChangedNotification";
/*!
@ingroup appkit
@@ -74,10 +73,19 @@ var CPAutosavedRecentsChangedNotification = @"CPAutosavedRecentsChangedNotificat
@"image-cancel": [CPNull null],
@"image-cancel-pressed": [CPNull null],
@"image-search-inset" : CGInsetMake(0, 0, 0, 5),
@"image-cancel-inset" : CGInsetMake(0, 5, 0, 0)
@"image-cancel-inset" : CGInsetMake(0, 5, 0, 0),
@"search-right-margin": 2
};
}
+ (Class)_binderClassForBinding:(CPString)aBinding
{
if (aBinding === CPPredicateBinding)
return [_CPSearchFieldPredicateBinder class];
return [super _binderClassForBinding:aBinding];
}
- (id)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame])
@@ -88,10 +96,6 @@ var CPAutosavedRecentsChangedNotification = @"CPAutosavedRecentsChangedNotificat
_recentsAutosaveName = nil;
[self _init];
#if PLATFORM(DOM)
_cancelButton._DOMElement.style.cursor = "default";
_searchButton._DOMElement.style.cursor = "default";
#endif
}
return self;
@@ -178,7 +182,7 @@ var CPAutosavedRecentsChangedNotification = @"CPAutosavedRecentsChangedNotificat
- (void)resetSearchButton
{
var button = [self searchButton],
searchButtonImage = (_searchMenuTemplate === nil) ? [self valueForThemeAttribute:@"image-search"] : [self valueForThemeAttribute:@"image-find"];
searchButtonImage = (_searchMenuTemplate === nil) ? [self currentValueForThemeAttribute:@"image-search"] : [self currentValueForThemeAttribute:@"image-find"];
[button setBordered:NO];
[button setImageScaling:CPImageScaleAxesIndependently];
@@ -247,8 +251,9 @@ var CPAutosavedRecentsChangedNotification = @"CPAutosavedRecentsChangedNotificat
if (_searchButton)
{
var searchBounds = [self searchButtonRectForBounds:bounds];
leftOffset = CGRectGetMaxX(searchBounds) + 2;
var searchBounds = [self searchButtonRectForBounds:bounds],
rightMargin = [self currentValueForThemeAttribute:@"search-right-margin"];
leftOffset = CGRectGetMaxX(searchBounds) + rightMargin;
}
if (_cancelButton)
@@ -387,9 +392,9 @@ var CPAutosavedRecentsChangedNotification = @"CPAutosavedRecentsChangedNotificat
*/
- (void)setRecentSearches:(CPArray)searches
{
var max = MIN([self maximumRecents], [searches count]),
searches = [searches subarrayWithRange:CPMakeRange(0, max)];
var max = MIN([self maximumRecents], [searches count]);
searches = [searches subarrayWithRange:CPMakeRange(0, max)];
_recentSearches = searches;
[self _autosaveRecentSearchList];
}
@@ -532,19 +537,16 @@ var CPAutosavedRecentsChangedNotification = @"CPAutosavedRecentsChangedNotificat
}
/*!
Provides the common case items for a recent searches menu. If there are not recent searches,
displays a single disabled item:
No Recent Searches
Provides the common case items for a recent searches menu.
If there are 1 more recent searches, it displays:
Recent Searches
recent search 1
recent search 2
etc.
Clear
---------------------
Clear Recent Searches
Recent Searches
recent search 1
recent search 2
etc.
If you wish to add items before or after the template, you can. If you put items
before, a separator will automatically be placed before the default template item.
@@ -569,6 +571,13 @@ var CPAutosavedRecentsChangedNotification = @"CPAutosavedRecentsChangedNotificat
var template = [[CPMenu alloc] init],
item;
item = [[CPMenuItem alloc] initWithTitle:@"Clear"
action:@selector(_searchFieldClearRecents:)
keyEquivalent:@""];
[item setTag:CPSearchFieldClearRecentsMenuItemTag];
[item setTarget:self];
[template addItem:item];
item = [[CPMenuItem alloc] initWithTitle:@"Recent Searches"
action:nil
keyEquivalent:@""];
@@ -583,20 +592,6 @@ var CPAutosavedRecentsChangedNotification = @"CPAutosavedRecentsChangedNotificat
[item setTarget:self];
[template addItem:item];
item = [[CPMenuItem alloc] initWithTitle:@"Clear Recent Searches"
action:@selector(_searchFieldClearRecents:)
keyEquivalent:@""];
[item setTag:CPSearchFieldClearRecentsMenuItemTag];
[item setTarget:self];
[template addItem:item];
item = [[CPMenuItem alloc] initWithTitle:@"No Recent Searches"
action:nil
keyEquivalent:@""];
[item setTag:CPSearchFieldNoRecentsMenuItemTag];
[item setEnabled:NO];
[template addItem:item];
return template;
}
@@ -609,6 +604,8 @@ var CPAutosavedRecentsChangedNotification = @"CPAutosavedRecentsChangedNotificat
countOfRecents = [_recentSearches count],
numberOfItems = [_searchMenuTemplate numberOfItems];
[menu setAutoenablesItems:NO];
for (var i = 0; i < numberOfItems; i++)
{
var item = [[_searchMenuTemplate itemAtIndex:i] copy];
@@ -629,8 +626,7 @@ var CPAutosavedRecentsChangedNotification = @"CPAutosavedRecentsChangedNotificat
for (var recentIndex = 0; recentIndex < countOfRecents; ++recentIndex)
{
// RECENT_SEARCH_PREFIX is a hack until CPMenuItem -setIndentationLevel works
var recentItem = [[CPMenuItem alloc] initWithTitle:RECENT_SEARCH_PREFIX + [_recentSearches objectAtIndex:recentIndex]
var recentItem = [[CPMenuItem alloc] initWithTitle:[_recentSearches objectAtIndex:recentIndex]
action:itemAction
keyEquivalent:[item keyEquivalent]];
[item setTarget:self];
@@ -690,7 +686,7 @@ var CPAutosavedRecentsChangedNotification = @"CPAutosavedRecentsChangedNotificat
- (void)_showMenu
{
if (_searchMenu === nil || [_searchMenu numberOfItems] === 0 || ![self isEnabled])
if (_searchMenu === nil || [_searchMenu numberOfItems] === 0 || ![self isEnabled] || ([_recentSearches count] === 0))
return;
var aFrame = [[self superview] convertRect:[self frame] toView:nil],
@@ -718,7 +714,7 @@ var CPAutosavedRecentsChangedNotification = @"CPAutosavedRecentsChangedNotificat
- (void)_searchFieldSearch:(id)sender
{
var searchString = [[sender title] substringFromIndex:[RECENT_SEARCH_PREFIX length]];
var searchString = [sender title];
if ([sender tag] != CPSearchFieldRecentsMenuItemTag)
[self _addStringToRecentSearches:searchString];
@@ -772,8 +768,75 @@ var CPAutosavedRecentsChangedNotification = @"CPAutosavedRecentsChangedNotificat
_recentSearches = list;
}
- (void)unbind:(CPString)aBinding
{
[super unbind:aBinding];
// our CPPredicateBinding binder adds a binding to the value.
// this private binding has to be also removed
if (aBinding === CPPredicateBinding)
[[[self class] _binderClassForBinding:aBinding] unbind:CPValueBinding forObject:self];
}
@end
#pragma mark -
@implementation CPSearchField (CPTrackingArea)
{
CPTrackingArea _searchButtonTrackingArea;
CPTrackingArea _cancelButtonTrackingArea;
}
- (void)updateTrackingAreas
{
if (_searchButtonTrackingArea)
{
[self removeTrackingArea:_searchButtonTrackingArea];
_searchButtonTrackingArea = nil;
}
if (_cancelButtonTrackingArea)
{
[self removeTrackingArea:_cancelButtonTrackingArea];
_cancelButtonTrackingArea = nil;
}
if (_searchButton)
{
_searchButtonTrackingArea = [[CPTrackingArea alloc] initWithRect:[_searchButton frame]
options:CPTrackingCursorUpdate | CPTrackingActiveInKeyWindow
owner:self
userInfo:@{ @"isButton": YES }];
[self addTrackingArea:_searchButtonTrackingArea];
}
if (_cancelButton)
{
_cancelButtonTrackingArea = [[CPTrackingArea alloc] initWithRect:[_cancelButton frame]
options:CPTrackingCursorUpdate | CPTrackingActiveInKeyWindow
owner:self
userInfo:@{ @"isButton": YES }];
[self addTrackingArea:_cancelButtonTrackingArea];
}
[super updateTrackingAreas];
}
- (void)cursorUpdate:(CPEvent)anEvent
{
if ([[[anEvent trackingArea] userInfo] objectForKey:@"isButton"])
[[CPCursor arrowCursor] set];
else
[super cursorUpdate:anEvent];
}
@end
#pragma mark -
var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
CPSendsWholeSearchStringKey = @"CPSendsWholeSearchStringKey",
CPSendsSearchStringImmediatelyKey = @"CPSendsSearchStringImmediatelyKey",
@@ -826,3 +889,44 @@ var CPRecentsAutosaveNameKey = @"CPRecentsAutosaveNameKey",
}
@end
@implementation _CPSearchFieldPredicateBinder : CPBinder
{
CPArrayController _controller;
CPString _predicateFormat;
}
- (void)setValue:(id)aValue forBinding:(CPString)aBinding
{
if (aBinding === CPPredicateBinding)
{
var options = [_info objectForKey:CPOptionsKey];
_controller = [_info objectForKey:CPObservedObjectKey];
_predicateFormat = [options objectForKey:"CPPredicateFormat"];
[_source bind:CPValueBinding toObject:self withKeyPath:"searchFieldValue" options:nil];
}
}
- (void)setSearchFieldValue:(CPString)aValue
{
var destination = [_info objectForKey:CPObservedObjectKey],
keyPath = [_info objectForKey:CPObservedKeyPathKey];
var formatString = _predicateFormat.replace(/\$value/g, "%@");
[self suppressSpecificNotificationFromObject:destination keyPath:keyPath];
if (aValue)
[_controller setFilterPredicate:[CPPredicate predicateWithFormat:formatString, aValue]];
else
[_controller setFilterPredicate:nil];
[self unsuppressSpecificNotificationFromObject:destination keyPath:keyPath];
}
- (CPString)searchFieldValue
{
return [_source stringValue];
}
@end
+57 -48
View File
@@ -604,7 +604,12 @@ CPSegmentSwitchTrackingMomentary = 2;
- (CPView)createEphemeralSubviewNamed:(CPString)aName
{
if ([aName hasPrefix:@"segment-content"])
return [[_CPImageAndTextView alloc] initWithFrame:CGRectMakeZero()];
{
var view = [[_CPImageAndTextView alloc] initWithFrame:CGRectMakeZero()];
[view _setUsesSingleLineMode:YES];
return view;
}
return [[CPView alloc] initWithFrame:CGRectMakeZero()];
}
@@ -867,64 +872,68 @@ CPSegmentSwitchTrackingMomentary = 2;
var type = [anEvent type],
location = [self convertPoint:[anEvent locationInWindow] fromView:nil];
if (type == CPLeftMouseUp)
switch (type)
{
if (_trackingSegment == -1)
case CPLeftMouseUp:
if (_trackingSegment === CPNotFound)
return;
if (_trackingSegment === [self testSegment:location])
{
if (_trackingMode == CPSegmentSwitchTrackingSelectAny)
{
[self setSelected:![self isSelectedForSegment:_trackingSegment] forSegment:_trackingSegment];
// With ANY, _selectedSegment means last pressed.
_selectedSegment = _trackingSegment;
}
else
[self setSelected:YES forSegment:_trackingSegment];
[self sendAction:[self action] to:[self target]];
if (_trackingMode == CPSegmentSwitchTrackingMomentary)
{
[self setSelected:NO forSegment:_trackingSegment];
_selectedSegment = CPNotFound;
}
}
[self drawSegmentBezel:_trackingSegment highlight:NO];
_trackingSegment = CPNotFound;
return;
if (_trackingSegment === [self testSegment:location])
{
if (_trackingMode == CPSegmentSwitchTrackingSelectAny)
case CPLeftMouseDown:
var trackingSegment = [self testSegment:location];
if (trackingSegment > CPNotFound && [self isEnabledForSegment:trackingSegment])
{
[self setSelected:![self isSelectedForSegment:_trackingSegment] forSegment:_trackingSegment];
// With ANY, _selectedSegment means last pressed.
_selectedSegment = _trackingSegment;
_trackingHighlighted = YES;
_trackingSegment = trackingSegment;
[self drawSegmentBezel:_trackingSegment highlight:YES];
}
else
[self setSelected:YES forSegment:_trackingSegment];
[self sendAction:[self action] to:[self target]];
break;
if (_trackingMode == CPSegmentSwitchTrackingMomentary)
case CPLeftMouseDragged:
if (_trackingSegment === CPNotFound)
return;
var highlighted = [self testSegment:location] === _trackingSegment;
if (highlighted != _trackingHighlighted)
{
[self setSelected:NO forSegment:_trackingSegment];
_trackingHighlighted = highlighted;
_selectedSegment = CPNotFound;
[self drawSegmentBezel:_trackingSegment highlight:_trackingHighlighted];
}
}
[self drawSegmentBezel:_trackingSegment highlight:NO];
_trackingSegment = -1;
return;
}
if (type == CPLeftMouseDown)
{
var trackingSegment = [self testSegment:location];
if (trackingSegment > -1 && [self isEnabledForSegment:trackingSegment])
{
_trackingHighlighted = YES;
_trackingSegment = trackingSegment;
[self drawSegmentBezel:_trackingSegment highlight:YES];
}
}
else if (type == CPLeftMouseDragged)
{
if (_trackingSegment == -1)
return;
var highlighted = [self testSegment:location] === _trackingSegment;
if (highlighted != _trackingHighlighted)
{
_trackingHighlighted = highlighted;
[self drawSegmentBezel:_trackingSegment highlight:_trackingHighlighted];
}
break;
}
[CPApp setTarget:self selector:@selector(trackSegment:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
+92 -60
View File
@@ -117,6 +117,7 @@ var ShouldSuppressResizeNotifications = 1,
CPArray _DOMDividerElements;
CPString _dividerImagePath;
int _drawingDivider;
BOOL _isTracking;
CPString _autosaveName;
BOOL _shouldAutosave;
@@ -158,6 +159,7 @@ var ShouldSuppressResizeNotifications = 1,
_buttonBars = [];
_shouldAutosave = YES;
_isTracking = NO;
[self _setVertical:YES];
}
@@ -213,6 +215,9 @@ var ShouldSuppressResizeNotifications = 1,
[_subviews[index] setFrame:CGRectMake(0, ROUND((eachSize + dividerThickness) * index), frame.size.width, eachSize)];
}
if (_DOMDividerElements[_drawingDivider])
[self _setupDOMDivider];
[self setNeedsDisplay:YES];
[self _postNotificationDidResize];
@@ -363,9 +368,9 @@ var ShouldSuppressResizeNotifications = 1,
_DOMDividerElements[_drawingDivider].style.backgroundRepeat = "repeat";
CPDOMDisplayServerAppendChild(_DOMElement, _DOMDividerElements[_drawingDivider]);
[self _setupDOMDivider];
}
[self _setupDOMDivider];
CPDOMDisplayServerSetStyleLeftTop(_DOMDividerElements[_drawingDivider], NULL, CGRectGetMinX(aRect), CGRectGetMinY(aRect));
CPDOMDisplayServerSetStyleSize(_DOMDividerElements[_drawingDivider], CGRectGetWidth(aRect), CGRectGetHeight(aRect));
#endif
@@ -452,17 +457,26 @@ var ShouldSuppressResizeNotifications = 1,
return nil;
var point = [self convertPoint:aPoint fromView:[self superview]],
count = [_subviews count] - 1;
dividerIndex = [self _dividerAtPoint:point];
for (var i = 0; i < count; i++)
{
if ([self cursorAtPoint:point hitDividerAtIndex:i])
return self;
}
if (dividerIndex !== CPNotFound)
return self;
return [super hitTest:aPoint];
}
- (CPInteger)_dividerAtPoint:(CGPoint)aPoint
{
var count = [_subviews count] - 1;
for (var i = 0; i < count; i++)
{
if ([self cursorAtPoint:aPoint hitDividerAtIndex:i])
return i;
}
return CPNotFound;
}
/*
Tracks the divider.
@param anEvent the input event
@@ -473,12 +487,13 @@ var ShouldSuppressResizeNotifications = 1,
if (type == CPLeftMouseUp)
{
// We disabled autosaving during tracking.
_shouldAutosave = YES;
if (_currentDivider != CPNotFound)
if ([anEvent clickCount] == 2 || (_isTracking && _currentDivider != CPNotFound))
{
// We disabled autosaving during tracking.
_shouldAutosave = YES;
_currentDivider = CPNotFound;
_isTracking = NO;
[self _autosave];
[self _updateResizeCursor:anEvent];
}
@@ -488,59 +503,55 @@ var ShouldSuppressResizeNotifications = 1,
if (type == CPLeftMouseDown)
{
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil],
count = [_subviews count] - 1;
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
_currentDivider = [self _dividerAtPoint:point];
_currentDivider = CPNotFound;
var frame = [_subviews[_currentDivider] frame],
startPosition = frame.origin[_originComponent] + frame.size[_sizeComponent];
for (var i = 0; i < count; i++)
if ([anEvent clickCount] == 2 &&
[self _delegateRespondsToSplitViewCanCollapseSubview] &&
[self _delegateRespondsToSplitViewshouldCollapseSubviewForDoubleClickOnDividerAtIndex])
{
var frame = [_subviews[i] frame],
startPosition = frame.origin[_originComponent] + frame.size[_sizeComponent];
var minPosition = [self minPossiblePositionOfDividerAtIndex:_currentDivider],
maxPosition = [self maxPossiblePositionOfDividerAtIndex:_currentDivider],
preCollapsePosition = [_preCollapsePositions objectForKey:"" + _currentDivider] || 0;
if ([self cursorAtPoint:point hitDividerAtIndex:i])
if ([self _sendDelegateSplitViewCanCollapseSubview:_subviews[_currentDivider]] && [self _sendDelegateSplitViewShouldCollapseSubview:_subviews[_currentDivider] forDoubleClickOnDividerAtIndex:_currentDivider])
{
if ([anEvent clickCount] == 2 &&
[self _delegateRespondsToSplitViewCanCollapseSubview] &&
[self _delegateRespondsToSplitViewshouldCollapseSubviewForDoubleClickOnDividerAtIndex])
{
var minPosition = [self minPossiblePositionOfDividerAtIndex:i],
maxPosition = [self maxPossiblePositionOfDividerAtIndex:i],
preCollapsePosition = [_preCollapsePositions objectForKey:"" + i] || 0;
if ([self _sendDelegateSplitViewCanCollapseSubview:_subviews[i]] && [self _sendDelegateSplitViewShouldCollapseSubview:_subviews[i] forDoubleClickOnDividerAtIndex:i])
{
if ([self isSubviewCollapsed:_subviews[i]])
[self setPosition:preCollapsePosition ? preCollapsePosition : (minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i];
else
[self setPosition:minPosition ofDividerAtIndex:i];
}
else if ([self _sendDelegateSplitViewCanCollapseSubview:_subviews[i + 1]] && [self _sendDelegateSplitViewShouldCollapseSubview:_subviews[i + 1] forDoubleClickOnDividerAtIndex:i])
{
if ([self isSubviewCollapsed:_subviews[i + 1]])
[self setPosition:preCollapsePosition ? preCollapsePosition : (minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:i];
else
[self setPosition:maxPosition ofDividerAtIndex:i];
}
}
if ([self isSubviewCollapsed:_subviews[_currentDivider]])
[self setPosition:preCollapsePosition ? preCollapsePosition : (minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:_currentDivider];
else
{
_currentDivider = i;
_initialOffset = startPosition - point[_originComponent];
// Don't autosave during a resize. We'll wait until it's done.
_shouldAutosave = NO;
[self _postNotificationWillResize];
}
[self setPosition:minPosition ofDividerAtIndex:_currentDivider];
}
else if ([self _sendDelegateSplitViewCanCollapseSubview:_subviews[_currentDivider + 1]] && [self _sendDelegateSplitViewShouldCollapseSubview:_subviews[_currentDivider + 1] forDoubleClickOnDividerAtIndex:_currentDivider])
{
if ([self isSubviewCollapsed:_subviews[_currentDivider + 1]])
[self setPosition:preCollapsePosition ? preCollapsePosition : (minPosition + (maxPosition - minPosition) / 2) ofDividerAtIndex:_currentDivider];
else
[self setPosition:maxPosition ofDividerAtIndex:_currentDivider];
}
}
else
{
_initialOffset = startPosition - point[_originComponent];
// Don't autosave during a resize. We'll wait until it's done.
_shouldAutosave = NO;
[self _postNotificationWillResize];
}
if (_currentDivider === CPNotFound)
return;
}
else if (type == CPLeftMouseDragged && _currentDivider != CPNotFound)
{
if (!_isTracking)
{
// Don't autosave during a resize. We'll wait until it's done.
_shouldAutosave = NO;
[self _postNotificationWillResize];
_isTracking = YES;
}
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil];
[self setPosition:(point[_originComponent] + _initialOffset) ofDividerAtIndex:_currentDivider];
@@ -553,8 +564,11 @@ var ShouldSuppressResizeNotifications = 1,
- (void)mouseDown:(CPEvent)anEvent
{
// FIXME: This should not trap events if not on a divider!
[self trackDivider:anEvent];
var point = [self convertPoint:[anEvent locationInWindow] fromView:nil],
dividerIndex = [self _dividerAtPoint:point];
if (dividerIndex !== CPNotFound)
[self trackDivider:anEvent];
}
- (void)viewDidMoveToWindow
@@ -1187,18 +1201,35 @@ The sum of the views and the sum of the dividers should be equal to the size of
@end
@implementation CPSplitView (CPTrackingArea)
{
CPMutableArray _splitViewTrackingAreas;
}
- (void)updateTrackingAreas
{
[self removeAllTrackingAreas];
if (_splitViewTrackingAreas)
{
for (var i = 0, count = [_splitViewTrackingAreas count]; i < count; i++)
[self removeTrackingArea:_splitViewTrackingAreas[i]];
_splitViewTrackingAreas = nil;
}
var options = CPTrackingCursorUpdate | CPTrackingActiveInKeyWindow;
_splitViewTrackingAreas = @[];
for (var i = 0; i < _subviews.length - 1; i++)
[self addTrackingArea:[[CPTrackingArea alloc] initWithRect:[self effectiveRectOfDividerAtIndex:i]
options:options
owner:self
userInfo:nil]];
{
[_splitViewTrackingAreas addObject:[[CPTrackingArea alloc] initWithRect:[self effectiveRectOfDividerAtIndex:i]
options:options
owner:self
userInfo:nil]];
[self addTrackingArea:_splitViewTrackingAreas[i]];
}
[super updateTrackingAreas];
}
- (void)cursorUpdate:(CPEvent)anEvent
@@ -1438,6 +1469,7 @@ var CPSplitViewDelegateKey = "CPSplitViewDelegateKey",
_currentDivider = CPNotFound;
_shouldAutosave = YES;
_isTracking = NO;
_DOMDividerElements = [];
+57 -7
View File
@@ -24,9 +24,13 @@
@import "CGGeometry.j"
@import "CPPlatformString.j"
@import "CPFont.j"
@import "CPCompatibility.j"
var CPStringSizeWithFontInWidthCache = {};
var CPStringSizeWithFontInWidthCache = [],
CPStringSizeWithFontHeightCache = [],
CPStringSizeMeasuringContext;
CPStringSizeCachingEnabled = YES;
@@ -53,21 +57,67 @@ CPStringSizeCachingEnabled = YES;
return [self sizeWithFont:aFont inWidth:NULL];
}
- (CGSize)sizeWithFont:(CPFont)aFont inWidth:(float)aWidth
+ (void) initialize
{
if ([self class] != [CPString class])
return;
#if PLATFORM(DOM)
if (CPFeatureIsCompatible(CPHTMLCanvasFeature) && !CPStringSizeMeasuringContext)
CPStringSizeMeasuringContext = CGBitmapGraphicsContextCreate();
#endif
}
- (CGSize)_sizeWithFont:(CPFont)aFont inWidth:(float)aWidth
{
var size;
#if PLATFORM(DOM)
if (!CPStringSizeCachingEnabled)
return [CPPlatformString sizeOfString:self withFont:aFont forWidth:aWidth];
var cacheKey = self + [aFont cssString] + aWidth,
size = CPStringSizeWithFontInWidthCache[cacheKey];
var sizeCacheForFont = CPStringSizeWithFontInWidthCache[self];
if (size === undefined)
{
if (sizeCacheForFont === undefined)
sizeCacheForFont = CPStringSizeWithFontInWidthCache[self] = [];
if (!aWidth)
aWidth = '0';
var cssString = [aFont cssString],
cacheKey = cssString + '_' + aWidth;
size = sizeCacheForFont[cacheKey];
if (size !== undefined && sizeCacheForFont.hasOwnProperty(cacheKey))
return CGSizeMakeCopy(size);
if (!CPFeatureIsCompatible(CPHTMLCanvasFeature) || aWidth > 0)
size = [CPPlatformString sizeOfString:self withFont:aFont forWidth:aWidth];
CPStringSizeWithFontInWidthCache[cacheKey] = size;
else
{
if (CPPlatformHasBug(CPTextSizingAlwaysNeedsSetFontBug) || CPStringSizeMeasuringContext.font !== cssString)
CPStringSizeMeasuringContext.font = cssString;
var fontHeight = CPStringSizeWithFontHeightCache[cssString];
if (fontHeight === undefined)
fontHeight = CPStringSizeWithFontHeightCache[cssString] = [aFont defaultLineHeightForFont];
size = CGSizeMake(CPStringSizeMeasuringContext.measureText(self).width, fontHeight);
}
sizeCacheForFont[cacheKey] = size;
#else
size = CGSizeMake(0, 0);
#endif
return CGSizeMakeCopy(size);
}
- (CGSize)sizeWithFont:(CPFont)aFont inWidth:(float)aWidth
{
var size = [self _sizeWithFont:aFont inWidth:aWidth];
return CGSizeMake(CEIL(size.width), size.height);
}
@end
+127 -22
View File
@@ -35,6 +35,7 @@ CPNoTabsLineBorder = 5; //Has no tabs and displays a line border.
CPNoTabsNoBorder = 6; //Displays no tabs and no border.
@class _CPTabViewBox
@class _CPSegmentedControl
var CPTabViewDidSelectTabViewItemSelector = 1 << 1,
CPTabViewShouldSelectTabViewItemSelector = 1 << 2,
@@ -65,9 +66,9 @@ var CPTabViewDidSelectTabViewItemSelector = 1 << 1,
{
CPArray _items;
CPSegmentedControl _tabs;
_CPSegmentedControl _tabs;
_CPTabViewBox _box;
CPView _placeHolderView;
CPView _placeholderView @accessors;
CPTabViewItem _selectedTabViewItem;
@@ -92,8 +93,8 @@ var CPTabViewDidSelectTabViewItemSelector = 1 << 1,
- (void)_init
{
_tabs = [[CPSegmentedControl alloc] initWithFrame:CGRectMakeZero()];
[_tabs setHitTests:NO];
_tabs = [[_CPSegmentedControl alloc] initWithFrame:CGRectMakeZero()];
[_tabs setTabView:self];
[_tabs setSegments:[CPArray array]];
var height = [_tabs valueForThemeAttribute:@"min-size"].height;
@@ -106,7 +107,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1 << 1,
[self addSubview:_box];
[self addSubview:_tabs];
_placeHolderView = nil;
_placeholderView = nil;
}
- (CPArray)items
@@ -136,6 +137,8 @@ var CPTabViewDidSelectTabViewItemSelector = 1 << 1,
- (void)_insertTabViewItems:(CPArray)tabViewItems atIndexes:(CPIndexSet)indexes
{
var prevItemsCount = [self numberOfTabViewItems];
[_tabs insertSegments:tabViewItems atIndexes:indexes];
[tabViewItems makeObjectsPerformSelector:@selector(_setTabView:) withObject:self];
@@ -143,6 +146,10 @@ var CPTabViewDidSelectTabViewItemSelector = 1 << 1,
[self _reverseSetContent];
[self _sendDelegateTabViewDidChangeNumberOfTabViewItems];
// Do not allow empty selection if selection bindings are not enabled.
if (prevItemsCount == 0 && [self numberOfTabViewItems] > 0 && ![self _isSelectionBinded])
[self _selectTabViewItemAtIndex:0];
}
/*!
@@ -169,7 +176,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1 << 1,
- (void)_didRemoveTabViewItem:(CPTabViewItem)aTabViewItem atIndex:(CPInteger)idx
{
// If the selection is managed by bindings, let the binder do that.
if ([self binderForBinding:CPSelectionIndexesBinding] || [self binderForBinding:CPSelectedIndexBinding])
if ([self _isSelectionBinded])
return;
if (_selectedTabViewItem == aTabViewItem)
@@ -335,13 +342,40 @@ var CPTabViewDidSelectTabViewItemSelector = 1 << 1,
[_tabs setSelectedSegment:anIndex];
_selectedTabViewItem = aTabViewItem;
[self _displayItemView:[aTabViewItem view]];
[self _loadTabViewItem:aTabViewItem];
[self _sendDelegateDidSelectTabViewItem:aTabViewItem];
return YES;
}
- (void)_loadTabViewItem:(CPTabViewItem)aTabViewItem
{
var controller = [aTabViewItem viewController];
if (controller !== nil && ![controller isViewLoaded])
{
[controller loadViewWithCompletionHandler:function(view, error)
{
if (error !== nil)
{
CPLog.warn("Could not load the view for item " + aTabViewItem + ". " + error);
}
else if (view !== nil)
{
[aTabViewItem setView:view];
if ([self selectedTabViewItem] == aTabViewItem)
[self _displayItemView:view];
}
}];
}
else
{
[self _displayItemView:[aTabViewItem view]];
}
}
/*!
Returns the current item being displayed.
@return the tab view item currenly being displayed by the receiver
@@ -492,14 +526,6 @@ var CPTabViewDidSelectTabViewItemSelector = 1 << 1,
return [_box backgroundColor];
}
- (void)mouseDown:(CPEvent)anEvent
{
var segmentIndex = [_tabs testSegment:[_tabs convertPoint:[anEvent locationInWindow] fromView:nil]];
if (segmentIndex != CPNotFound && [self selectTabViewItemAtIndex:segmentIndex])
[_tabs trackSegment:anEvent];
}
- (void)_repositionTabs
{
var horizontalCenterOfSelf = CGRectGetWidth([self bounds]) / 2,
@@ -584,10 +610,15 @@ var CPTabViewDidSelectTabViewItemSelector = 1 << 1,
- (CPBinder)binderForBinding:(CPString)aBinding
{
var cls = [[self class] _binderClassForBinding:aBinding]
var cls = [[self class] _binderClassForBinding:aBinding];
return [cls getBinding:aBinding forObject:self];
}
- (BOOL)_isSelectionBinded
{
return [self binderForBinding:CPSelectionIndexesBinding] || [self binderForBinding:CPSelectedIndexBinding];
}
- (void)setItems:(CPArray)tabViewItems
{
if ([tabViewItems isEqualToArray:[_tabs segments]])
@@ -614,17 +645,17 @@ var CPTabViewDidSelectTabViewItemSelector = 1 << 1,
- (void)_displayPlaceholder:(CPString)aPlaceholder
{
if (_placeHolderView == nil)
if (_placeholderView == nil)
{
_placeHolderView = [[CPView alloc] initWithFrame:CGRectMakeZero()];
_placeholderView = [[CPView alloc] initWithFrame:CGRectMakeZero()];
var textField = [[CPTextField alloc] initWithFrame:CGRectMakeZero()];
[textField setTag:1000];
[textField setTextColor:[CPColor whiteColor]];
[textField setFont:[CPFont boldFontWithName:@"Geneva" size:18 italic:YES]];
[_placeHolderView addSubview:textField];
[_placeholderView addSubview:textField];
}
var textField = [_placeHolderView viewWithTag:1000];
var textField = [_placeholderView viewWithTag:1000];
[textField setStringValue:aPlaceholder];
[textField sizeToFit];
@@ -634,7 +665,7 @@ var CPTabViewDidSelectTabViewItemSelector = 1 << 1,
[textField setFrameOrigin:origin];
[self _displayItemView:_placeHolderView];
[self _displayItemView:_placeholderView];
}
#pragma mark -
@@ -848,4 +879,78 @@ var CPTabViewItemsKey = "CPTabViewItemsKey",
return [super hitTest:aPoint];
}
@end
@end
# pragma mark -
// This subclass of CPSegmentedControl implements specific behaviour needed by CPTabView, which
// differs in some ways from normal CPSegmentedControl habits :
//
// - all items are enabled
// - when you select a tab (mouse down, holding) and drag upon another tab, the second one reacts
// (showing a pushed state) and can then be selected by releasing the mouse over it.
// - a delegate has the opportunity to accept or not the selection of an item
@implementation _CPSegmentedControl : CPSegmentedControl
{
CPTabView _tabView @accessors(property=tabView);
}
- (void)trackSegment:(CPEvent)anEvent
{
var type = [anEvent type],
location = [self convertPoint:[anEvent locationInWindow] fromView:nil],
currentSegment = [self testSegment:location];
switch (type)
{
case CPLeftMouseUp:
if (_trackingSegment === CPNotFound)
return;
if ((_trackingSegment !== _selectedSegment) &&
[_tabView _sendDelegateShouldSelectTabViewItem:[_tabView tabViewItemAtIndex:_trackingSegment]])
{
[self setSelected:YES forSegment:_trackingSegment];
_selectedSegment = _trackingSegment;
[_tabView selectTabViewItemAtIndex:_selectedSegment];
}
[self drawSegmentBezel:_trackingSegment highlight:NO];
_trackingSegment = CPNotFound;
return;
case CPLeftMouseDown:
if (currentSegment > CPNotFound)
{
_trackingSegment = currentSegment;
[self drawSegmentBezel:_trackingSegment highlight:YES];
}
break;
case CPLeftMouseDragged:
if (_trackingSegment !== currentSegment)
{
if (_trackingSegment > CPNotFound)
[self drawSegmentBezel:_trackingSegment highlight:NO];
_trackingSegment = currentSegment;
if (_trackingSegment > CPNotFound)
[self drawSegmentBezel:_trackingSegment highlight:YES];
}
break;
}
[CPApp setTarget:self selector:@selector(trackSegment:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
}
@end
+1 -1
View File
@@ -270,7 +270,7 @@ CPPressedTab = 2;
[self setLabel:title];
if ([_tabView selectedTabViewItem] == self)
[_tabView _displayItemView:[_viewController view]];
[_tabView _loadTabViewItem:self];
}
@end
+10 -2
View File
@@ -287,7 +287,7 @@ CPTableColumnUserResizingMask = 1 << 1;
if (width < [self minWidth])
[self setMinWidth:width];
else if (width > [self maxWidth])
[self setMaxWidth:width]
[self setMaxWidth:width];
if (_width !== width)
[self setWidth:width];
@@ -499,7 +499,7 @@ CPTableColumnUserResizingMask = 1 << 1;
*/
- (void)setHidden:(BOOL)shouldBeHidden
{
shouldBeHidden = !!shouldBeHidden
shouldBeHidden = !!shouldBeHidden;
if (_isHidden === shouldBeHidden)
return;
@@ -537,6 +537,14 @@ CPTableColumnUserResizingMask = 1 << 1;
return _headerToolTip;
}
/*!
@ignore
*/
- (CPString)description
{
return [CPString stringWithFormat:"<%@ 0x%@ identifier=%@>", [self className], [CPString stringWithHash:[self UID]], [self identifier]];
}
@end
@implementation CPTableColumnValueBinder : CPBinder
+33 -13
View File
@@ -89,7 +89,7 @@
var inset = [self currentValueForThemeAttribute:@"text-inset"],
bounds = [self bounds];
[_textField setFrame:CGRectMake(inset.right, inset.top, bounds.size.width - inset.right - inset.left, bounds.size.height - inset.top - inset.bottom)];
[_textField setFrame:CGRectMake(inset.left, inset.top, bounds.size.width - inset.right - inset.left, bounds.size.height - inset.top - inset.bottom)];
[_textField setTextColor:[self currentValueForThemeAttribute:@"text-color"]];
[_textField setFont:[self currentValueForThemeAttribute:@"font"]];
[_textField setTextShadowColor:[self currentValueForThemeAttribute:@"text-shadow-color"]];
@@ -417,8 +417,7 @@ var CPTableHeaderViewResizeZone = 3.0,
}
else if (_isDragging)
{
// Disable autoscrolling until it behaves correctly.
//[self _autoscroll:theEvent localLocation:currentLocation];
[self _autoscroll:theEvent localLocation:currentLocation];
[self _dragTableColumn:_activeColumn to:currentLocation];
}
else // tracking a press, could become a drag
@@ -462,18 +461,38 @@ var CPTableHeaderViewResizeZone = 3.0,
@end
@implementation CPTableHeaderView (CPTrackingArea)
{
CPMutableArray _tableHeaderViewTrackingAreas;
}
- (void)updateTrackingAreas
{
[self removeAllTrackingAreas];
if (_tableHeaderViewTrackingAreas)
{
for (var i = 0, count = [_tableHeaderViewTrackingAreas count]; i < count; i++)
[self removeTrackingArea:_tableHeaderViewTrackingAreas[i]];
_tableHeaderViewTrackingAreas = nil;
}
var options = CPTrackingCursorUpdate | CPTrackingActiveInKeyWindow;
if (!_tableView)
return;
_tableHeaderViewTrackingAreas = @[];
for (var i = 0; i < _tableView._tableColumns.length; i++)
[self addTrackingArea:[[CPTrackingArea alloc] initWithRect:[self _cursorRectForColumn:i]
options:options
owner:self
userInfo:nil]];
{
[_tableHeaderViewTrackingAreas addObject:[[CPTrackingArea alloc] initWithRect:[self _cursorRectForColumn:i]
options:options
owner:self
userInfo:nil]];
[self addTrackingArea:_tableHeaderViewTrackingAreas[i]];
}
[super updateTrackingAreas];
}
- (void)cursorUpdate:(CPEvent)anEvent
@@ -679,20 +698,21 @@ var CPTableHeaderViewResizeZone = 3.0,
[_columnDragClipView removeFromSuperview];
[_tableView _setDraggedColumn:-1];
var headerView = [[[_tableView tableColumns] objectAtIndex:aColumnIndex] headerView];
var tableColumn = [[_tableView tableColumns] objectAtIndex:aColumnIndex],
headerView = [tableColumn headerView];
[[headerView subviews] makeObjectsPerformSelector:@selector(setHidden:) withObject:NO];
if (_tableView._draggedColumnIsSelected)
[headerView setThemeState:CPThemeStateSelected];
var columnRect = [_tableView rectOfColumn:aColumnIndex];
[_tableView _reloadDataViews];
[[_tableView headerView] setNeedsLayout];
[[CPCursor arrowCursor] set];
[self updateTrackingAreas];
[_tableView _sendDelegateDidDragTableColumn:tableColumn];
}
- (BOOL)_shouldResizeTableColumn:(CPInteger)aColumnIndex at:(CGPoint)aPoint
+40 -34
View File
@@ -203,7 +203,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
@ingroup appkit
@class CPTableView
CPTableView object displays record-oriented data in a table and
A table view control 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
@ref numberofrows "numberOfRowsInTableView:" and @ref objectValueForTable "tableView:objectValueForTableColumn:row:",
@@ -346,8 +346,8 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
+ (CPDictionary)themeAttributes
{
return @{
@"alternating-row-colors": [CPNull null],
@"grid-color": [CPNull null],
@"alternating-row-colors": @[[CPColor whiteColor], [CPColor colorWithRed:245.0 / 255.0 green:249.0 / 255.0 blue:252.0 / 255.0 alpha:1.0]],
@"grid-color": [CPColor colorWithHexString:@"dce0e2"],
@"grid-line-thickness": 1.0,
@"highlighted-grid-color": [CPNull null],
@"selection-color": [CPNull null],
@@ -368,7 +368,8 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
@"dropview-above-border-color": [CPNull null],
@"dropview-above-border-width": [CPNull null],
@"dropview-above-selected-border-color": [CPNull null],
@"dropview-above-selected-border-width": [CPNull null]
@"dropview-above-selected-border-width": [CPNull null],
@"header-view-height": 25.0
};
}
@@ -390,8 +391,7 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
_selectionHighlightStyle = CPTableViewSelectionHighlightStyleRegular;
[self setUsesAlternatingRowBackgroundColors:NO];
[self setAlternatingRowBackgroundColors:
[[CPColor whiteColor], [CPColor colorWithRed:245.0 / 255.0 green:249.0 / 255.0 blue:252.0 / 255.0 alpha:1.0]]];
[self setAlternatingRowBackgroundColors:[self valueForThemeAttribute:@"alternating-row-colors"]];
_tableColumns = [];
_tableColumnRanges = [];
@@ -401,10 +401,10 @@ CPTableViewFirstColumnOnlyAutoresizingStyle = 5;
_intercellSpacing = CGSizeMake(3.0, 2.0);
_rowHeight = [self valueForThemeAttribute:@"default-row-height"];
[self setGridColor:[CPColor colorWithHexString:@"dce0e2"]];
[self setGridColor:[self valueForThemeAttribute:@"grid-color"]];
[self setGridStyleMask:CPTableViewGridNone];
[self setHeaderView:[[CPTableHeaderView alloc] initWithFrame:CGRectMake(0, 0, [self bounds].size.width, _rowHeight)]];
[self setHeaderView:[[CPTableHeaderView alloc] initWithFrame:CGRectMake(0, 0, [self bounds].size.width, [self valueForThemeAttribute:@"header-view-height"])]];
[self setCornerView:[[_CPCornerView alloc] initWithFrame:CGRectMake(0, 0, [CPScroller scrollerWidth], CGRectGetHeight([_headerView frame]))]];
_currentHighlightedTableColumn = nil;
@@ -3096,10 +3096,15 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
*/
- (CPView)dragViewForRowsWithIndexes:(CPIndexSet)theDraggedRows tableColumns:(CPArray)theTableColumns event:(CPEvent)theDragEvent offset:(CGPoint)dragViewOffset
{
var bounds = [self bounds],
var firstRowFrame = [self frameOfDataViewAtColumn:0 row:[theDraggedRows firstIndex]],
lastRowFrame = [self frameOfDataViewAtColumn:0 row:[theDraggedRows lastIndex]],
dragViewHeight = CGRectGetMaxY(lastRowFrame) - CGRectGetMinY(firstRowFrame);
var bounds = CGRectMake(0, 0, CGRectGetWidth([self bounds]), dragViewHeight),
dragView = [[CPView alloc] initWithFrame:bounds];
[dragView setAlphaValue:0.7];
// [dragView setBackgroundColor:[CPColor colorWithWhite:1 alpha:0.5]];
// We have to fetch all the data views for the selected rows and columns
// After that we can copy these add them to a transparent drag view and use that drag view
@@ -3107,7 +3112,11 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
[self _enumerateViewsInRows:theDraggedRows tableColumns:theTableColumns usingBlock:function(v, row, tableColumn, stop)
{
var column = [_tableColumns indexOfObjectIdenticalTo:tableColumn],
newDataView = [self preparedViewAtColumn:column row:row];
newDataView = [self preparedViewAtColumn:column row:row],
origin = [newDataView frame].origin;
origin.y -= CGRectGetMinY(firstRowFrame);
[newDataView setFrameOrigin:origin];
[dragView addSubview:newDataView];
}];
@@ -3751,7 +3760,7 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
{
if (!dataViewsForRow)
{
dataViewsForRow = {}
dataViewsForRow = {};
_dataViewsForRows[row] = dataViewsForRow;
}
@@ -4600,7 +4609,9 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
}
var bounds = [view bounds],
viewLocation = CGPointMake(aPoint.x - CGRectGetWidth(bounds) / 2 + offset.x, aPoint.y - CGRectGetHeight(bounds) / 2 + offset.y);
firstRowFrame = [self frameOfDataViewAtColumn:0 row:[_draggedRowIndexes firstIndex]],
viewLocation = CGPointMake(aPoint.x - CGRectGetWidth(bounds) / 2 + offset.x, aPoint.y - CGRectGetHeight(bounds) / 2 + offset.y + CGRectGetMinY(firstRowFrame));
[self dragView:view at:viewLocation offset:CGPointMakeZero() event:[CPApp currentEvent] pasteboard:pboard source:self slideBack:YES];
_startTrackingPoint = nil;
@@ -4896,7 +4907,7 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
row = _retargetedDropRow;
if (row === nil)
var row = [self _proposedRowAtPoint:location];
row = [self _proposedRowAtPoint:location];
return [self _sendDataSourceAcceptDrop:sender row:row dropOperation:operation];
}
@@ -5097,14 +5108,7 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
}
}
else if (!_isViewBased && [aView isKindOfClass:[CPControl class]] && ![aView isKindOfClass:[CPTextField class]])
{
[self getColumn:@ref(column) row:@ref(row) forView:aView];
_editingColumn = column;
_editingRow = row;
[aView addObserver:self forKeyPath:@"objectValue" options:CPKeyValueObservingOptionOld | CPKeyValueObservingOptionNew context:"editing"];
}
return aView;
}
@@ -5135,7 +5139,7 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
{
[super viewWillMoveToWindow:aWindow];
[self _stopObservingFirstResponderForWindow:aWindow];
[self _stopObservingFirstResponderForWindow:[self window]];
if (aWindow)
[self _startObservingFirstResponderForWindow:aWindow];
@@ -5236,7 +5240,7 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
if (!_isViewBased)
{
[self _setEditingState:NO forView:textField];
[self _commitDataViewObjectValue:textField];
[self _commitDataViewObjectValue:textField forColumn:_editingColumn andRow:_editingRow];
}
else
[textField setBezeled:NO];
@@ -5286,19 +5290,19 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
The action for any dataview that supports editing. This will only be called when the value was changed.
The table view becomes the first responder after user is done editing a dataview.
*/
- (void)_commitDataViewObjectValue:(id)aDataView
- (void)_commitDataViewObjectValue:(id)aDataView forColumn:(CPInteger)column andRow:(CPInteger)row
{
var editingTableColumn = _tableColumns[_editingColumn];
var editingTableColumn = _tableColumns[column];
if (_implementedDataSourceMethods & CPTableViewDataSource_tableView_setObjectValue_forTableColumn_row_)
[_dataSource tableView:self setObjectValue:[aDataView objectValue] forTableColumn:editingTableColumn row:_editingRow];
[_dataSource tableView:self setObjectValue:[aDataView objectValue] forTableColumn:editingTableColumn row:row];
// Allow the column binding to do a reverse set. Note that we do this even if the data source method above
// is implemented.
[editingTableColumn _reverseSetDataView:aDataView forRow:_editingRow];
[editingTableColumn _reverseSetDataView:aDataView forRow:row];
if (_editingRow !== CPNotFound && _editingColumn !== CPNotFound)
[self reloadDataForRowIndexes:[CPIndexSet indexSetWithIndex:_editingRow] columnIndexes:[CPIndexSet indexSetWithIndex:_editingColumn]];
if (row !== CPNotFound && column !== CPNotFound)
[self _reloadDataForRowIndexes:[CPIndexSet indexSetWithIndex:row] columnIndexes:[CPIndexSet indexSetWithIndex:column]];
}
- (void)_setEditingState:(BOOL)editingState forView:(CPView)aView
@@ -5348,9 +5352,12 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
if (context === "editing" && [object superview] === self)
{
[object removeObserver:self forKeyPath:keyPath];
[self _commitDataViewObjectValue:object];
_editingRow = CPNotFound;
_editingColumn = CPNotFound;
var row,
column;
[self getColumn:@ref(column) row:@ref(row) forView:object];
[self _commitDataViewObjectValue:object forColumn:column andRow:row];
}
}
@@ -5752,10 +5759,10 @@ Your delegate can implement this method to avoid subclassing the tableview to ad
@ignore
Call the delegate didDragTableColumn with the given tableColumn
*/
- (void)_sendDelegateDidDragTableColumn:(CPInteger)column
- (void)_sendDelegateDidDragTableColumn:(CPTableColumn)aTableColumn
{
if (_implementedDelegateMethods & CPTableViewDelegate_tableView_didDragTableColumn_)
[_delegate tableView:self didDragTableColumn:_tableColumns[column]];
[_delegate tableView:self didDragTableColumn:aTableColumn];
}
/*!
@@ -6111,7 +6118,6 @@ var CPTableViewDataSourceKey = @"CPTableViewDataSourceKey",
CPTableViewGridStyleMaskKey = @"CPTableViewGridStyleMaskKey",
CPTableViewUsesAlternatingBackgroundKey = @"CPTableViewUsesAlternatingBackgroundKey",
CPTableViewAlternatingRowColorsKey = @"CPTableViewAlternatingRowColorsKey",
CPTableViewHeaderViewKey = @"CPTableViewHeaderViewKey",
CPTableViewCornerViewKey = @"CPTableViewCornerViewKey",
CPTableViewAutosaveNameKey = @"CPTableViewAutosaveNameKey",
CPTableViewArchivedReusableViewsKey = @"CPTableViewArchivedReusableViewsKey";
+313 -5
View File
@@ -5,6 +5,13 @@
* Created by Alexander Ljungberg.
* Copyright 2010, WireLoad, LLC.
*
* additions from
*
* Daniel Boehringer on 8/02/2014.
* Copyright Daniel Boehringer on 8/02/2014.
*
*
*
* 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
@@ -20,6 +27,30 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/Foundation.j>
@import "CPPasteboard.j"
@import "CPView.j"
@global CPStringPboardType
@global _CPSmartPboardType
@class CPAttributedString
@class _CPRTFParser
@protocol CPTextDelegate <CPObject>
@optional
- (BOOL)textShouldBeginEditing:(CPText)aTextObject;
- (BOOL)textShouldEndEditing:(CPText)aTextObject;
- (void)textDidBeginEditing:(CPNotification)aNotification;
- (void)textDidChange:(CPNotification)aNotification;
- (void)textDidEndEditing:(CPNotification)aNotification;
@end
CPParagraphSeparatorCharacter = 0x2029;
CPLineSeparatorCharacter = 0x2028;
CPEnterCharacter = "\u0003";
CPBackspaceCharacter = "\u0008";
CPTabCharacter = "\u0009";
@@ -29,6 +60,7 @@ CPCarriageReturnCharacter = "\u000d";
CPBackTabCharacter = "\u0019";
CPDeleteCharacter = "\u007f";
@typedef CPTextMovement
CPIllegalTextMovement = 0;
CPOtherTextMovement = 0;
CPReturnTextMovement = 16;
@@ -46,8 +78,284 @@ CPWritingDirectionLeftToRight = 0;
CPWritingDirectionRightToLeft = 1;
@typedef CPTextAlignment
CPLeftTextAlignment = 0;
CPRightTextAlignment = 1;
CPCenterTextAlignment = 2;
CPJustifiedTextAlignment = 3;
CPNaturalTextAlignment = 4;
CPLeftTextAlignment = 0;
CPRightTextAlignment = 1;
CPCenterTextAlignment = 2;
CPJustifiedTextAlignment = 3;
CPNaturalTextAlignment = 4;
/*
CPText notifications
*/
CPTextDidBeginEditingNotification = @"CPTextDidBeginEditingNotification";
CPTextDidChangeNotification = @"CPTextDidChangeNotification";
CPTextDidEndEditingNotification = @"CPTextDidEndEditingNotification";
/*
CPTextView Notifications
*/
CPTextViewDidChangeSelectionNotification = @"CPTextViewDidChangeSelectionNotification";
CPTextViewDidChangeTypingAttributesNotification = @"CPTextViewDidChangeTypingAttributesNotification";
/*
FIXME: move these to CPAttributed string
Make use of attributed keys in AppKit
*/
CPFontAttributeName = @"CPFontAttributeName";
CPForegroundColorAttributeName = @"CPForegroundColorAttributeName";
CPBackgroundColorAttributeName = @"CPBackgroundColorAttributeName";
CPShadowAttributeName = @"CPShadowAttributeName";
CPUnderlineStyleAttributeName = @"CPUnderlineStyleAttributeName";
CPSuperscriptAttributeName = @"CPSuperscriptAttributeName";
CPBaselineOffsetAttributeName = @"CPBaselineOffsetAttributeName";
CPAttachmentAttributeName = @"CPAttachmentAttributeName";
CPLigatureAttributeName = @"CPLigatureAttributeName";
CPKernAttributeName = @"CPKernAttributeName";
@implementation CPText : CPView
{
BOOL _isEditable @accessors(getter=isEditable, setter=setEditable:);
BOOL _isSelectable @accessors(getter=isSelectable, setter=setSelectable:);
BOOL _isRichText @accessors(getter=isRichText, setter=setRichText:);
}
- (void)setSelectable:(BOOL)flag
{
[self willChangeValueForKey:@"selectable"];
_isSelectable = flag;
[self didChangeValueForKey:@"selectable"];
if (!flag)
[self setEditable:flag];
}
- (void)setEditable:(BOOL)flag
{
[self willChangeValueForKey:@"editable"];
_isEditable = flag;
[self didChangeValueForKey:@"editable"];
if (flag)
[self setSelectable:flag];
}
- (void)changeFont:(id)sender
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
}
- (void)copy:(id)sender
{
var selectedRange = [self selectedRange];
if (selectedRange.length < 1)
return;
var pasteboard = [CPPasteboard generalPasteboard];
// put plain representation on the pasteboad unconditionally
[pasteboard declareTypes:[CPStringPboardType] owner:nil];
[pasteboard setString:[[self stringValue] substringWithRange:selectedRange] forType:CPStringPboardType];
}
- (id)_plainStringForPasting
{
return [[CPPasteboard generalPasteboard] stringForType:CPStringPboardType];
}
- (id)_stringForPasting
{
var pasteboard = [CPPasteboard generalPasteboard],
dataForPasting = [pasteboard stringForType:CPRTFPboardType],
stringForPasting = [pasteboard stringForType:CPStringPboardType];
if (dataForPasting || [stringForPasting hasPrefix:"{\\rtf1\\ansi"])
stringForPasting = [[_CPRTFParser new] parseRTF:dataForPasting ? dataForPasting : stringForPasting];
if (![self isRichText] && [stringForPasting isKindOfClass:[CPAttributedString class]])
stringForPasting = stringForPasting._string;
return stringForPasting;
}
- (BOOL)_shouldUseSmartPasting
{
return parseInt([[CPPasteboard generalPasteboard] stringForType:_CPSmartPboardType], 10) > 0 || NO;
}
- (void)paste:(id)sender
{
var stringForPasting = [self _stringForPasting];
if (stringForPasting)
[self insertText:stringForPasting];
}
- (void)copyFont:(id)sender
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
}
- (void)delete:(id)sender
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
}
- (CPFont)font:(CPFont)aFont
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
return nil;
}
- (BOOL)isHorizontallyResizable
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
return NO;
}
- (BOOL)isRulerVisible
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
return NO;
}
- (BOOL)isVerticallyResizable
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
return NO;
}
- (CGSize)maxSize
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
return CGSizeMake(0,0);
}
- (CGSize)minSize
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
return CGSizeMake(0,0);
}
- (void)pasteFont:(id)sender
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
}
- (void)replaceCharactersInRange:(CPRange)aRange withString:(CPString)aString
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
}
- (void)scrollRangeToVisible:(CPRange)aRange
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
}
- (void)selectedAll:(id)sender
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
}
- (CPRange)selectedRange
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
return CPMakeRange(CPNotFound, 0);
}
- (void)setFont:(CPFont)aFont
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
}
- (void)setFont:(CPFont)aFont range:(CPRange)aRange
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
}
- (void)setHorizontallyResizable:(BOOL)flag
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
}
- (void)setMaxSize:(CGSize)aSize
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
}
- (void)setMinSize:(CGSize)aSize
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
}
- (void)setString:(CPString)aString
{
[self replaceCharactersInRange:CPMakeRange(0, [[self string] length]) withString:aString];
}
- (void)setUsesFontPanel:(BOOL)flag
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
}
- (void)setVerticallyResizable:(BOOL)flag
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
}
- (CPString)string
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
return nil;
}
- (void)underline:(id)sender
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
}
- (BOOL)usesFontPanel
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
return NO;
}
@end
var CPTextViewIsEditableKey = @"CPTextViewIsEditableKey",
CPTextViewIsSelectableKey = @"CPTextViewIsSelectableKey",
CPTextViewIsRichTextKey = @"CPTextViewIsRichTextKey";
@implementation CPText (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
[self setSelectable:[aCoder decodeBoolForKey:CPTextViewIsSelectableKey]];
[self setEditable:[aCoder decodeBoolForKey:CPTextViewIsEditableKey]];
[self setRichText:[aCoder decodeBoolForKey:CPTextViewIsRichTextKey]];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeBool:_isEditable forKey:CPTextViewIsEditableKey];
[aCoder encodeBool:_isSelectable forKey:CPTextViewIsSelectableKey];
[aCoder encodeBool:_isRichText forKey:CPTextViewIsRichTextKey];
}
@end
+69 -55
View File
@@ -77,26 +77,16 @@ function CPTextFieldBlurFunction(anEvent, owner, domElement, inputElement, resig
var ownerWindow = [owner window];
if (!resigning && [ownerWindow isKeyWindow])
if (!resigning && [ownerWindow isKeyWindow] && [ownerWindow firstResponder] === owner)
{
/*
Browsers blur text fields when a click occurs anywhere outside the text field. That is normal for browsers, but in Cocoa the key view retains focus unless the click target accepts first responder. So if we lost focus but were not told to resign and our window is still key, restore focus,
but only if the text field is completely within the browser window. If we restore focus when it
is off screen, the entire body scrolls out of our control.
Previously we had code here which would force the input to regain focus if the input lost focus without the CPTextField having actually lost first responder status. This typically happened because the user clicked away from the input in the browser, without clicking on something that could become the first responder. In the browser, clicking outside of an input blurs it, but in Cocoa and Cappuccino it does not (unless you actually click something that will become the first responder).
That refocusing code has now been removed because we simply prevent the default action on clicks in the browser instead, which combined with the fix in 58d5d7d7, successfully prevents unintentional focus loss in (at least) Safari 9.1.1, Chrome 51 and Safari for iOS 9.3 when you click outside of a text field.
Now we can still lose focus unexpectedly: this is when the 'done' button is tapped on the virtual keyboard of a mobile device. In this case we actually do want to resign first responder status, because that is what the done button should do (and if we did not the keyboard would go away and then immediately come back which looks dumb and isn't what the user wanted).
*/
if ([owner _isWithinUsablePlatformRect])
{
[[CPRunLoop mainRunLoop] performBlock:function()
{
// This will prevent to jump to the focused element
var previousScrollingOrigin = [owner _scrollToVisibleRectAndReturnPreviousOrigin];
inputElement.focus();
[owner _restorePreviousScrollingOrigin:previousScrollingOrigin];
}
argument:nil order:0 modes:[CPDefaultRunLoopMode]];
}
[ownerWindow makeFirstResponder:nil];
}
CPTextFieldHandleBlur(anEvent, @ref(owner));
@@ -341,7 +331,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
[CPTextFieldInputOwner keyUp:cappEvent];
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
}
};
CPTextFieldDOMPasswordInputElement.oninput = CPTextFieldInputFunction;
CPTextFieldDOMPasswordInputElement.onblur = CPTextFieldBlurHandler;
@@ -403,7 +393,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
else
[self unsetThemeState:CPThemeStateEditable];
// We only allow first responder status if the field is enable, and editable or selectable.
// We only allow first responder status if the field is enabled, and editable or selectable.
if (!(shouldBeEditable && ![self isSelectable]) && [[self window] firstResponder] === self)
[[self window] makeFirstResponder:nil];
@@ -411,6 +401,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
[self setThemeState:CPThemeStateEditable];
else
[self unsetThemeState:CPThemeStateEditable];
[self updateTrackingAreas];
}
/*!
@@ -432,6 +424,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
// We only allow first responder status if the field is enabled.
if (!shouldBeEnabled && [[self window] firstResponder] === self)
[[self window] makeFirstResponder:nil];
[self updateTrackingAreas];
}
/*!
@@ -441,6 +435,8 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
- (void)setSelectable:(BOOL)aFlag
{
_isSelectable = aFlag;
[self updateTrackingAreas];
}
/*!
@@ -839,7 +835,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
[self _resignFirstKeyResponder];
_isEditing = NO;
if ([self isEditable])
{
[self textDidEndEditing:[CPNotification notificationWithName:CPControlTextDidEndEditingNotification object:self userInfo:@{"CPTextMovement": [self _currentTextMovement]}]];
@@ -877,12 +873,18 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
if (!CPTextFieldInputDidBlur)
CPTextFieldBlurHandler();
CPTextFieldInputDidBlur = NO;
CPTextFieldInputResigning = NO;
if (element.parentNode == _DOMElement)
element.parentNode.removeChild(element);
// Previosly, we unflagged CPTextFieldInputDidBlur and CPTextFieldInputResigning before
// the call to removeChild. This resulted in DOM exceptions in Chrome under certain conditions.
// See https://stackoverflow.com/questions/21926083/failed-to-execute-removechild-on-node
// for why we need to unflag CPTextFieldInputDidBlur and CPTextFieldInputResigning
// only after removing the element.
CPTextFieldInputDidBlur = NO;
CPTextFieldInputResigning = NO;
CPTextFieldInputIsActive = NO;
if (document.attachEvent)
@@ -999,14 +1001,11 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
[self textDidChange:[CPNotification notificationWithName:CPControlTextDidChangeNotification object:self userInfo:nil]];
}
- (void)mouseMoved:(CPEvent)anEvent
{
[super mouseMoved:anEvent];
[self _updateCursorForEvent:anEvent];
}
- (void)mouseDown:(CPEvent)anEvent
{
if (![self isEnabled])
return [[self nextResponder] mouseDown:anEvent];
// Don't track! (ever?)
if ([self isEditable] && [self isEnabled])
{
@@ -1041,7 +1040,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
[[self window] platformWindow]._DOMBodyElement.ondrag = CPTextFieldCachedDragFunction;
[[self window] platformWindow]._DOMBodyElement.onselectstart = CPTextFieldCachedSelectStartFunction;
CPTextFieldCachedSelectStartFunction = nil
CPTextFieldCachedSelectStartFunction = nil;
CPTextFieldCachedDragFunction = nil;
}
@@ -1244,7 +1243,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
return;
if (_implementedDelegateMethods & CPTextFieldDelegate_controlTextDidBeginEditing_)
[_delegate controlTextDidBeginEditing:[[CPNotification alloc] initWithName:CPControlTextDidBeginEditingNotification object:self userInfo:@{"CPFieldEditor": [note object]}]]
[_delegate controlTextDidBeginEditing:[[CPNotification alloc] initWithName:CPControlTextDidBeginEditingNotification object:self userInfo:@{"CPFieldEditor": [note object]}]];
[super textDidBeginEditing:note];
}
@@ -1261,27 +1260,6 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
[_delegate controlTextDidEndEditing:note];
}
- (void)_updateCursorForEvent:(CPEvent)anEvent
{
var frame = CGRectMakeCopy([self frame]),
contentInset = [self currentValueForThemeAttribute:@"content-inset"];
frame = [[self superview] convertRectToBase:CGRectInsetByInset(frame, contentInset)];
if ([self isEnabled] && ([self isSelectable] || [self isEditable]) && CGRectContainsPoint(frame, [anEvent locationInWindow]))
{
#if PLATFORM(DOM)
self._DOMElement.style.cursor = "text";
#endif
}
else
{
#if PLATFORM(DOM)
self._DOMElement.style.cursor = "default";
#endif
}
}
/*!
Returns the string in the text field.
*/
@@ -1812,7 +1790,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
_implementedDelegateMethods = 0;
if ([_delegate respondsToSelector:@selector(control:didFailToFormatString:errorDescription:)])
_implementedDelegateMethods |= CPTextFieldDelegate_control_didFailToFormatString_errorDescription_
_implementedDelegateMethods |= CPTextFieldDelegate_control_didFailToFormatString_errorDescription_;
if ([_delegate respondsToSelector:@selector(controlTextDidBeginEditing:)])
_implementedDelegateMethods |= CPTextFieldDelegate_controlTextDidBeginEditing_;
@@ -2015,7 +1993,7 @@ CPTextFieldStatePlaceholder = CPThemeState("placeholder");
frame.origin = [wind convertBaseToGlobal:frame.origin];
// Here we restore the the previous scrolling posiition
// Here we restore the previous scrolling posiition
[self _restorePreviousScrollingOrigin:previousScrollingOrigin];
return (CGRectGetMinX(frame) >= CGRectGetMinX(usableRect) &&
@@ -2202,4 +2180,40 @@ var CPTextFieldIsEditableKey = "CPTextFieldIsEditableKey",
[_source setObjectValue:aValue];
}
@end
@end
@implementation CPTextField (CPTrackingArea)
{
CPTrackingArea _textFieldTrackingArea;
}
- (void)updateTrackingAreas
{
if (_textFieldTrackingArea)
{
[self removeTrackingArea:_textFieldTrackingArea];
_textFieldTrackingArea = nil;
}
if ([self isEnabled] && (_isEditable || _isSelectable))
{
var myBounds = CGRectMakeCopy([self bounds]),
contentInset = [self currentValueForThemeAttribute:@"content-inset"];
_textFieldTrackingArea = [[CPTrackingArea alloc] initWithRect:CGRectInsetByInset(myBounds, contentInset)
options:CPTrackingCursorUpdate | CPTrackingActiveInKeyWindow
owner:self
userInfo:nil];
[self addTrackingArea:_textFieldTrackingArea];
}
[super updateTrackingAreas];
}
- (void)cursorUpdate:(CPEvent)anEvent
{
[[CPCursor IBeamCursor] set];
}
@end
+315
View File
@@ -0,0 +1,315 @@
/*
* CPFontDescriptor.j
* AppKit
*
* Created by Emmanuel Maillard on 07/03/10.
* Copyright Emmanuel Maillard 2010.
*
* 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>
/*
Font descriptor dictionary keys
*/
/*
CPFontNameAttribute contains a CPString that specified the font name
(may be an name list like: 'Marker Felt, Lucida Grande, Helvetica')
*/
CPFontNameAttribute = @"CPFontNameAttribute";
/*
CPFontSizeAttribute contains a CPString that specified the font size
(as a float value)
*/
CPFontSizeAttribute = @"CPFontSizeAttribute";
/*
CPFontTraitsAttribute a CPDictionary that contains font traits keys
(CPFontSymbolicTrait or CPFontWeightTrait)
*/
CPFontTraitsAttribute = @"CPFontTraitsAttribute";
// Font traits dictionary keys
/*
CPFontSymbolicTrait a CPNumber that contains CPFontFamilyClass and
typeface information flags.
*/
CPFontSymbolicTrait = @"CPFontSymbolicTrait";
/*
CPFontWeightTrait
We use CPString with CSS string values for font weight
(normal | bold | bolder | lighter | 100 | 200 | 300 | 400
| 500 | 600 | 700 | 800 | 900)
NOTE: Cocoa compatibility issue: NSFontWeightTrait are NSNumber for
font weight (from -1.0 to 1.0, 0.0 for normal weight).
*/
CPFontWeightTrait = @"CPFontWeightTrait";
/*
CPFontFamilyClass
*/
CPFontUnknownClass = 0 << 28;
CPFontOldStyleSerifsClass = 1 << 28;
CPFontTransitionalSerifsClass = 2 << 28;
CPFontModernSerifsClass = 3 << 28;
CPFontClarendonSerifsClass = 4 << 28;
CPFontSlabSerifsClass = 5 << 28;
CPFontFreeformSerifsClass = 7 << 28;
CPFontSansSerifClass = 8 << 28;
CPFontSerifClass = (CPFontOldStyleSerifsClass | CPFontTransitionalSerifsClass |
CPFontModernSerifsClass | CPFontClarendonSerifsClass |
CPFontSlabSerifsClass | CPFontFreeformSerifsClass);
CPFontFamilyClassMask = 0xF0000000;
/*
Typeface information
*/
CPFontItalicTrait = 1 << 0;
CPFontBoldTrait = 1 << 1;
CPFontExpandedTrait = 1 << 5; /* TODO: CCS 3 font-stretch */
CPFontCondensedTrait = 1 << 6;
CPFontSmallCapsTrait = 1 << 7;
/*!
@ingroup appkit
@class CPFontDescriptor
*/
@implementation CPFontDescriptor : CPObject
{
CPDictionary _attributes;
}
/*!
Returns a font descriptor with the specified attributes.
@param attributes a dictionary that describe the desired font descriptor
@return the requested font descriptor
*/
+ (CPFontDescriptor)fontDescriptorWithFontAttributes:(CPDictionary)attributes
{
return [[CPFontDescriptor alloc] initWithFontAttributes:attributes];
}
/*!
Returns a font descriptor with the specified name and size.
@param fontName the name of the font
@param aSize the size of the font (in points)
@return the requested font descriptor
*/
+ (CPFontDescriptor)fontDescriptorWithName:(CPString)fontName size:(float)size
{
return [[CPFontDescriptor alloc] initWithFontAttributes:[CPDictionary dictionaryWithObjects:[fontName, [CPString stringWithString:size + '']] forKeys:[CPFontNameAttribute,CPFontSizeAttribute]]];
}
/*!
Initialize a font descriptor with the specified attributes.
@param attributes a dictionary that describe the desired font descriptor
@return the requested font descriptor
*/
- (id)initWithFontAttributes:(CPDictionary)attributes
{
if (self = [super init])
{
_attributes = [[CPMutableDictionary alloc] init];
if (attributes)
[_attributes addEntriesFromDictionary:attributes];
}
return self;
}
/*!
Returns a new font descriptor that is the same as the receiver but with the
specified attributes taking precedence over the existing ones.
@param attributes a dictionary that describe the desired font descriptor
@return the new font descriptor
*/
- (CPFontDescriptor)fontDescriptorByAddingAttributes:(CPDictionary)attributes
{
var attrib = [_attributes copy];
[attrib addEntriesFromDictionary:attributes];
return [[CPFontDescriptor alloc] initWithFontAttributes:attrib];
}
/*!
Returns a new font descriptor that is the same as the receiver but with the specified size taking precedence over the existing ones.
@param aSize the new size
@return the new font descriptor
*/
- (CPFontDescriptor)fontDescriptorWithSize:(float)aSize
{
var attrib = [_attributes copy];
[attrib setObject:[CPString stringWithString:aSize + ''] forKey:CPFontSizeAttribute];
return [[CPFontDescriptor alloc] initWithFontAttributes:attrib];
}
/*!
Returns a new font descriptor that is the same as the receiver but with
the specified symbolic traits taking precedence over the existing ones.
@param symbolicTraits the desired new symbolic traits
@return the new font descriptor
*/
- (CPFontDescriptor)fontDescriptorWithSymbolicTraits:(CPFontSymbolicTraits)symbolicTraits
{
var attrib = [_attributes copy];
if ([attrib objectForKey:CPFontTraitsAttribute])
[[attrib objectForKey:CPFontTraitsAttribute] setObject:[CPNumber numberWithUnsignedInt:symbolicTraits]
forKey:CPFontSymbolicTrait];
else
[attrib setObject:[CPDictionary dictionaryWithObject:[CPNumber numberWithUnsignedInt:symbolicTraits]
forKey:CPFontSymbolicTrait] forKey:CPFontTraitsAttribute];
return [[CPFontDescriptor alloc] initWithFontAttributes:attrib];
}
- (id)objectForKey:(id)aKey
{
return [_attributes objectForKey:aKey];
}
- (CPDictionary)fontAttributes
{
return _attributes;
}
- (float)pointSize
{
var value = [_attributes objectForKey:CPFontSizeAttribute];
return value ? [value floatValue] : 0.0;
}
- (CPFontSymbolicTraits)symbolicTraits
{
var traits = [_attributes objectForKey:CPFontTraitsAttribute];
return (traits && [traits objectForKey:CPFontSymbolicTrait]) ? [[traits objectForKey:CPFontSymbolicTrait] unsignedIntValue] : 0;
}
@end
var CPFontDescriptorAttributesKey = @"CPFontDescriptorAttributesKey";
@implementation CPFontDescriptor (CPCoding)
/*!
Initializes the font descriptor from a coder.
@param aCoder the coder from which to read the font descriptor data
@return the initialized font
*/
- (id)initWithCoder:(CPCoder)aCoder
{
return [self initWithFontAttributes:[aCoder decodeObjectForKey:CPFontDescriptorAttributesKey]];
}
/*!
Writes the font descriptor to a coder.
@param aCoder the coder to which the data will be written
*/
- (void)encodeWithCoder:(CPCoder)aCoder
{
[aCoder encodeObject:_attributes forKey:CPFontDescriptorAttributesKey];
}
@end
var _wrapNameRegEx = new RegExp(/(\w+\s+\w+)(,*)/g);
/*
Helper methods to CPFont for generating CSS font style
*/
@implementation CPFontDescriptor (CPFontCSSHelper)
- (CPString)fontStyleCSSString
{
return [self symbolicTraits] & CPFontItalicTrait ? @"italic" : @"normal";
}
- (CPString)fontWeightCSSString
{
var traitsAttributes = [_attributes objectForKey:CPFontTraitsAttribute];
if (traitsAttributes)
{
/* give preference to CPFontWeightTrait */
if ([traitsAttributes objectForKey:CPFontWeightTrait])
return [traitsAttributes objectForKey:CPFontWeightTrait];
/* else fallback to facetype symbolic traits */
if ([self symbolicTraits] & CPFontBoldTrait)
return @"bold";
}
return @"normal";
}
- (CPString)fontSizeCSSString
{
return [_attributes objectForKey:CPFontSizeAttribute] ? [[_attributes objectForKey:CPFontSizeAttribute] intValue] + "px" : @"";
}
- (CPString)fontFamilyCSSString
{
var aName = @"";
if ([_attributes objectForKey:CPFontNameAttribute])
aName += [_attributes objectForKey:CPFontNameAttribute].replace(_wrapNameRegEx, '"$1"$2');
var symbolicTraits = [self symbolicTraits];
if (symbolicTraits)
{
if ((symbolicTraits & CPFontFamilyClassMask) & CPFontSansSerifClass)
aName += @", sans-serif";
else if ((symbolicTraits & CPFontFamilyClassMask) & CPFontSerifClass)
aName += @", serif";
}
return aName;
}
- (CPString)fontVariantCSSString
{
if ([self symbolicTraits] & CPFontSmallCapsTrait)
return @"small-caps";
return @"normal";
}
- (CPString)cssString
{
return [CPString stringWithString:[self fontStyleCSSString] + " "
+ [self fontVariantCSSString] + " "
+ [self fontWeightCSSString] + " "
+ [self fontSizeCSSString] + " "
+ [self fontFamilyCSSString]];
}
@end
+443
View File
@@ -0,0 +1,443 @@
/*
* CPFontPanel.j
* AppKit
*
* TODOs:
* 1. make browser-width for size smaller and fix columns
* 2. add all the missing features from the MacOS X counterpart (sampleview)
*
*
* Created by Daniel Boehringer on 2/JAN/2014.
* All modifications copyright Daniel Boehringer 2013.
* Extensive code formatting and review by Andrew Hankinson
* Based on original work by
* Created by Emmanuel Maillard on 06/03/2010.
* Copyright Emmanuel Maillard 2010.
*
* 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"
@import "CPColorWell.j"
@import "CPColorPanel.j"
@import "CPBrowser.j"
@import "CPText.j"
@import "CPFontManager.j"
@class CPTextStorage
@class CPLayoutManager
@class CPTextContainer
@class CPFontManager
/*
Collection indexes
*/
var kTypefaceIndex_Normal = 0,
kTypefaceIndex_Italic = 1,
kTypefaceIndex_Bold = 2,
kTypefaceIndex_BoldItalic = 3,
kToolbarHeight = 32,
kBorderSpacing = 6,
kInnerSpacing = 2,
kNothingChanged = 0,
kFontNameChanged = 1,
kTypefaceChanged = 2,
kSizeChanged = 3,
kTextColorChanged = 4,
kBackgroundColorChanged = 5,
kUnderlineChanged = 6,
kWeightChanged = 7,
_sharedFontPanel;
// FIXME<!> Locale support
var _availableTraits= [@"Normal", @"Italic", @"Bold", @"Bold Italic"],
_availableSizes = [@"9", @"10", @"11", @"12", @"13", @"14", @"18", @"24", @"36", @"48", @"72", @"96"];
/*!
@ingroup appkit
@class CPFontPanel
*/
@implementation CPFontPanel : CPPanel
{
id _fontBrowser;
id _traitBrowser;
id _sizeBrowser;
CPArray _availableFonts;
id _textColorWell;
CPColor _textColor;
int _currentColorButtonTag;
BOOL _setupDone;
int _fontChanges;
}
#pragma mark -
#pragma mark Class methods
/*!
Check if the shared Font panel exists.
*/
+ (BOOL)sharedFontPanelExists
{
return _sharedFontPanel !== nil;
}
/*!
Return the shared Font panel.
*/
+ (CPFontPanel)sharedFontPanel
{
if (!_sharedFontPanel)
_sharedFontPanel = [[CPFontPanel alloc] init];
return _sharedFontPanel;
}
#pragma mark -
#pragma mark Init methods
/*! @ignore */
- (id)init
{
if (self = [super initWithContentRect:CGRectMake(100, 90, 450, 394) styleMask:(CPTitledWindowMask | CPClosableWindowMask /*| CPResizableWindowMask*/ )])
{
[[self contentView] setBackgroundColor:[CPColor colorWithWhite:0.95 alpha:1.0]];
[self setTitle:@"Font Panel"];
[self setLevel:CPFloatingWindowLevel];
[self setFloatingPanel:YES];
[self setBecomesKeyOnlyIfNeeded:YES];
[self setMinSize:CGSizeMake(378, 394)];
_availableFonts = [[CPFontManager sharedFontManager] availableFonts];
_textColor = [CPColor blackColor];
_setupDone = NO;
_fontChanges = kNothingChanged;
}
return self;
}
/*! @ignore */
- (void)_setupToolbarView
{
_toolbarView = [[CPView alloc] initWithFrame:CGRectMake(0, kBorderSpacing, CGRectGetWidth([self frame]), kToolbarHeight)];
[_toolbarView setAutoresizingMask:CPViewWidthSizable];
// Text color
_textColorWell = [[CPColorWell alloc] initWithFrame:CGRectMake(10, 0, 25, 25)];
[_textColorWell setColor:_textColor];
[_toolbarView addSubview:_textColorWell];
}
- (void)_setupBrowser:(CPBrowser)aBrowser
{
[aBrowser setTarget:self];
[aBrowser setAction:@selector(browserClicked:)];
[aBrowser setDoubleAction:@selector(dblClicked:)];
[aBrowser setAllowsEmptySelection:NO];
[aBrowser setAllowsMultipleSelection:NO];
[aBrowser setDelegate:self];
[[self contentView] addSubview:aBrowser];
}
- (void)_setupContents
{
if (_setupDone)
return;
_setupDone = YES;
[self _setupToolbarView];
var contentView = [self contentView],
label = [CPTextField labelWithTitle:@"Font name"],
contentBounds = [contentView bounds],
upperView = [[CPView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(contentBounds), CGRectGetHeight(contentBounds) - (kBorderSpacing + kToolbarHeight + kInnerSpacing))];
[contentView addSubview:_toolbarView];
_fontBrowser = [[CPBrowser alloc] initWithFrame:CGRectMake(10, 35, 150, 350)];
_traitBrowser = [[CPBrowser alloc] initWithFrame:CGRectMake(155, 35, 150, 350)];
_sizeBrowser = [[CPBrowser alloc] initWithFrame:CGRectMake(300, 35, 140, 350)];
[self _setupBrowser:_fontBrowser];
[self _setupBrowser:_traitBrowser];
[self _setupBrowser:_sizeBrowser];
[[CPNotificationCenter defaultCenter] addObserver:self
selector:@selector(textViewDidChangeSelection:)
name:CPTextViewDidChangeSelectionNotification
object:nil];
}
- (void)textViewDidChangeSelection:(CPNotification)notification
{
[self _refreshWithTextView:[notification object]];
}
- (void)_refreshWithTextView:(CPTextView)textView
{
if (![self isVisible])
return;
var attribs = [textView _attributesForFontPanel],
font = [attribs objectForKey:CPFontAttributeName] || [[textView textStorage] font] || [CPFont systemFontOfSize:12.0],
color = [attribs objectForKey:CPForegroundColorAttributeName];
if (!font)
return;
var trait = kTypefaceIndex_Normal;
if ([font isItalic] && [font isBold])
trait = kTypefaceIndex_BoldItalic;
else if ([font isItalic])
trait = kTypefaceIndex_Italic;
else if ([font isBold])
trait = kTypefaceIndex_Bold;
[self setCurrentFont:font];
[self setCurrentTrait:trait];
[self setCurrentSize:[font size] + ""]; //cast to string
if (!color)
return;
[_textColorWell setColor:color];
}
- (void)orderFront:(id)sender
{
[self _setupContents];
[super orderFront:sender];
[self _refreshWithTextView:[[CPApp keyWindow] firstResponder]];
}
- (void)reloadDefaultFontFamilies
{
_availableFonts = [[CPFontManager sharedFontManager] availableFonts];
}
- (BOOL)worksWhenModal
{
return YES;
}
/*!
@param aFont the font to convert.
@return The converted font or \c aFont if failed to convert.
*/
- (CPFont)panelConvertFont:(CPFont)aFont
{
var newFont = aFont,
index = 0;
switch (_fontChanges)
{
case kFontNameChanged:
newFont = [CPFont fontWithDescriptor:[[aFont fontDescriptor] fontDescriptorByAddingAttributes:
[CPDictionary dictionaryWithObject:[self currentFont] forKey:CPFontNameAttribute]] size:0.0];
break;
case kTypefaceChanged:
index = [self currentTrait];
if (index == kTypefaceIndex_BoldItalic)
newFont = [[CPFontManager sharedFontManager] convertFont:aFont toHaveTrait:CPBoldFontMask | CPItalicFontMask];
else if (index == kTypefaceIndex_Bold)
newFont = [[CPFontManager sharedFontManager] convertFont:aFont toHaveTrait:CPBoldFontMask];
else if (index == kTypefaceIndex_Italic)
newFont = [[CPFontManager sharedFontManager] convertFont:aFont toHaveTrait:CPItalicFontMask];
else
newFont = [[CPFontManager sharedFontManager] convertFont:aFont toNotHaveTrait:CPBoldFontMask | CPItalicFontMask];
break;
case kSizeChanged:
newFont = [[CPFontManager sharedFontManager] convertFont:aFont toSize:[self currentSize]];
break;
case kNothingChanged:
break;
default:
CPLog.trace(@"FIXME: -[" + [self className] + " " + _cmd + "] unhandled _fontChanges: " + _fontChanges);
break;
}
return newFont;
}
- (void)setCurrentSize:(CGSize)aSize
{
[_sizeBrowser selectRow:[_availableSizes indexOfObject:aSize] inColumn:0];
}
- (CPString)currentSize
{
return [_sizeBrowser selectedItem];
}
- (void)setCurrentFont:(CPFont)aFont
{
[_fontBrowser selectRow:[_availableFonts indexOfObject:[aFont familyName]] inColumn:0];
}
- (CPString)currentFont
{
return [_fontBrowser selectedItem];
}
- (void)setCurrentTrait:(unsigned)aTrait
{
var row = 0;
switch (aTrait)
{
case kTypefaceIndex_Italic:
row = 1;
break;
case kTypefaceIndex_Bold:
row = 2;
break;
case kTypefaceIndex_BoldItalic:
row = 3;
break;
}
[_traitBrowser selectRow:row inColumn:0];
}
// FIXME<!> Locale support
- (unsigned)currentTrait
{
var sel = [_traitBrowser selectedItem];
if (sel === "Italic")
return kTypefaceIndex_Italic;
if (sel === "Bold")
return kTypefaceIndex_Bold;
if (sel === "Bold Italic")
return kTypefaceIndex_BoldItalic;
return kTypefaceIndex_Normal;
}
/*!
Set the selected font in Font panel.
@param font the selected font
@param flag if \c the current selection have multiple fonts.
*/
- (void)setPanelFont:(CPFont)font isMultiple:(BOOL)flag
{
[self _setupContents];
if ([self currentFont] !== [font familyName])
[self setCurrentFont:[font familyName]];
if ([self currentSize] != [font size])
[self setCurrentSize:[font size]];
var typefaceIndex = kTypefaceIndex_Normal,
symbolicTraits = [[font fontDescriptor] symbolicTraits];
if ((symbolicTraits & CPFontItalicTrait) && (symbolicTraits & CPFontBoldTrait))
typefaceIndex = kTypefaceIndex_BoldItalic;
else if (symbolicTraits & CPFontItalicTrait)
typefaceIndex = kTypefaceIndex_Italic;
else if (symbolicTraits & CPFontBoldTrait)
typefaceIndex = kTypefaceIndex_Bold;
if ([self currentTrait] != typefaceIndex)
[self setCurrentTrait:typefaceIndex ];
_fontChanges = kNothingChanged;
}
- (void)changeColor:(id)sender
{
_textColor = [sender color];
_fontChanges = kTextColorChanged;
[[CPFontManager sharedFontManager] modifyFontViaPanel:self];
}
////////////////////////////////////////////////////////////////////
// TODO: ask CPFontManager for traits //
- (void)browserClicked:(id)aBrowser
{
if (aBrowser === _fontBrowser)
{
_fontChanges = kFontNameChanged;
[[CPFontManager sharedFontManager] modifyFontViaPanel:self];
}
else if (aBrowser === _traitBrowser)
{
_fontChanges = kTypefaceChanged;
[[CPFontManager sharedFontManager] modifyFontViaPanel:self];
}
else if (aBrowser === _sizeBrowser)
{
_fontChanges = kSizeChanged;
[[CPFontManager sharedFontManager] modifyFontViaPanel:self];
}
}
- (void)dblClicked:(id)sender
{
// alert("DOUBLE");
}
- (id)browser:(id)aBrowser numberOfChildrenOfItem:(id)anItem
{
if (aBrowser === _fontBrowser)
return [_availableFonts count];
if (aBrowser === _traitBrowser)
return [_availableTraits count];
return [_availableSizes count]
}
- (id)browser:(id)aBrowser child:(int)index ofItem:(id)anItem
{
if (aBrowser === _fontBrowser)
return [_availableFonts objectAtIndex:index];
if (aBrowser === _traitBrowser)
return [_availableTraits objectAtIndex:index];
return [_availableSizes objectAtIndex:index];
}
- (id)browser:(id)aBrowser objectValueForItem:(id)anItem
{
return anItem;
}
- (BOOL)browser:(id)aBrowser isLeafItem:(id)anItem
{
return YES;
}
@end
[CPFontManager setFontPanelFactory:[CPFontPanel class]];
File diff suppressed because it is too large Load Diff
+223
View File
@@ -0,0 +1,223 @@
/*
* CPParagraphStyle.j
* AppKit
*
* FIXME
* This is basically a stub.
* We need to store all the spacing informations as well as writing direction (among others)
*
* Created by Daniel Boehringer on 11/01/2014
* Copyright Daniel Boehringer 2014.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPObject.j>
@import <Foundation/CPArray.j>
@import "CPText.j"
CPLeftTabStopType = 0;
CPParagraphStyleAttributeName = @"CPParagraphStyleAttributeName";
var _sharedDefaultParagraphStyle,
_defaultTabStopArray;
@implementation CPParagraphStyle : CPObject
{
CPArray _tabStops @accessors(property=tabStops);
CPTextAlignment _alignment @accessors(property=alignment);
unsigned _firstLineHeadIndent @accessors(property=firstLineHeadIndent);
unsigned _headIndent @accessors(property=headIndent);
unsigned _tailIndent @accessors(property=tailIndent);
unsigned _paragraphSpacing @accessors(property=paragraphSpacing);
unsigned _minimumLineHeight @accessors(property=minimumLineHeight);
unsigned _maximumLineHeight @accessors(property=maximumLineHeight);
unsigned _lineSpacing @accessors(property=lineSpacing);
}
#pragma mark -
#pragma mark Class methods
+ (CPParagraphStyle)defaultParagraphStyle
{
if (!_sharedDefaultParagraphStyle)
_sharedDefaultParagraphStyle = [self new];
return _sharedDefaultParagraphStyle;
}
+ (CPArray)_defaultTabStops
{
if (!_defaultTabStopArray)
{
var i;
_defaultTabStopArray = [];
// <!> FIXME: Define constants for these magic numbers: 13, 28
for (i = 1; i < 16 ; i++)
{
_defaultTabStopArray.push([[CPTextTab alloc] initWithType:CPLeftTabStopType location:i * 28]);
}
}
return _defaultTabStopArray;
}
#pragma mark -
#pragma mark Init methods
- (id)init
{
[self _initWithDefaults];
return self;
}
- (CPParagraphStyle)initWithParagraphStyle:(CPParagraphStyle)other
{
self = [super init];
_tabStops = [other._tabStops copy];
_alignment = other._alignment;
_firstLineHeadIndent = other._firstLineHeadIndent;
_headIndent = other._headIndent;
_tailIndent = other._tailIndent;
_paragraphSpacing = other._paragraphSpacing;
_minimumLineHeight = other._minimumLineHeight;
_maximumLineHeight = other._maximumLineHeight;
_lineSpacing = other._lineSpacing;
return self;
}
- (void)_initWithDefaults
{
_alignment = CPLeftTextAlignment;
_tabStops = [[[self class] _defaultTabStops] copy];
}
- (void)addTabStop:(CPTextTab)aStop
{
_tabStops.push(aStop);
}
- (id)copy
{
var other = [[self class] alloc];
return [other initWithParagraphStyle:self];
}
@end
var CPParagraphStyleTabStopsKey = @"CPParagraphStyleTabStopsKey",
CPParagraphStyleAlignmentKey = @"CPParagraphStyleAlignmentKey",
CPParagraphStyleFirstLineHeadIndentKey = @"CPParagraphStyleFirstLineHeadIndentKey",
CPParagraphStyleHeadIndentKey = @"CPParagraphStyleHeadIndentKey",
CPParagraphStyleTailIndentKey = @"CPParagraphStyleTailIndentKey",
CPParagraphStyleParagraphSpacingKey = @"CPParagraphStyleParagraphSpacingKey",
CPParagraphStyleMinimumLineHeightKey = @"CPParagraphStyleMinimumLineHeightKey",
CPParagraphStyleMaximumLineHeightKey = @"CPParagraphStyleMaximumLineHeightKey",
CPParagraphStyleLineSpacingKey = @"CPParagraphStyleLineSpacingKey";
@implementation CPParagraphStyle (CPCoding)
- (id)initWithCoder:(id)aCoder
{
self = [self init];
if (self)
{
_tabStops = [aCoder decodeObjectForKey:"CPParagraphStyleTabStopsKey"];
_alignment = [aCoder decodeIntForKey:"CPParagraphStyleAlignmentKey"];
_firstLineHeadIndent = [aCoder decodeIntForKey:"CPParagraphStyleFirstLineHeadIndentKey"];
_headIndent = [aCoder decodeIntForKey:"CPParagraphStyleHeadIndentKey"];
_tailIndent = [aCoder decodeIntForKey:"CPParagraphStyleTailIndentKey"];
_paragraphSpacing = [aCoder decodeIntForKey:"CPParagraphStyleParagraphSpacingKey"];
_minimumLineHeight = [aCoder decodeIntForKey:"CPParagraphStyleMinimumLineHeightKey"];
_maximumLineHeight = [aCoder decodeIntForKey:"CPParagraphStyleMaximumLineHeightKey"];
_lineSpacing = [aCoder decodeIntForKey:"CPParagraphStyleLineSpacingKey"];
}
return self;
}
- (void)encodeWithCoder:(id)aCoder
{
[aCoder encodeInt:_alignment forKey:"CPParagraphStyleAlignmentKey"];
[aCoder encodeObject:_tabStops forKey:"CPParagraphStyleTabStopsKey"];
[aCoder encodeInt:_firstLineHeadIndent forKey:"CPParagraphStyleFirstLineHeadIndentKey"];
[aCoder encodeInt:_headIndent forKey:"CPParagraphStyleHeadIndentKey"];
[aCoder encodeInt:_tailIndent forKey:"CPParagraphStyleTailIndentKey"];
[aCoder encodeInt:_paragraphSpacing forKey:"CPParagraphStyleParagraphSpacingKey"];
[aCoder encodeInt:_minimumLineHeight forKey:"CPParagraphStyleMinimumLineHeightKey"];
[aCoder encodeInt:_maximumLineHeight forKey:"CPParagraphStyleMaximumLineHeightKey"];
[aCoder encodeInt:_lineSpacing forKey:"CPParagraphStyleLineSpacingKey"];
}
@end
@implementation CPTextTab : CPObject
{
int _type @accessors(property = tabStopType);
double _location @accessors(property = location);
}
- (id)initWithType:(CPTabStopType) aType location:(double) aLocation
{
if ([self = [super init]])
{
_type = aType;
_location = aLocation;
}
return self;
}
@end
var CPTextTabTypeKey = @"CPTextTabTypeKey",
CPTextTabLocationKey = @"CPTextTabLocationKey";
@implementation CPTextTab (CPCoding)
- (id)initWithCoder:(id)aCoder
{
self = [self init];
if (self)
{
_type = [aCoder decodeIntForKey:"CPTextTabTypeKey"];
_location = [aCoder decodeDoubleForKey:"CPTextTabLocationKey"];
}
return self;
}
- (void)encodeWithCoder:(id)aCoder
{
[aCoder encodeInt:_type forKey:"CPTextTabTypeKey"];
[aCoder encodeDouble:_location forKey:"CPTextTabLocationKey"];
}
@end
+252
View File
@@ -0,0 +1,252 @@
/*
* CPTextContainer.j
* AppKit
*
* Created by Emmanuel Maillard on 27/02/2010.
* Copyright Emmanuel Maillard 2010.
*
* 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/CPGeometry.j>
@import "CPLayoutManager.j"
@class CPTextView
@class CPLayoutManager
/*
@global
@group CPLineSweepDirection
*/
CPLineSweepLeft = 0;
/*
@global
@group CPLineSweepDirection
*/
CPLineSweepRight = 1;
/*
@global
@group CPLineSweepDirection
*/
CPLineSweepDown = 2;
/*
@global
@group CPLineSweepDirection
*/
CPLineSweepUp = 3;
/*
@global
@group CPLineMovementDirection
*/
CPLineDoesntMoves = 0;
/*
@global
@group CPLineMovementDirection
*/
CPLineMovesLeft = 1;
/*
@global
@group CPLineMovementDirection
*/
CPLineMovesRight = 2;
/*
@global
@group CPLineMovementDirection
*/
CPLineMovesDown = 3;
/*
@global
@group CPLineMovementDirection
*/
CPLineMovesUp = 4;
/*!
@ingroup appkit
@class CPTextContainer
*/
@implementation CPTextContainer : CPObject
{
float _lineFragmentPadding @accessors(property=lineFragmentPadding);
CGSize _size @accessors(property=containerSize);
CPLayoutManager _layoutManager @accessors(property=layoutManager);
CPTextView _textView @accessors(property=textView);
BOOL _inResizing;
}
#pragma mark -
#pragma mark Init methods
- (id)initWithContainerSize:(CGSize)aSize
{
self = [super init];
if (self)
{
_size = aSize;
[self _init];
}
return self;
}
- (id)init
{
return [self initWithContainerSize:CPMakeSize(1e7, 1e7)];
}
- (void)_init
{
_lineFragmentPadding = 0.0;
_layoutManager = [[CPLayoutManager alloc] init];
[_layoutManager addTextContainer:self];
}
#pragma mark -
#pragma mark Setter methods
- (void)setContainerSize:(CGSize)someSize
{
var oldSize = _size;
_size = CGSizeMakeCopy(someSize);
if (oldSize.width != _size.width)
{
_inResizing = YES;
[_layoutManager invalidateLayoutForCharacterRange:CPMakeRange(0, [[_layoutManager textStorage] length])
isSoft:NO
actualCharacterRange:NULL];
[_layoutManager _validateLayoutAndGlyphs];
[_textView sizeToFit]; // this is necessary to adopt the height of CPTextView in case of rewrapping
_inResizing = NO;
}
}
// Controls whether the receiver adjusts the width of its bounding rectangle when its text view is resized.
- (void)setWidthTracksTextView:(BOOL)flag
{
[_textView setPostsFrameChangedNotifications:flag];
if (flag)
{
[[CPNotificationCenter defaultCenter] addObserver:self
selector:@selector(textViewFrameChanged:)
name:CPViewFrameDidChangeNotification
object:_textView];
}
else
{
[[CPNotificationCenter defaultCenter] removeObserver:self
name:CPViewFrameDidChangeNotification
object:_textView];
}
}
- (void)textViewFrameChanged:(CPNotification)aNotification
{
var newSize = CGSizeMake([_textView frame].size.width, _size.height);
[self setContainerSize:newSize];
}
- (void)setTextView:(CPTextView)aTextView
{
if (_textView)
[_textView setTextContainer:nil];
_textView = aTextView;
if (_textView)
[_textView setTextContainer:self];
[_layoutManager textContainerChangedTextView:self];
}
- (BOOL)containsPoint:(CGPoint)aPoint
{
return CGRectContainsPoint(CGRectMake(0, 0, _size.width, _size.height), aPoint);
}
- (BOOL)isSimpleRectangularTextContainer
{
return YES;
}
- (CGRect)lineFragmentRectForProposedRect:(CGRect)proposedRect
sweepDirection:(CPLineSweepDirection)sweep
movementDirection:(CPLineMovementDirection)movement
remainingRect:(CGRectPointer)remainingRect
{
var resultRect = CGRectCreateCopy(proposedRect);
if (sweep != CPLineSweepRight || movement != CPLineMovesDown)
{
CPLog.trace(@"FIXME: unsupported sweep (" + sweep + ") or movement (" + movement + ")");
return CGRectMakeZero();
}
if (resultRect.origin.x + resultRect.size.width > _size.width)
resultRect.size.width = _size.width - resultRect.origin.x;
if (resultRect.size.width < 0)
resultRect = CGRectMakeZero();
if (remainingRect)
{
remainingRect.origin.x = resultRect.origin.x + resultRect.size.width;
remainingRect.origin.y = resultRect.origin.y;
remainingRect.size.height = resultRect.size.height;
remainingRect.size.width = _size.width - (resultRect.origin.x + resultRect.size.width);
}
return resultRect;
}
@end
var CPTextContainerSizeKey = @"CPTextContainerSizeKey",
CPTextContainerLayoutManagerKey = @"CPTextContainerLayoutManagerKey";
@implementation CPTextContainer (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super init];
if (self)
{
[self _init];
_size = [aCoder decodeSizeForKey:CPTextContainerSizeKey];
_layoutManager = [aCoder decodeObjectForKey:CPTextContainerLayoutManagerKey];
[_layoutManager addTextContainer:self];
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[aCoder encodeSize:_size forKey:CPTextContainerSizeKey];
[aCoder encodeObject:_layoutManager forKey:CPTextContainerLayoutManagerKey];
}
@end
+303
View File
@@ -0,0 +1,303 @@
/*
* CPTextStorage.j
* AppKit
*
* Created by Emmanuel Maillard on 27/02/2010.
* Copyright Emmanuel Maillard 2010.
*
* 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/CPNotificationCenter.j>
@import <Foundation/CPAttributedString.j>
@import "CPText.j"
@import "CPFont.j"
@class CPLayoutManager;
CPTextStorageEditedAttributes = 1;
CPTextStorageEditedCharacters = 2;
CPTextStorageWillProcessEditingNotification = @"CPTextStorageWillProcessEditingNotification";
CPTextStorageDidProcessEditingNotification = @"CPTextStorageDidProcessEditingNotification";
@protocol CPTextStorageDelegate <CPObject>
- (void)textStorageWillProcessEditing:(CPNotification)aNotification;
- (void)textStorageDidProcessEditing:(CPNotification)aNotification;
@end
var CPTextStorageDelegate_textStorageWillProcessEditing_ = 1 << 1,
CPTextStorageDelegate_textStorageDidProcessEditing_ = 1 << 2;
/*!
@ingroup appkit
@class CPTextStorage
*/
@implementation CPTextStorage : CPMutableAttributedString
{
CPColor _foregroundColor @accessors(property=foregroundColor);
CPFont _font @accessors(property=font);
CPMutableArray _layoutManagers @accessors(getter=layoutManagers);
CPRange _editedRange @accessors(getter=editedRange);
id <CPTextStorageDelegate> _delegate @accessors(property=delegate);
int _changeInLength @accessors(property=changeInLength);
unsigned _editedMask @accessors(property=editedMask);
int _editCount; // {begin,end}Editing counter
unsigned _implementedDelegateMethods;
}
#pragma mark -
#pragma mark Init methods
- (id)initWithString:(CPString)aString attributes:(CPDictionary)attributes
{
self = [super initWithString:aString attributes:attributes];
if (self)
{
_layoutManagers = [[CPMutableArray alloc] init];
_editedRange = CPMakeRange(CPNotFound, 0);
_changeInLength = 0;
_editedMask = 0;
}
return self;
}
- (id)initWithString:(CPString)aString
{
return [self initWithString:aString attributes:nil];
}
- (id)init
{
return [self initWithString:@"" attributes:nil];
}
#pragma mark -
#pragma mark Delegate methods
- (void)setDelegate:(id <CPTextStorageDelegate>)aDelegate
{
if (_delegate === aDelegate)
return;
_implementedDelegateMethods = 0;
_delegate = aDelegate;
if (_delegate)
{
if ([_delegate respondsToSelector:@selector(textStorageWillProcessEditing:)])
_implementedDelegateMethods |= CPTextStorageDelegate_textStorageWillProcessEditing_;
if ([_delegate respondsToSelector:@selector(textStorageDidProcessEditing:)])
_implementedDelegateMethods |= CPTextStorageDelegate_textStorageDidProcessEditing_;
}
}
#pragma mark -
#pragma mark Layout manager methods
- (void)addLayoutManager:(CPLayoutManager)aManager
{
if ([_layoutManagers containsObject:aManager])
return
[aManager setTextStorage:self];
[_layoutManagers addObject:aManager];
}
- (void)removeLayoutManager:(CPLayoutManager)aManager
{
if (![_layoutManagers containsObject:aManager])
return
[aManager setTextStorage:nil];
[_layoutManagers removeObject:aManager];
}
- (void)invalidateAttributesInRange:(CPRange)aRange
{
/* FIXME: stub */
}
#pragma mark -
#pragma mark Editing methods
- (void)processEditing
{
[self _sendDelegateWillProcessEditingNotification];
[self invalidateAttributesInRange:[self editedRange]];
[self _sendDelegateDidProcessEditingNotification];
var c = [_layoutManagers count];
for (var i = 0; i < c; i++)
{
[[_layoutManagers objectAtIndex:i] textStorage:self
edited:_editedMask
range:_editedRange
changeInLength:_changeInLength
invalidatedRange:_editedRange];
}
_editedRange.location = CPNotFound;
_editedMask = 0;
_changeInLength = 0;
}
- (void)beginEditing
{
if (_editCount == 0)
_editedRange = CPMakeRange(CPNotFound, 0);
_editCount++;
}
- (void)endEditing
{
_editCount--;
if (_editCount == 0)
[self processEditing];
}
- (void)edited:(unsigned)editedMask range:(CPRange)aRange changeInLength:(int)lengthChange
{
var copyRange = CPMakeRangeCopy(aRange);
if (_editCount == 0) // used outside a beginEditing/endEditing
{
_editedMask = editedMask;
_changeInLength = lengthChange;
copyRange.length += lengthChange;
_editedRange = copyRange;
[self processEditing];
}
else
{
_editedMask |= editedMask;
_changeInLength += lengthChange;
copyRange.length += lengthChange;
if (_editedRange.location == CPNotFound)
_editedRange = copyRange;
else
_editedRange = CPUnionRange(_editedRange,copyRange);
}
}
- (void)removeAttribute:(CPString)anAttribute range:(CPRange)aRange
{
[self beginEditing];
[super removeAttribute:anAttribute range:aRange];
[self edited:CPTextStorageEditedAttributes range:aRange changeInLength:0];
[self endEditing];
}
- (void)addAttributes:(CPDictionary)aDictionary range:(CPRange)aRange
{
[self beginEditing];
[super addAttributes:aDictionary range:aRange];
[self edited:CPTextStorageEditedAttributes range:aRange changeInLength:0];
[self endEditing];
}
- (void)deleteCharactersInRange:(CPRange)aRange
{
[self beginEditing];
[super deleteCharactersInRange:aRange];
[self edited:CPTextStorageEditedCharacters range:aRange changeInLength:-aRange.length];
[self endEditing];
}
- (void)replaceCharactersInRange:(CPRange)aRange withString:(CPString)aString
{
[self beginEditing];
[super replaceCharactersInRange:aRange withString:aString];
[self edited:CPTextStorageEditedCharacters range:aRange changeInLength:([aString length] - aRange.length)];
[self endEditing];
}
- (void)replaceCharactersInRange:(CPRange)aRange withAttributedString:(CPAttributedString)aString
{
[self beginEditing];
[super replaceCharactersInRange:aRange withAttributedString:aString];
[self edited:(CPTextStorageEditedAttributes | CPTextStorageEditedCharacters) range:aRange changeInLength:([aString length] - aRange.length)];
[self endEditing];
}
- (CPAttributedString)attributedSubstringFromRange:(CPRange)aRange
{
if (!aRange.length)
return [CPAttributedString new];
return [super attributedSubstringFromRange:aRange];
}
@end
@implementation CPTextStorage (CPTextStorageDelegate)
- (void)_sendDelegateWillProcessEditingNotification
{
if (_implementedDelegateMethods & CPTextStorageDelegate_textStorageWillProcessEditing_)
[_delegate textStorageWillProcessEditing:[[CPNotification alloc] initWithName:CPTextStorageWillProcessEditingNotification object:self userInfo:nil]];
[[CPNotificationCenter defaultCenter] postNotificationName:CPTextStorageWillProcessEditingNotification object:self];
}
- (void)_sendDelegateDidProcessEditingNotification
{
if (_implementedDelegateMethods & CPTextStorageDelegate_textStorageDidProcessEditing_)
[_delegate textStorageWillProcessEditing:[[CPNotification alloc] initWithName:CPTextStorageDidProcessEditingNotification object:self userInfo:nil]];
[[CPNotificationCenter defaultCenter] postNotificationName:CPTextStorageDidProcessEditingNotification object:self];
}
@end
@implementation CPTextStorage (CPCoding)
- (id)initWithCoder:(CPCoder)aCoder
{
self = [super initWithCoder:aCoder];
if (self)
{
}
return self;
}
- (void)encodeWithCoder:(CPCoder)aCoder
{
[super encodeWithCoder:aCoder];
}
@end
File diff suppressed because it is too large Load Diff
+429
View File
@@ -0,0 +1,429 @@
/*
* CPTypesetter.j
* AppKit
*
* Created by Daniel Boehringer on 27/12/2013.
* All modifications copyright Daniel Boehringer 2013.
* Extensive code formatting and review by Andrew Hankinson
* Based on original work by
* Emmanuel Maillard on 27/02/2010.
* Copyright Emmanuel Maillard 2010.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@import <Foundation/CPObject.j>
@import "CPParagraphStyle.j"
@import "CPTextStorage.j"
@import "CPFont.j"
// forward declare these classes for type matching
@class CPLayoutManager
@class CPTextContainer
@class CPTextView
/*
CPTypesetterControlCharacterAction
*/
CPTypesetterZeroAdvancementAction = 1 << 0;
CPTypesetterWhitespaceAction = 1 << 1;
CPSTypesetterHorizontalTabAction = 1 << 2;
CPTypesetterLineBreakAction = 1 << 3;
CPTypesetterParagraphBreakAction = 1 << 4;
CPTypesetterContainerBreakAction = 1 << 5;
var CPSystemTypesetterFactory,
_sharedSimpleTypesetter;
@implementation CPTypesetter : CPObject
#pragma mark -
#pragma mark Class methods
+ (void)initialize
{
[CPTypesetter _setSystemTypesetterFactory:[CPSimpleTypesetter class]];
}
+ (id)sharedSystemTypesetter
{
return [CPSystemTypesetterFactory sharedInstance];
}
+ (void)_setSystemTypesetterFactory:(Class)aClass
{
CPSystemTypesetterFactory = aClass;
}
- (CPTypesetterControlCharacterAction)actionForControlCharacterAtIndex:(unsigned)charIndex
{
return CPTypesetterZeroAdvancementAction;
}
- (CPLayoutManager)layoutManager
{
return nil;
}
- (CPTextContainer)currentTextContainer
{
return nil;
}
- (CPArray)textContainers
{
return nil;
}
- (void)layoutGlyphsInLayoutManager:(CPLayoutManager)layoutManager
startingAtGlyphIndex:(unsigned)startGlyphIndex
maxNumberOfLineFragments:(unsigned)maxNumLines
nextGlyphIndex:(UIntegerReference)nextGlyph
{
_CPRaiseInvalidAbstractInvocation(self, _cmd);
}
@end
@implementation CPSimpleTypesetter : CPTypesetter
{
CPLayoutManager _layoutManager @accessors(property=layoutManager);
CPTextContainer _currentTextContainer @accessors(property=currentTextContainer);
CPTextStorage _textStorage;
CPRange _attributesRange;
CPDictionary _currentAttributes;
CPParagraphStyle _currentParagraph;
float _lineHeight;
float _lineBase;
float _lineWidth;
unsigned _indexOfCurrentContainer;
CPArray _lineFragments;
}
#pragma mark -
#pragma mark Class methods
+ (id)sharedInstance
{
if (!_sharedSimpleTypesetter)
_sharedSimpleTypesetter = [[CPSimpleTypesetter alloc] init];
return _sharedSimpleTypesetter;
}
- (CPArray)textContainers
{
return [_layoutManager textContainers];
}
- (CPTextTab)textTabForWidth:(double)aWidth writingDirection:(CPWritingDirection)direction
{
var tabStops = [_currentParagraph tabStops];
if (!tabStops)
tabStops = [CPParagraphStyle _defaultTabStops];
var l = tabStops.length;
if (aWidth > tabStops[l - 1]._location)
return nil;
for (var i = l - 1; i >= 0; i--)
{
if (aWidth > tabStops[i]._location)
{
if (i + 1 < l)
return tabStops[i + 1];
}
}
if (i === -1)
return tabStops[0];
return nil;
}
- (BOOL)_flushRange:(CPRange)lineRange
lineOrigin:(CGPoint)lineOrigin
currentContainer:(CPTextContainer)aContainer
advancements:(CPArray)advancements
lineCount:(unsigned)lineCount
sameLine:(BOOL)sameLine
{
var myX = 0,
rect = CGRectMake(lineOrigin.x, lineOrigin.y, _lineWidth, _lineHeight),
containerSize = aContainer._size;
[_layoutManager _appendNewLineFragmentInTextContainer:_currentTextContainer forGlyphRange:lineRange];
var fragment = [_layoutManager._lineFragments lastObject];
fragment._isLast = !sameLine;
_lineFragments.push(fragment);
[_layoutManager setLineFragmentRect:rect forGlyphRange:lineRange usedRect:rect];
switch ([_currentParagraph alignment])
{
case CPLeftTextAlignment:
myX = 0;
break;
case CPCenterTextAlignment:
myX = (containerSize.width - _lineWidth) / 2;
break;
case CPRightTextAlignment:
myX = containerSize.width - _lineWidth;
break;
}
[_layoutManager setLocation:CGPointMake(myX, _lineBase) forStartOfGlyphRange:lineRange];
[_layoutManager _setAdvancements:advancements forGlyphRange:lineRange];
if (!sameLine) //fix the _lineFragments when fontsizes differ
{
var l = _lineFragments.length;
for (var i = 0 ; i < l ; i++)
[_lineFragments[i] _adjustForHeight:_lineHeight];
}
if (!lineCount) // do not rescue on first line
return NO;
if (aContainer._inResizing)
return NO;
return ([_layoutManager _rescuingInvalidFragmentsWasPossibleForGlyphRange:lineRange]);
}
- (void)layoutGlyphsInLayoutManager:(CPLayoutManager)layoutManager
startingAtGlyphIndex:(unsigned)glyphIndex
maxNumberOfLineFragments:(unsigned)maxNumLines
nextGlyphIndex:(UIntegerReference)nextGlyph
{
var textContainers = [layoutManager textContainers],
textContainersCount = [textContainers count];
_layoutManager = layoutManager;
_textStorage = [_layoutManager textStorage];
_indexOfCurrentContainer = MAX(0, [textContainers
indexOfObject:[_layoutManager textContainerForGlyphAtIndex:glyphIndex effectiveRange:nil withoutAdditionalLayout:YES]
inRange:CPMakeRange(0, textContainersCount)]);
_currentTextContainer = textContainers[_indexOfCurrentContainer];
_attributesRange = CPMakeRange(0, 0);
_lineHeight = 0;
_lineBase = 0;
_lineWidth = 0;
var containerSize = [_currentTextContainer containerSize],
containerSizeWidth = containerSize.width,
containerSizeHeight = containerSize.height,
lineRange = CPMakeRange(glyphIndex, 0),
wrapRange = CPMakeRange(0, 0),
wrapWidth = 0,
isNewline = NO,
isTabStop = NO,
isWordWrapped = NO,
numberOfGlyphs= [_textStorage length],
leading,
numLines = 0,
theString = [_textStorage string],
lineOrigin,
ascent,
descent,
advancements = [],
prevRangeWidth = 0,
measuringRange = CPMakeRange(glyphIndex, 0),
currentAnchor = 0,
currentFont,
currentFontLineHeight,
previousFont,
currentParagraphMinimumLineHeight,
currentParagraphMaximumLineHeight,
currentParagraphLineSpacing;
if (glyphIndex > 0)
lineOrigin = CGPointCreateCopy([_layoutManager lineFragmentRectForGlyphAtIndex:glyphIndex effectiveRange:nil].origin);
else if ([_layoutManager extraLineFragmentTextContainer])
lineOrigin = CGPointMake(0, [_layoutManager extraLineFragmentUsedRect].origin.y);
else
lineOrigin = CGPointMake(0, 0);
[_layoutManager _removeInvalidLineFragments];
if (![_textStorage length])
return;
_lineFragments = [];
for (; numLines != maxNumLines && glyphIndex < numberOfGlyphs; glyphIndex++)
{
// check whether there any change in the attributes from here on
if (!CPLocationInRange(glyphIndex, _attributesRange))
{
_currentAttributes = [_textStorage attributesAtIndex:glyphIndex effectiveRange:_attributesRange];
currentFont = [_currentAttributes objectForKey:CPFontAttributeName];
_currentParagraph = [_currentAttributes objectForKey:CPParagraphStyleAttributeName] || [CPParagraphStyle defaultParagraphStyle];
currentParagraphMinimumLineHeight = [_currentParagraph minimumLineHeight];
currentParagraphMaximumLineHeight = [_currentParagraph maximumLineHeight];
currentParagraphLineSpacing = [_currentParagraph lineSpacing];
if (!currentFont)
currentFont = [_textStorage font] || [CPFont systemFontOfSize:12.0];
ascent = [currentFont ascender];
descent = [currentFont descender];
leading = (ascent - descent) * 0.2; // FAKE leading
currentFontLineHeight = ascent - descent + leading;
if (previousFont !== currentFont)
{
measuringRange = CPMakeRange(glyphIndex, 0);
currentAnchor = prevRangeWidth;
previousFont = currentFont;
}
}
if (currentFontLineHeight > _lineHeight)
_lineHeight = currentFontLineHeight;
if (ascent > _lineBase)
_lineBase = ascent;
lineRange.length++;
measuringRange.length++;
var currentCharCode = theString.charCodeAt(glyphIndex), // use pure javascript methods for performance reasons
rangeWidth = [theString.substr(measuringRange.location, measuringRange.length) _sizeWithFont:currentFont inWidth:NULL].width + currentAnchor;
switch (currentCharCode) // faster than sending actionForControlCharacterAtIndex: called for each char.
{
case 9: // '\t'
{
var nextTab = [self textTabForWidth:rangeWidth + lineOrigin.x writingDirection:0];
isTabStop = YES;
if (nextTab)
rangeWidth = nextTab._location - lineOrigin.x;
else
rangeWidth += 28; //FIXME
} // fallthrough intentional
case 32: // ' '
wrapRange = CPMakeRangeCopy(lineRange);
wrapWidth = rangeWidth;
wrapRange._height = _lineHeight;
wrapRange._base = _lineBase;
break;
case 10:
case 13:
isNewline = YES;
}
advancements.push({width: rangeWidth - prevRangeWidth, height: ascent, descent: descent});
prevRangeWidth = _lineWidth = rangeWidth;
if (lineOrigin.x + rangeWidth > containerSizeWidth)
{
if (wrapWidth)
{
lineRange = wrapRange;
_lineWidth = wrapWidth;
_lineHeight = wrapRange._height;
_lineBase = wrapRange._base;
}
isNewline = YES;
isWordWrapped = YES;
glyphIndex = CPMaxRange(lineRange) - 1; // start the line starts directly at current character
}
if (isNewline || isTabStop)
{
if ([self _flushRange:lineRange lineOrigin:lineOrigin currentContainer:_currentTextContainer advancements:advancements lineCount:numLines sameLine:!isNewline])
return;
if (isTabStop)
{
lineOrigin.x += rangeWidth;
isTabStop = NO;
}
if (isNewline)
{
if (currentParagraphMinimumLineHeight && currentParagraphMinimumLineHeight > _lineHeight)
_lineHeight = currentParagraphMinimumLineHeight;
if (currentParagraphMaximumLineHeight && currentParagraphMaximumLineHeight < _lineHeight)
_lineHeight = currentParagraphMaximumLineHeight;
lineOrigin.y += _lineHeight;
if (currentParagraphLineSpacing)
lineOrigin.y += currentParagraphLineSpacing;
if (lineOrigin.y > containerSizeHeight && _indexOfCurrentContainer < textContainersCount - 1)
{
_currentTextContainer = textContainers[++_indexOfCurrentContainer];
containerSize = [_currentTextContainer containerSize];
containerSizeWidth = containerSize.width;
containerSizeHeight = containerSize.height;
}
lineOrigin.x = 0;
numLines++;
isNewline = NO;
_lineFragments = [];
_lineHeight = 0;
_lineBase = ascent;
}
_lineWidth = 0;
advancements = [];
currentAnchor = 0;
prevRangeWidth = 0;
lineRange = CPMakeRange(glyphIndex + 1, 0);
measuringRange = CPMakeRange(glyphIndex + 1, 0);
wrapRange = CPMakeRange(0, 0);
wrapWidth = 0;
isWordWrapped = NO;
}
}
// this is to "flush" the remaining characters
if (lineRange.length)
{
[self _flushRange:lineRange lineOrigin:lineOrigin currentContainer:_currentTextContainer advancements:advancements lineCount:numLines sameLine:NO];
}
var rect = CGRectMake(0, lineOrigin.y, containerSizeWidth, [_layoutManager._lineFragments lastObject]._usedRect.size.height - descent);
[_layoutManager setExtraLineFragmentRect:rect usedRect:rect textContainer:_currentTextContainer];
}
@end
+793
View File
@@ -0,0 +1,793 @@
/* RTFParser.j
Parse a RTF string into a CPAttributedString
Copyright (C) 2014 Daniel Boehringer
FIXME: this class should be redone using a 'real' parser
* all paragraph spacing information is currently not parsed
* 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/CPAttributedString.j>
@import <Foundation/CPGeometry.j>
@import "CPFontManager.j"
@import "CPParagraphStyle.j"
@global CPLeftTextAlignment
@global CPRightTextAlignment
@global CPCenterTextAlignment
@global CPJustifiedTextAlignment
@global CPNaturalTextAlignment
@global CPFontAttributeName
@global CPForegroundColorAttributeName
var hexTable = [];
// Hold the attributes of the current run
@implementation _RTFAttribute : CPObject
{
CPRange _range;
CPParagraphStyle paragraph;
CPColor fgColour;
CPColor bgColour;
CPColor ulColour;
CPString fontName;
unsigned fontSize;
BOOL bold;
BOOL italic;
BOOL underline;
BOOL strikethrough;
BOOL script;
BOOL _tabChanged;
}
- (id)init
{
if (self = [super init])
{
[self resetFont];
[self resetParagraphStyle];
_range = CPMakeRange(0, 0);
}
return self;
}
- (id)copy
{
var mynew = [_RTFAttribute new];
mynew.paragraph = [paragraph copy];
mynew.fontName = fontName;
mynew.fgColour = fgColour;
mynew.bgColour = bgColour;
mynew.ulColour = ulColour;
return mynew;
}
- (CPFont)currentFont
{
var font = [CPFont _fontWithName:fontName size:fontSize bold:bold italic:italic];
if (font)
return font;
//Before giving up and using a default font, we try if this is
//not the case of a font with a composite name, such as
//'Helvetica-Light'. In that case, even if we don't have
//exactly an 'Helvetica-Light' font family, we might have an
//'Helvetica' one.
var range = [fontName rangeOfString:@"-"];
if (range.location != CPNotFound)
{
var fontFamily = [fontName substringToIndex: range.location];
font = [CPFont fontWithName:fontFamily size:fontSize];
}
/* Last resort, default font. :-( */
if (font == nil)
font = [CPFont systemFontOfSize:fontSize];
return font;
}
- (CPNumber)script
{
return [CPNumber numberWithInt:script];
}
- (CPNumber)underline
{
if (underline != 0)
return [CPNumber numberWithInt:underline];
else
return nil;
}
- (CPNumber)strikethrough
{
if (strikethrough != 0)
return [CPNumber numberWithInt:strikethrough];
else
return nil;
}
- (void)resetParagraphStyle
{
paragraph = [[CPParagraphStyle defaultParagraphStyle] copy];
}
- (void)resetFont
{
var font = [CPFont systemFontOfSize:12];
fontName = [font familyName];
fontSize = 12.0;
italic = NO;
bold = NO;
underline = 0;
strikethrough = 0;
script = 0;
}
- (void)addTab:(float)location type:(CPTextTabType)type
{
var tab = [[CPTextTab alloc] initWithType:CPLeftTabStopType
location:location];
if (!_tabChanged)
{
[paragraph setTabStops:[tab]];
_tabChanged = YES;
}
else
{
[paragraph addTabStop: tab];
}
}
- (CPDictionary)dictionary
{
var ret = @{};
[ret setObject:[self currentFont] forKey:CPFontAttributeName];
[ret setObject:paragraph forKey:CPParagraphStyleAttributeName];
if (fgColour)
[ret setObject:fgColour forKey:CPForegroundColorAttributeName];
return ret;
}
@end
// based on https://github.com/lazygyu/RTF-parser
var kRTFParserType_char = 0,
kRTFParserType_dest = 1,
kRTFParserType_prop = 2,
kRTFParserType_spec = 3;
// Keyword descriptions
var kRgsymRtf = {
// keyword dflt fPassDflt kwd idx
"b" : [ "b", 1, false, kRTFParserType_prop, "propBold"],
"ul" : [ "ul", 1, false, kRTFParserType_prop, "propUnderline"],
"i" : [ "i", 1, false, kRTFParserType_prop, "propItalic"],
"li" : [ "li", 0, false, kRTFParserType_prop, "propPgnFormat"],
"pgnucltr" : [ "pgnucltr", "pgULtr", true, kRTFParserType_prop, "propPgnFormat"],
"pgnlcltr" : [ "pgnlcltr", "pgLLtr", true, kRTFParserType_prop, "propPgnFormat"],
"qc" : [ "qc", "justC", true, kRTFParserType_prop, "propJust"],
"ql" : [ "ql", "justL", true, kRTFParserType_prop, "propJust"],
"qr" : [ "qr", "justR", true, kRTFParserType_prop, "propJust"],
"qj" : [ "qj", "justF", true, kRTFParserType_prop, "propJust"],
"paperw" : [ "paperw", 12240, false, kRTFParserType_prop, "propXaPage"],
"paperh" : [ "paperh", 15480, false, kRTFParserType_prop, "propYaPage"],
"margl" : [ "margl", 1800, false, kRTFParserType_prop, "propXaLeft"],
"margr" : [ "margr", 1800, false, kRTFParserType_prop, "propXaRight"],
"margt" : [ "margt", 1440, false, kRTFParserType_prop, "propYaTop"],
"margb" : [ "margb", 1440, false, kRTFParserType_prop, "propYaBottom"],
"pgnstart" : [ "pgnstart", 1, true, kRTFParserType_prop, "propPgnStart"],
"facingp" : [ "facingp", 1, true, kRTFParserType_prop, "propFacingp"],
"landscape" : [ "landscape",1, true, kRTFParserType_prop, "propLandscape"],
"par" : [ "par", 0, false, kRTFParserType_char, "\n"],
"pard" : [ "pard", 0, false, kRTFParserType_prop, "propDefaultPara"],
"\0x0a" : [ "\0x0a", 0, false, kRTFParserType_char, "\n"],
"\0x0d" : [ "\0x0d", 0, false, kRTFParserType_char, ""],
"tab" : [ "tab", 0, false, kRTFParserType_char, "\t"],
"ldblquote" : [ "ldblquote",0, false, kRTFParserType_char, '"'],
"rdblquote" : [ "rdblquote",0, false, kRTFParserType_char, '"'],
"bin" : [ "bin", 0, false, kRTFParserType_spec, "ipfnBin"],
"*" : [ "*", 0, false, kRTFParserType_spec, "ipfnDestSkip"],
"'" : [ "'", 0, false, kRTFParserType_spec, "ipfnHex"],
"author" : [ "author", 0, false, kRTFParserType_dest, "destSkip"],
"buptim" : [ "buptim", 0, false, kRTFParserType_dest, "destSkip"],
"colortbl" : [ "colortbl", 0, false, kRTFParserType_dest, "destSkip"],
"comment" : [ "comment", 0, false, kRTFParserType_dest, "destSkip"],
"creatim" : [ "creatim", 0, false, kRTFParserType_dest, "destSkip"],
"doccomm" : [ "doccomm", 0, false, kRTFParserType_dest, "destSkip"],
"fonttbl" : [ "fonttbl", 0, false, kRTFParserType_dest, "destSkip"],
"footer" : [ "footer", 0, false, kRTFParserType_dest, "destSkip"],
"footerf" : [ "footerf", 0, false, kRTFParserType_dest, "destSkip"],
"footerl" : [ "footerl", 0, false, kRTFParserType_dest, "destSkip"],
"footerr" : [ "footerr", 0, false, kRTFParserType_dest, "destSkip"],
"footnote" : [ "footnote", 0, false, kRTFParserType_dest, "destSkip"],
"ftncn" : [ "ftncn", 0, false, kRTFParserType_dest, "destSkip"],
"ftnsep" : [ "ftnsep", 0, false, kRTFParserType_dest, "destSkip"],
"ftnsepc" : [ "ftnsepc", 0, false, kRTFParserType_dest, "destSkip"],
"fprq" : [ "fprq", 0, false, kRTFParserType_dest, "destSkip"],
// "fcharset" : [ "fcharset", 0, false, kRTFParserType_dest, "destSkip"],
"rquote" : [ "rquote", 0, false, kRTFParserType_char, "'"],
// "s" : [ "s", 0, false, kRTFParserType_dest, "destSkip"],
"header" : [ "header", 0, false, kRTFParserType_dest, "destSkip"],
"headerf" : [ "headerf", 0, false, kRTFParserType_dest, "destSkip"],
"headerl" : [ "headerl", 0, false, kRTFParserType_dest, "destSkip"],
"headerr" : [ "headerr", 0, false, kRTFParserType_dest, "destSkip"],
"info" : [ "info", 0, false, kRTFParserType_dest, "destSkip"],
"keywords" : [ "keywords", 0, false, kRTFParserType_dest, "destSkip"],
"operator" : [ "operator", 0, false, kRTFParserType_dest, "destSkip"],
"pict" : [ "pict", 0, false, kRTFParserType_dest, "destSkip"],
"printim" : [ "printim", 0, false, kRTFParserType_dest, "destSkip"],
"private1" : [ "private1", 0, false, kRTFParserType_dest, "destSkip"],
"revtim" : [ "revtim", 0, false, kRTFParserType_dest, "destSkip"],
"rxe" : [ "rxe", 0, false, kRTFParserType_dest, "destSkip"],
"stylesheet" : [ "stylesheet",0, false, kRTFParserType_dest, "destSkip"],
"subject" : [ "subject", 0, false, kRTFParserType_dest, "destSkip"],
"tc" : [ "tc", 0, false, kRTFParserType_dest, "destSkip"],
"title" : [ "title", 0, false, kRTFParserType_dest, "destSkip"],
"txe" : [ "txe", 0, false, kRTFParserType_dest, "destSkip"],
"xe" : [ "xe", 0, false, kRTFParserType_dest, "destSkip"],
"[" : [ "[", 0, false, kRTFParserType_char, '['],
" " : [ " ", 0, false, kRTFParserType_char, ' '],
"]" : [ "]", 0, false, kRTFParserType_char, ']'],
"{" : [ "{", 0, false, kRTFParserType_char, '{'],
"}" : [ "}", 0, false, kRTFParserType_char, '}'],
"\\" : [ "\\", 0, false, kRTFParserType_char, '\\']
};
@implementation _CPRTFParser : CPObject
{
CPString _codePage;
CGSize _paper;
CPString _rtf;
unsigned _curState;
CPArray _states;
unsigned _currentParseIndex;
BOOL _hexreturn;
_RTFAttribute _currentRun;
CPAttributedString _result;
CPArray _colorArray;
CPArray _fontArray;
CPString _freename;
BOOL _parsingFontTable;
}
- (id)init
{
if (self = [super init])
{
_paper = CPMakeSize(0, 0);
_rtf = "";
_curState = 0; // 0 = normal, 1 = skip
_states = [];
_currentParseIndex = 0;
_hexreturn = NO;
_result = [CPAttributedString new];
_colorArray = [];
_fontArray = ['Arial']; // FIXME: should be name of system font
_freename = "";
_parsingFontTable = NO;
}
return self;
}
- (CPString)_checkChar:(CPArray)sym parameter:(CPString)ch
{
switch (_curState)
{
case 0:
if (sym && sym[4])
return sym[4];
case 1:
// CPLogConsole("skipped : " + sym[4]);
return '';
default:
if (sym && sym[4])
return sym[4];
}
}
- (BOOL)pushState
{
_states.push["group"];
return YES;
}
- (BOOL)popState
{
_states.pop();
if (_curState > 0)
_curState--;
return YES;
}
- (CPString)_parseSpec:(CPArray)sym parameter:(CPString)v
{
var ch = '';
switch (sym[4])
{
case "ipfnDestSkip":
_curState++;
return '';
case "ipfnHex":
ch = _rtf.charAt(++_currentParseIndex);
var hex = '';
while (new RegExp("[a-fA-F0-9\\']").test(ch))
{
if (ch == "'")
{
_currentParseIndex++;
continue;
}
hex += (ch + '');
ch = _rtf.charAt(++_currentParseIndex);
}
//ch = parseInt(ch, 16);
//console.log("hex : " + hex);
_hexreturn = YES;
_currentParseIndex--;
if (_curState !== 0)
return '';
else
return hex;
break;
case "codePage":
ch = _rtf.charAt(++_currentParseIndex);
var code = '';
while (new RegExp("[0-9]").test(ch))
{
code += (ch + '');
ch = _rtf.charAt(++_currentParseIndex);
}
_codePage = code;
_currentParseIndex--;
break;
}
return '';
}
- (void)_flushCurrentRun
{
var newOffset = 0;
if (_currentRun)
{
if ([_result length] == _currentRun._range.location)
return;
_currentRun._range.length = [_result length] - _currentRun._range.location;
newOffset = CPMaxRange(_currentRun._range);
var dict = [_currentRun dictionary];
[_result setAttributes:dict range:_currentRun._range]; // flush previous run
_currentRun.fgColour = [CPColor blackColor];
}
else
_currentRun = [_RTFAttribute new];
_currentRun._range = CPMakeRange(newOffset, 0); // open a new one
}
- (CPString)_applyPropChange:sym parameter:param
{
//console.log("prop : " + sym[0] + " / param : " + param+ ' ');
switch (sym[0])
{
case "pard":
[self _flushCurrentRun];
break;
case "b": // bold
if (param === 0)
{
if (_currentRun && _currentRun.bold)
[self _flushCurrentRun];
_currentRun.bold = NO
}
else
{
if (_currentRun && !_currentRun.bold)
[self _flushCurrentRun];
_currentRun.bold = YES;
}
break;
case "i": // italic
if (param === 0)
{
if (_currentRun && _currentRun.italic)
[self _flushCurrentRun];
_currentRun.italic = NO
}
else
{
if (_currentRun && !_currentRun.italic)
[self _flushCurrentRun];
_currentRun.italic = YES;
}
break;
case "qc": // paragraph center
[_currentRun.paragraph setAlignment:CPCenterTextAlignment];
break;
case "paperw":
_paper.width = param;
break;
case "paperh":
_paper.height = param;
break;
}
return '';
}
- (CPString)_changeDest:(CPArray)sym
{
switch (sym[0])
{
case "colortbl":
_colorArray.push([CPColor blackColor]);
break;
case "fonttbl":
_parsingFontTable = YES;
break;
}
if (sym[4] == "destSkip")
{
CPLogConsole("Dest skip start : [" + sym[0] + "]");
_curState++;
}
return '';
}
- (CPString)_translateKeyword:(CPString)keyword parameter:(CPString)param fParameter:(BOOL)fParam
{
if (kRgsymRtf[keyword] !== undefined)
{
var sym = kRgsymRtf[keyword];
switch (sym[3])
{
case kRTFParserType_prop:
if (sym[2] || !fParam)
param = sym[1];
return [self _applyPropChange:sym parameter:param];
case kRTFParserType_char:
if((param + '') !== 'NaN' && (param + '') !== 'null' && (param + '').length)
_currentParseIndex -= (param + '').length;
return [self _checkChar:sym parameter:param];
case kRTFParserType_dest:
return [self _changeDest:sym];
case kRTFParserType_spec:
return [self _parseSpec:sym parameter:param];
default:
return '';
}
}
else
{
switch (keyword)
{
case "red":
var oldColor = [_colorArray lastObject],
green = [oldColor greenComponent],
blue = [oldColor blueComponent];
_colorArray.pop();
_colorArray.push([CPColor colorWithRed:parseInt(param) / 255 green:green blue:blue alpha:1.0]);
break;
case "green":
var oldColor = [_colorArray lastObject],
red = [oldColor redComponent],
blue = [oldColor blueComponent];
_colorArray.pop();
_colorArray.push([CPColor colorWithRed:red green: parseInt(param) / 255 blue:blue alpha:1.0]);
break;
case "blue":
var oldColor = [_colorArray lastObject],
green = [oldColor greenComponent],
red = [oldColor redComponent];
_colorArray.pop();
_colorArray.push([CPColor colorWithRed:red green:green blue:parseInt(param) / 255 alpha:1.0]);
_colorArray.push([CPColor blackColor]); // placeholder for next color
break;
case "cf": // change foreground color
[self _flushCurrentRun];
var fontIndex = parseInt(param) - 1;
if (_currentRun && fontIndex >= 0)
_currentRun.fgColour = _colorArray[fontIndex];
break;
case "f": // change font
[self _flushCurrentRun];
var fontIndex = parseInt(param);
if (_currentRun && fontIndex >= 0 && fontIndex < _fontArray.length)
_currentRun.fontName = _fontArray[fontIndex];
break;
case "fs": // change font size
[self _flushCurrentRun];
_currentRun.fontSize = parseInt(param) / 2;
break;
case "tx": // tabstop
var location = parseInt(param) / 20;
if (_currentRun)
[_currentRun addTab:location type:CPLeftTabStopType];
break;
default:
CPLogConsole("skip : " + keyword + " param: " + param);
}
if (_states.length > 0)
_curState = 1;
return '';
}
}
- (CPString)_parseKeyword:(CPString)rtf length:(unsigned)len
{
var ch = '',
fParam = false,
fNeg = false,
keyword = '',
param = '';
_rtf = rtf;
if (++_currentParseIndex >= len)
return len;
ch = rtf.charAt(_currentParseIndex);
if (!/[a-zA-Z]/.test(ch))
return [self _translateKeyword:ch parameter:nil fParameter:fParam];
while (new RegExp("[a-zA-Z]").test(ch))
{
keyword += ch;
ch = rtf.charAt(++_currentParseIndex);
}
if (ch == '-')
{
fNeg = true;
ch = rtf.charAt(++_currentParseIndex);
}
fParam = true;
while (new RegExp("[0-9]").test(ch))
{
param += (ch + '');
ch = rtf.charAt(++_currentParseIndex);
}
_currentParseIndex--;
param = parseInt(param);
if (fNeg)
param *= -1;
return [self _translateKeyword:keyword parameter:param fParameter:fParam];
}
- (void)_appendPlainString:(CPString) aString
{
[_result replaceCharactersInRange:CPMakeRange([_result length], 0) withString:aString];
}
- (CPAttributedString)parseRTF:(CPString)rtf
{
rtf = rtf.replace(/\\\n/g, "\\par\n");
if (rtf.length == 0)
return '';
_currentParseIndex = -1;
var len = rtf.length,
tmp = '',
ch = '',
hex = '',
lastchar = 0;
while (_currentParseIndex < len)
{
tmp = rtf.charAt(++_currentParseIndex);
if (tmp !== "\\" && hex.length > 0)
{
[self _appendPlainString: String.fromCharCode(parseInt((hex), 16))];
hex = '';
}
switch (tmp)
{
case " ":
if (lastchar == 1)
{
lastchar = 0;
}
else
{
_freename += tmp;
[self _appendPlainString:tmp];
}
break;
case "{":
if ([self pushState])
CPLogConsole("push");
break;
case "}":
if ([self popState])
CPLogConsole("pop");
if (_freename)
{
CPLogConsole(_freename);
if (_parsingFontTable)
{
_fontArray.push(_freename);
_parsingFontTable = NO;
}
_freename = "";
}
[self _flushCurrentRun];
break;
case "\\":
_freename = '';
ch = [self _parseKeyword:rtf length:len];
if (!_hexreturn && ch.length == 0)
lastchar = 1;
else
lastchar = 0;
if (_hexreturn)
{
if (ch.length > 0)
{
if (parseInt(ch, 16) & 0x80)
{
hex += ch.toUpperCase();
}
else
{
[self _appendPlainString: String.fromCharCode(parseInt((hex + ch), 16))];
hex = '';
}
if (hex.length == 4)
{
var temp = parseInt(hex, 16);
if (hexTable && hexTable[hex.toUpperCase()] !== undefined)
temp = parseInt(hexTable[hex.toUpperCase()], 16);
[self _appendPlainString: String.fromCharCode(temp)];
hex = '';
}
}
else
{
CPLogConsole("hex skipped");
}
_hexreturn = NO;
}
else if (ch !== undefined && _curState === 0)
{
[self _appendPlainString:ch];
}
break;
case 0x0d:
case 0x0a:
case '\n':
case '\r':
break;
default:
lastchar = 0;
if (_curState == 0)
[self _appendPlainString:tmp];
else if (tmp !== ';')
_freename += tmp;
break;
}
}
return _result;
}
@end
+613
View File
@@ -0,0 +1,613 @@
/*
_CPRTFProducer.j
Serialize CPAttributedString to a RTF String
Copyright (C) 2014 Daniel Boehringer
This file is based on the RTFProducer from GNUStep
(which i co-authored with Fred Kiefer in 1999)
* 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/CPAttributedString.j>
@import "CPParagraphStyle.j"
@import "CPColor.j"
@import "CPGraphics.j"
@import "CPFontManager.j"
@global CPForegroundColorAttributeName
@global CPBackgroundColorAttributeName
@global CPUnderlineStyleAttributeName
@global CPSuperscriptAttributeName
@global CPBaselineOffsetAttributeName
@global CPAttachmentAttributeName
@global CPLigatureAttributeName
@global CPKernAttributeName
@global CPLeftTextAlignment
@global CPRightTextAlignment
@global CPCenterTextAlignment
@global CPJustifiedTextAlignment
@global CPNaturalTextAlignment
var PAPERSIZE = @"PaperSize",
LEFTMARGIN = @"LeftMargin",
RIGHTMARGIN = @"RightMargin",
TOPMARGIN = @"TopMargin",
BUTTOMMARGIN = @"ButtomMargin";
function _points2twips(a) { return (a) * 20.0; }
@implementation _CPRTFProducer : CPObject
{
CPAttributedString text;
CPMutableDictionary fontDict;
CPMutableDictionary colorDict;
CPDictionary docDict;
CPMutableArray attachments;
CPFont currentFont;
CPColor fgColor;
CPColor bgColor;
CPColor ulColor;
}
#pragma mark -
#pragma mark Class methods
+ (CPString)produceRTF:(CPAttributedString)aText documentAttributes:(CPDictionary)dict
{
var mynew = [self new];
return [mynew RTFDStringFromAttributedString:aText documentAttributes:dict];
}
#pragma mark -
#pragma mark init methods
- (id)init
{
if (self = [super init])
{
// maintain a dictionary for the used colours
// (for rtf-header generation)
colorDict = [CPMutableDictionary new];
//maintain a dictionary for the used fonts
//(for rtf-header generation)
fontDict = [CPMutableDictionary new];
fgColor = [CPColor blackColor];
bgColor= [CPColor whiteColor];
}
return self;
}
// private stuff follows
- (CPString)fontTable
{
if (![fontDict count])
return @"";
var fontlistString = "",
fontEnum,
currFont,
keyArray;
keyArray = [fontDict allKeys];
keyArray = [keyArray sortedArrayUsingSelector:@selector(compare:)];
fontEnum = [keyArray objectEnumerator];
while ((currFont = [fontEnum nextObject]) !== nil)
{
var fontFamily,
detail;
if ([currFont isEqualToString:@"Symbol"])
fontFamily = @"tech";
else if ([currFont isEqualToString:@"Helvetica"])
fontFamily = @"swiss";
else if ([currFont isEqualToString:@"Arial"])
fontFamily = @"swiss";
else if ([currFont isEqualToString:@"Courier"])
fontFamily = @"modern";
else if ([currFont isEqualToString:@"Times"])
fontFamily = @"roman";
else fontFamily = @"nil";
detail = [CPString stringWithFormat:@"%@\\f%@ %@;", [fontDict objectForKey:currFont], fontFamily, currFont];
fontlistString += detail;
}
return [CPString stringWithFormat:@"{\\fonttbl%@}\n", fontlistString];
}
- (CPString)colorTable
{
if (![colorDict count])
return @"";
var result,
count = [colorDict count],
list = [CPMutableArray arrayWithCapacity:count],
keyEnum = [colorDict keyEnumerator],
next,
i;
while ((next = [keyEnum nextObject]) !== nil)
{
var cn = [colorDict objectForKey:next];
[list insertObject:[CPColor colorWithCSSString:next] atIndex:[cn intValue]-1];
}
result = [CPString stringWithString:@"{\\colortbl;"];
for (i = 0; i < count; i++)
{
var color = [[list objectAtIndex:i]
colorUsingColorSpaceName:CPCalibratedRGBColorSpace];
result += [CPString stringWithFormat:@"\\red%d\\green%d\\blue%d;",
([color redComponent] * 255),
([color greenComponent] * 255),
([color blueComponent] * 255)];
}
result += @"}\n";
return result;
}
- (CPString)documentAttributes
{
if (!docDict)
return @"";
var result,
detail,
val,
num;
result = [CPString string];
val = [docDict objectForKey:PAPERSIZE];
if (val)
{
detail = [CPString stringWithFormat:@"\\paperw%d \\paperh%d",
_points2twips(val.width),
_points2twips(val.height)];
result += detail;
}
num = [docDict objectForKey:LEFTMARGIN];
if (num)
{
var f = [num floatValue];
detail = [CPString stringWithFormat:@"\\margl%d", _points2twips(f)];
result += detail;
}
num = [docDict objectForKey:RIGHTMARGIN];
if (num)
{
var f = [num floatValue];
detail = [CPString stringWithFormat:@"\\margr%d", _points2twips(f)];
result += detail;
}
num = [docDict objectForKey:TOPMARGIN];
if (num)
{
var f = [num floatValue];
detail = [CPString stringWithFormat:@"\\margt%d", _points2twips(f)];
result += detail;
}
num = [docDict objectForKey:BUTTOMMARGIN];
if (num)
{
var f = [num floatValue];
detail = [CPString stringWithFormat:@"\\margb%d", _points2twips(f)];
result += detail;
}
return result;
}
- (CPString)headerString
{
var result;
result = [CPString stringWithString:@"{\\rtf1\\ansi"];
result += [self fontTable];
result += [self colorTable];
result += [self documentAttributes];
return result;
}
- (CPString)trailerString
{
return @"}";
}
- (CPString)fontToken:(CPString) fontName
{
var fCount = [fontDict objectForKey:fontName];
if (fCount == nil)
{
var count = [fontDict count];
fCount = [CPString stringWithFormat:@"\\f%d", count];
[fontDict setObject:fCount forKey:fontName];
}
return fCount;
}
- (int)numberForColor:(CPColor)color
{
var num = [colorDict objectForKey:[color cssString]];
if (!num)
[colorDict setObject:num = [CPNumber numberWithInt:[colorDict count] + 1]
forKey:[color cssString]];
return [num intValue];
}
- (CPString)paragraphStyle:(CPParagraphStyle)paraStyle
{
var headerString = [CPString stringWithString:@"\\pard"],
twips;
if (paraStyle == nil)
return headerString;
switch ([paraStyle alignment])
{
case CPRightTextAlignment:
headerString += @"\\qr";
break;
case CPCenterTextAlignment:
headerString += @"\\qc";
break;
case CPLeftTextAlignment:
headerString += @"\\ql";
break;
case CPJustifiedTextAlignment:
headerString += @"\\qj";
break;
default:
headerString += @"\\ql";
break;
}
// write first line indent and left indent
var twips = _points2twips([paraStyle firstLineHeadIndent]);
if (twips != 0.0)
headerString += [CPString stringWithFormat:@"\\fi%d", twips];
twips = _points2twips([paraStyle headIndent]);
if (twips != 0.0)
headerString += [CPString stringWithFormat:@"\\li%d", twips];
twips = _points2twips([paraStyle tailIndent]);
if (twips != 0.0)
headerString += [CPString stringWithFormat:@"\\ri%d", twips];
twips = _points2twips([paraStyle paragraphSpacing]);
if (twips != 0.0)
headerString += [CPString stringWithFormat:@"\\sa%d", twips];
twips = _points2twips([paraStyle minimumLineHeight]);
if (twips != 0.0)
headerString += [CPString stringWithFormat:@"\\sl%d", twips];
twips = _points2twips([paraStyle maximumLineHeight]);
if (twips != 0.0)
headerString += [CPString stringWithFormat:@"\\sl-%d", twips];
var enumerator,
tab;
enumerator = [[paraStyle tabStops] objectEnumerator];
while ((tab = [enumerator nextObject]))
{
switch ([tab tabStopType])
{
case CPLeftTabStopType:
// no tabkind emission needed
break;
/* case NSRightTabStopType:
headerString += @"\\tqr";
break;
case NSCenterTabStopType:
headerString += @"\\tqc";
break;
case NSDecimalTabStopType:
headerString += @"\\tqdec";
break;
default:
NSLog(@"Unknown tab stop type.");
*/
}
headerString += [CPString stringWithFormat:@"\\tx%d",_points2twips([tab location])];
}
return headerString;
}
- (CPString)runStringForString:(CPString) substring
attributes:(CPDictionary) attributes
paragraphStart:(BOOL) first
{
var result = "",
headerString = "",
trailerString = "",
attribEnum,
currAttrib;
if (first)
{
var paraStyle = [attributes objectForKey:CPParagraphStyleAttributeName];
headerString += [self paragraphStyle:paraStyle];
}
/*
* analyze attributes of current run
*
* FIXME: All the character attributes should be output relative to the font
* attributes of the paragraph. So if the paragraph has underline on it should
* still be possible to switch it off for some characters, which currently is
* not possible.
*/
attribEnum = [attributes keyEnumerator];
while ((currAttrib = [attribEnum nextObject]) != nil)
{
if ([currAttrib isEqualToString:CPFontAttributeName])
{
/*
* handle fonts
*/
var font,
fontName,
traits;
font = [attributes objectForKey:CPFontAttributeName];
fontName = [font familyName];
traits = [[CPFontManager sharedFontManager] traitsOfFont:font];
/*
* font name
*/
if (currentFont == nil || ![fontName isEqualToString:[currentFont familyName]])
headerString += [self fontToken:fontName];
/*
* font size
*/
if (currentFont == nil || [font size] != [currentFont size])
{
var points = [font size] * 2,
pString;
pString = [CPString stringWithFormat:@"\\fs%d", points];
headerString += pString;
}
/*
* font attributes
*/
if (traits & CPItalicFontMask)
{
headerString += @"\\i";
trailerString += @"\\i0";
}
if (traits & CPBoldFontMask)
{
headerString += @"\\b";
trailerString += @"\\b0";
}
if (first)
currentFont = font;
}
else if ([currAttrib isEqualToString:CPForegroundColorAttributeName])
{
var color = [attributes objectForKey:CPForegroundColorAttributeName];
if (![color isEqual:fgColor])
{
headerString += [CPString stringWithFormat:@"\\cf%d", [self numberForColor:color]];
trailerString += @"\\cf0";
}
}
else if ([currAttrib isEqualToString:CPBackgroundColorAttributeName])
{
var color = [attributes objectForKey:CPBackgroundColorAttributeName];
if (![color isEqual:bgColor])
{
headerString += [CPString stringWithFormat:@"\\cb%d", [self numberForColor:color]];
trailerString += @"\\cb0";
}
}
else if ([currAttrib isEqualToString:CPUnderlineStyleAttributeName])
{
headerString += @"\\ul";
trailerString += @"\\ulnone";
}
else if ([currAttrib isEqualToString:CPSuperscriptAttributeName])
{
var value = [attributes objectForKey:CPSuperscriptAttributeName],
svalue = [value intValue] * 6;
if (svalue > 0)
{
headerString += [CPString stringWithFormat:@"\\up%d", svalue];
trailerString += @"\\up0";
}
else if (svalue < 0)
{
headerString += [CPString stringWithFormat:@"\\dn-%d", svalue];
trailerString += @"\\dn0";
}
}
else if ([currAttrib isEqualToString:CPBaselineOffsetAttributeName])
{
var value = [attributes objectForKey:CPBaselineOffsetAttributeName],
svalue = [value floatValue] * 2;
if (svalue > 0)
{
headerString += [CPString stringWithFormat:@"\\up%d", svalue];
trailerString += @"\\up0";
}
else if (svalue < 0)
{
headerString += [CPString stringWithFormat:@"\\dn-%d", svalue];
trailerString += @"\\dn0";
}
}
else if ([currAttrib isEqualToString:CPAttachmentAttributeName])
{
}
else if ([currAttrib isEqualToString:CPLigatureAttributeName])
{
}
else if ([currAttrib isEqualToString:CPKernAttributeName])
{
}
}
substring = substring.replace(/\\/g, '\\\\');
substring = substring.replace(/\n/g, '\\par\n');
substring = substring.replace(/\t/g, '\\tab');
substring = substring.replace(/{/g, '\\{');
substring = substring.replace(/}/g, '\\}');
// FIXME: All characters not in the standard encoding must be
// replaced by \'xx
if (!first)
{
var braces;
if ([headerString length])
braces = [CPString stringWithFormat:@"{%@ %@}", headerString, substring];
else
braces = substring;
result += braces;
}
else
{
var nobraces;
if ([headerString length])
nobraces = [CPString stringWithFormat:@"%@ %@", headerString, substring];
else
nobraces = substring;
result += nobraces;
}
return result + trailerString;
}
- (CPString)bodyString
{
var string = [text string],
result = "",
loc = 0,
length = [string length],
currRange = CPMakeRange(loc, 0),
completeRange = CPMakeRange(0, length),
first = YES;
// FIXME <!> split along newline characters and run as outer loop
while (CPMaxRange(currRange) < CPMaxRange(completeRange)) // save all "runs"
{
var attributes,
substring,
runString;
attributes = [text attributesAtIndex:CPMaxRange(currRange)
longestEffectiveRange:currRange
inRange:completeRange];
substring = [string substringWithRange:currRange];
runString = [self runStringForString:substring
attributes:attributes
paragraphStart:YES];
result += runString;
first = NO;
}
return result;
}
- (CPString)RTFDStringFromAttributedString:(CPAttributedString)aText
documentAttributes:(CPDictionary)dict
{
var output = [CPString string],
headerString,
trailerString,
bodyString;
text = aText;
docDict = dict;
/*
* do not change order! (esp. body has to be generated first; builds context)
*/
bodyString = [self bodyString];
trailerString = [self trailerString];
headerString = [self headerString];
output += headerString;
output += bodyString;
output += trailerString;
return output;
}
@end
+70 -2
View File
@@ -24,9 +24,12 @@
@import <Foundation/CPMutableArray.j>
@import <Foundation/CPString.j>
@import <Foundation/CPKeyedUnarchiver.j>
@import <Foundation/CPBundle.j>
@class CPView
@class _CPThemeAttribute
@class CPImage
@class CPColor
var CPThemesByName = { },
CPThemeDefaultTheme = nil,
@@ -313,6 +316,71 @@ var CPThemeNameKey = @"CPThemeNameKey",
@end
#pragma mark -
#pragma mark CSS Theming
// The code below adds support for CSS theming with 100% compatibility with current theming system.
// The idea is to extend CPColor and CPImage with CSS components and adapt low level UI components to
// support this new kind of CPColor/CPImage. See CPImageView, CPView and _CPImageAndTextView.
//
// To be considered and treated as CSS based, a theme must set to YES the attribute "css-based" for CPView
// in the theDescriptor (default value is NO), like in the example below :
//
// + (CPView)themedView
// {
// var view = [[CPView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
//
// [self registerThemeValues:[[@"css-based", YES]] forView:view];
//
// return view;
// }
//
// You can use the method -(BOOL)isCSSBased on a theme to determine how to cope with it in your own code.
//
// The method -(void)setCSSResourcesPath is meant to be used only by CPThemeBlend during theme loading in order to
// replace the special path "%%" in CSS components (like in url(%%packed.png) ) with the path to the theme blend resources folder.
@implementation CPTheme (CSSTheming)
- (void)setCSSResourcesPath:(CPString)pathToResources
{
[_attributes enumerateKeysAndObjectsUsingBlock:function(aKey, anObject, stop)
{
[anObject enumerateKeysAndObjectsUsingBlock:function(aKey2, anObject2, stop2)
{
// anObject2 is now a _CPThemeAttribute
[[anObject2 values] enumerateKeysAndObjectsUsingBlock:function(aKey3, anObject3, stop3)
{
if (anObject3.isa && ([anObject3 isKindOfClass:CPImage] || [anObject3 isKindOfClass:CPColor]) && [anObject3 cssDictionary])
{
// We have a CSS defined image or color
[self _fixPathInCSSDictionary:[anObject3 cssDictionary] withPathToResources:pathToResources];
[self _fixPathInCSSDictionary:[anObject3 cssBeforeDictionary] withPathToResources:pathToResources];
[self _fixPathInCSSDictionary:[anObject3 cssAfterDictionary] withPathToResources:pathToResources];
}
}];
}];
}];
}
- (void)_fixPathInCSSDictionary:(CPDictionary)aDictionary withPathToResources:(CPString)pathToResources
{
[aDictionary enumerateKeysAndObjectsUsingBlock:function(aKey, anObject, stop)
{
[aDictionary setObject:[anObject stringByReplacingOccurrencesOfString:@"%%" withString:pathToResources] forKey:aKey];
}];
}
- (BOOL)isCSSBased
{
return !![self valueForAttributeWithName:@"css-based" forClass:[CPView class]];
}
@end
#pragma mark -
/*!
* ThemeStates are immutable objects representing a particular ThemeState. Applications should never be creating
* ThemeStates directly but should instead use the CPThemeState function.
@@ -322,7 +390,7 @@ function ThemeState(stateNames)
var stateNameKeys = [];
this._stateNames = {};
for (key in stateNames)
for (var key in stateNames)
{
if (!stateNames.hasOwnProperty(key))
continue;
@@ -769,7 +837,7 @@ var ParentAttributeForCoder = nil;
if ([aCoder containsValueForKey:@"state"])
state = [aCoder decodeObjectForKey:@"state"];
else
state = CPThemeStateNormalString
state = CPThemeStateNormalString;
[_values setObject:[aCoder decodeObjectForKey:"value"] forKey:state];
}
+15 -6
View File
@@ -64,12 +64,10 @@
*/
- (CPArray)themeNames
{
var names = [];
for (var i = 0; i < _themes.length; ++i)
names.push(_themes[i].substring(0, _themes[i].indexOf(".keyedtheme")));
return names;
return [_themes arrayByApplyingBlock:function(theme)
{
return theme.substring(0, theme.indexOf(".keyedtheme"));
}];
}
- (void)loadWithDelegate:(id)aDelegate
@@ -97,6 +95,17 @@
[unarchiver finishDecoding];
}
// CSS Theming
for (var i = 0, nb = [_themes count], allThemes = [self themeNames], aThemeName, aTheme; i < nb; i++)
{
aThemeName = allThemes[i];
aTheme = [CPTheme themeNamed:aThemeName];
if ([aTheme isCSSBased])
[aTheme setCSSResourcesPath:[aBundle resourcePath]];
}
[_loadDelegate blendDidFinishLoading:self];
}
+14 -6
View File
@@ -523,17 +523,25 @@ CPTokenFieldDeleteButtonType = 1;
var element = [self _inputElement];
CPTokenFieldInputResigning = YES;
element.blur();
if (CPTokenFieldInputIsActive)
element.blur();
if (!CPTokenFieldInputDidBlur)
CPTokenFieldBlurHandler();
CPTokenFieldInputDidBlur = NO;
CPTokenFieldInputResigning = NO;
if (element.parentNode == [_tokenScrollView documentView]._DOMElement)
element.parentNode.removeChild(element);
// Previosly, we unflagged CPTokenFieldInputDidBlur and CPTokenFieldInputResigning before
// the call to removeChild. This may result in DOM exceptions in Chrome under certain conditions.
// See https://stackoverflow.com/questions/21926083/failed-to-execute-removechild-on-node
// for why we need to unflag CPTokenFieldInputDidBlur and CPTokenFieldInputResigning
// only after removing the element.
CPTokenFieldInputDidBlur = NO;
CPTokenFieldInputResigning = NO;
CPTokenFieldInputIsActive = NO;
if (document.attachEvent)
@@ -541,7 +549,7 @@ CPTokenFieldDeleteButtonType = 1;
CPTokenFieldCachedSelectStartFunction = nil;
CPTokenFieldCachedDragFunction = nil;
document.body.ondrag = CPTokenFieldCachedDragFunction
document.body.ondrag = CPTokenFieldCachedDragFunction;
document.body.onselectstart = CPTokenFieldCachedSelectStartFunction
}
@@ -1239,7 +1247,7 @@ CPTokenFieldDeleteButtonType = 1;
var scrollToToken = _shouldScrollTo;
if (scrollToToken === CPScrollDestinationLeft)
scrollToToken = tokens[_selectedRange.location]
scrollToToken = tokens[_selectedRange.location];
else if (scrollToToken === CPScrollDestinationRight)
scrollToToken = tokens[MAX(0, CPMaxRange(_selectedRange) - 1)];
[self _scrollTokenViewToVisible:scrollToToken];
+6 -7
View File
@@ -153,7 +153,7 @@ var CPToolbarsByIdentifier = nil,
if (!toolbarsSharingIdentifier)
{
toolbarsSharingIdentifier = []
toolbarsSharingIdentifier = [];
[CPToolbarsByIdentifier setObject:toolbarsSharingIdentifier forKey:identifier];
}
@@ -459,11 +459,10 @@ var CPToolbarsByIdentifier = nil,
/* @ignore */
- (id)_itemsWithIdentifiers:(CPArray)identifiers
{
var items = [];
for (var i = 0; i < identifiers.length; i++)
[items addObject:[self _itemForItemIdentifier:identifiers[i] willBeInsertedIntoToolbar:NO]];
return items;
return [identifiers arrayByApplyingBlock:function(identifier)
{
return [self _itemForItemIdentifier:identifier willBeInsertedIntoToolbar:NO];
}];
}
/* @ignore */
@@ -589,7 +588,7 @@ var CPToolbarIdentifierKey = @"CPToolbarIdentifierKey",
[aCoder encodeBool:_showsBaselineSeparator forKey:CPToolbarShowsBaselineSeparatorKey];
[aCoder encodeBool:_allowsUserCustomization forKey:CPToolbarAllowsUserCustomizationKey];
[aCoder encodeBool:_isVisible forKey:CPToolbarIsVisibleKey];
[aCoder encodeInt:_sizeMode forKey:CPToolbarSizeModeKey]
[aCoder encodeInt:_sizeMode forKey:CPToolbarSizeModeKey];
[aCoder encodeObject:_identifiedItems forKey:CPToolbarIdentifiedItemsKey];
[aCoder encodeObject:_defaultItems forKey:CPToolbarDefaultItemsKey];
+223 -121
View File
@@ -112,6 +112,11 @@ CPViewHeightSizable = 16;
*/
CPViewMaxYMargin = 32;
_CPViewWillAppearNotification = @"CPViewWillAppearNotification";
_CPViewDidAppearNotification = @"CPViewDidAppearNotification";
_CPViewWillDisappearNotification = @"CPViewWillDisappearNotification";
_CPViewDidDisappearNotification = @"CPViewDidDisappearNotification";
CPViewBoundsDidChangeNotification = @"CPViewBoundsDidChangeNotification";
CPViewFrameDidChangeNotification = @"CPViewFrameDidChangeNotification";
@@ -124,7 +129,8 @@ var DOMElementPrototype = nil,
BackgroundVerticalThreePartImage = 1,
BackgroundHorizontalThreePartImage = 2,
BackgroundNinePartImage = 3,
BackgroundTransparentColor = 4;
BackgroundTransparentColor = 4,
BackgroundCSSStyling = 5;
#endif
var CPViewFlags = { },
@@ -172,6 +178,7 @@ var CPViewHighDPIDrawingEnabled = YES;
CPArray _registeredDraggedTypesArray;
BOOL _isHidden;
BOOL _isHiddenOrHasHiddenAncestor;
BOOL _hitTests;
BOOL _clipsToBounds;
@@ -189,6 +196,10 @@ var CPViewHighDPIDrawingEnabled = YES;
CPArray _DOMImageSizes;
unsigned _backgroundType;
// CSS styling
CPArray _cssStylePreviousState;
DOMElement _cssStyleNode;
#endif
CGRect _dirtyRect;
@@ -243,6 +254,11 @@ var CPViewHighDPIDrawingEnabled = YES;
CPMutableArray _trackingAreas @accessors(getter=trackingAreas, copy);
BOOL _inhibitUpdateTrackingAreas;
id _animator;
CPDictionary _animationsDictionary;
BOOL _inhibitDOMUpdates @accessors(setter=_setInhibitDOMUpdates);
BOOL _forceUpdates @accessors(setter=_setForceUpdates);
}
/*
@@ -309,6 +325,18 @@ var CPViewHighDPIDrawingEnabled = YES;
return nil;
}
+ (CPString)defaultThemeClass
{
return @"view";
}
+ (CPDictionary)themeAttributes
{
return @{
@"css-based": NO
};
}
- (void)_setupViewFlags
{
var theClass = [self class],
@@ -369,6 +397,7 @@ var CPViewHighDPIDrawingEnabled = YES;
_opacity = 1.0;
_isHidden = NO;
_isHiddenOrHasHiddenAncestor = NO;
_hitTests = YES;
_hierarchyScaleSize = CGSizeMake(1.0 , 1.0);
@@ -387,16 +416,28 @@ var CPViewHighDPIDrawingEnabled = YES;
_DOMImageParts = [];
_DOMImageSizes = [];
_cssStylePreviousState = @[];
#endif
_animator = nil;
_animationsDictionary = @{};
[self _setupViewFlags];
[self _loadThemeAttributes];
}
_inhibitDOMUpdates = NO;
_forceUpdates = NO;
// We force here an updateTrackingAreas in order to let the view install its own tracking areas
// in the case where an externally owned tracking area is installed on this view before putting
// it in the view hierarchy.
[self updateTrackingAreas];
}
return self;
}
/*!
Sets the tooltip for the receiver.
@@ -404,7 +445,7 @@ var CPViewHighDPIDrawingEnabled = YES;
*/
- (void)setToolTip:(CPString)aToolTip
{
if (_toolTip == aToolTip)
if (_toolTip === aToolTip)
return;
if (aToolTip && ![aToolTip isKindOfClass:CPString])
@@ -432,7 +473,7 @@ var CPViewHighDPIDrawingEnabled = YES;
return;
if (!_toolTipFunctionIn)
_toolTipFunctionIn = function(e) { [_CPToolTip scheduleToolTipForView:self]; }
_toolTipFunctionIn = function(e) { [_CPToolTip scheduleToolTipForView:self]; };
if (!_toolTipFunctionOut)
_toolTipFunctionOut = function(e) { [_CPToolTip invalidateCurrentToolTipIfNeeded]; };
@@ -562,7 +603,7 @@ var CPViewHighDPIDrawingEnabled = YES;
[[self window] _dirtyKeyViewLoop];
// If this is already one of our subviews, remove it.
if (aSubview._superview == self)
if (aSubview._superview === self)
{
var index = [_subviews indexOfObjectIdenticalTo:aSubview];
@@ -591,8 +632,9 @@ var CPViewHighDPIDrawingEnabled = YES;
// Remove the view from its previous superview.
[aSubview _removeFromSuperview];
[aSubview _postViewWillAppearNotification];
// Set ourselves as the superview.
aSubview._superview = self;
[aSubview _setSuperview:self];
}
if (anIndex === CPNotFound || anIndex >= count)
@@ -617,11 +659,6 @@ var CPViewHighDPIDrawingEnabled = YES;
[aSubview setNextResponder:self];
[aSubview _scaleSizeUnitSquareToSize:[self _hierarchyScaleSize]];
// If the subview is not hidden and one of its ancestors is hidden,
// notify the subview that it is now hidden.
if (![aSubview isHidden] && [self isHiddenOrHasHiddenAncestor])
[aSubview _notifyViewDidHide];
[aSubview viewDidMoveToSuperview];
// Set the subview's window to our own.
@@ -682,6 +719,7 @@ var CPViewHighDPIDrawingEnabled = YES;
[[self window] _dirtyKeyViewLoop];
[_superview willRemoveSubview:self];
[self _postViewWillDisappearNotification];
[_superview._subviews removeObjectIdenticalTo:self];
@@ -691,13 +729,10 @@ var CPViewHighDPIDrawingEnabled = YES;
// If the view is not hidden and one of its ancestors is hidden,
// notify the view that it is now unhidden.
if (!_isHidden && [_superview isHiddenOrHasHiddenAncestor])
[self _notifyViewDidUnhide];
[self _setSuperview:nil];
[self _notifyWindowDidResignKey];
[self _notifyViewDidResignFirstResponder];
_superview = nil;
}
/*!
@@ -805,13 +840,13 @@ var CPViewHighDPIDrawingEnabled = YES;
[_window _noteUnregisteredDraggedTypes:_registeredDraggedTypes];
[aWindow _noteRegisteredDraggedTypes:_registeredDraggedTypes];
}
// View must be removed from the current window viewsWithTrackingAreas
if (_window && (_trackingAreas.length > 0))
[_window _removeTrackingAreaView:self];
_window = aWindow;
if (_window)
{
var owners;
@@ -857,7 +892,7 @@ var CPViewHighDPIDrawingEnabled = YES;
do
{
if (view == aView)
if (view === aView)
return YES;
} while(view = [view superview])
@@ -972,7 +1007,7 @@ var CPViewHighDPIDrawingEnabled = YES;
- (CPView)viewWithTag:(CPInteger)aTag
{
if ([self tag] == aTag)
if ([self tag] === aTag)
return self;
var index = 0,
@@ -1007,7 +1042,7 @@ var CPViewHighDPIDrawingEnabled = YES;
*/
- (void)setFrame:(CGRect)aFrame
{
if (CGRectEqualToRect(_frame, aFrame))
if (CGRectEqualToRect(_frame, aFrame) && !_forceUpdates)
return;
_inhibitFrameAndBoundsChangedNotifications = YES;
@@ -1024,7 +1059,7 @@ var CPViewHighDPIDrawingEnabled = YES;
[[self superview] viewFrameChanged:[[CPNotification alloc] initWithName:CPViewFrameDidChangeNotification object:self userInfo:nil]];
if (!_inhibitUpdateTrackingAreas)
[self _updateTrackingAreas];
[self _updateTrackingAreasWithRecursion:YES];
}
/*!
@@ -1078,7 +1113,7 @@ var CPViewHighDPIDrawingEnabled = YES;
{
var origin = _frame.origin;
if (!aPoint || CGPointEqualToPoint(origin, aPoint))
if (!aPoint || (CGPointEqualToPoint(origin, aPoint) && !_forceUpdates))
return;
origin.x = aPoint.x;
@@ -1091,13 +1126,16 @@ var CPViewHighDPIDrawingEnabled = YES;
[[self superview] viewFrameChanged:[[CPNotification alloc] initWithName:CPViewFrameDidChangeNotification object:self userInfo:nil]];
#if PLATFORM(DOM)
var transform = _superview ? _superview._boundsTransform : NULL;
if (!_inhibitDOMUpdates)
{
var transform = _superview ? _superview._boundsTransform : NULL;
CPDOMDisplayServerSetStyleLeftTop(_DOMElement, transform, origin.x, origin.y);
CPDOMDisplayServerSetStyleLeftTop(_DOMElement, transform, origin.x, origin.y);
}
#endif
if (!_inhibitUpdateTrackingAreas && !_inhibitFrameAndBoundsChangedNotifications)
[self _updateTrackingAreas];
[self _updateTrackingAreasWithRecursion:YES];
}
/*!
@@ -1110,7 +1148,7 @@ var CPViewHighDPIDrawingEnabled = YES;
{
var size = _frame.size;
if (!aSize || CGSizeEqualToSize(size, aSize))
if (!aSize || (CGSizeEqualToSize(size, aSize) && !_forceUpdates))
return;
var oldSize = CGSizeMakeCopy(size);
@@ -1251,7 +1289,7 @@ var CPViewHighDPIDrawingEnabled = YES;
[[self superview] viewFrameChanged:[[CPNotification alloc] initWithName:CPViewFrameDidChangeNotification object:self userInfo:nil]];
if (!_inhibitUpdateTrackingAreas && !_inhibitFrameAndBoundsChangedNotifications)
[self _updateTrackingAreas];
[self _updateTrackingAreasWithRecursion:!_autoresizesSubviews];
}
/*!
@@ -1264,7 +1302,8 @@ var CPViewHighDPIDrawingEnabled = YES;
#if PLATFORM(DOM)
var scale = [self scaleSize];
CPDOMDisplayServerSetStyleSize(_DOMElement, aSize.width * 1 / scale.width, aSize.height * 1 / scale.height);
if (!_inhibitDOMUpdates)
CPDOMDisplayServerSetStyleSize(_DOMElement, aSize.width * 1 / scale.width, aSize.height * 1 / scale.height);
if (_DOMContentsElement)
{
@@ -1300,7 +1339,7 @@ var CPViewHighDPIDrawingEnabled = YES;
[[self superview] viewBoundsChanged:[[CPNotification alloc] initWithName:CPViewBoundsDidChangeNotification object:self userInfo:nil]];
if (!_inhibitUpdateTrackingAreas)
[self _updateTrackingAreas];
[self _updateTrackingAreasWithRecursion:YES];
}
/*!
@@ -1368,7 +1407,7 @@ var CPViewHighDPIDrawingEnabled = YES;
[[self superview] viewBoundsChanged:[[CPNotification alloc] initWithName:CPViewBoundsDidChangeNotification object:self userInfo:nil]];
if (!_inhibitUpdateTrackingAreas && !_inhibitFrameAndBoundsChangedNotifications)
[self _updateTrackingAreas];
[self _updateTrackingAreasWithRecursion:YES];
}
/*!
@@ -1412,7 +1451,7 @@ var CPViewHighDPIDrawingEnabled = YES;
[[self superview] viewBoundsChanged:[[CPNotification alloc] initWithName:CPViewBoundsDidChangeNotification object:self userInfo:nil]];
if (!_inhibitUpdateTrackingAreas && !_inhibitFrameAndBoundsChangedNotifications)
[self _updateTrackingAreas];
[self _updateTrackingAreasWithRecursion:YES];
}
@@ -1424,7 +1463,7 @@ var CPViewHighDPIDrawingEnabled = YES;
{
var mask = [self autoresizingMask];
if (mask == CPViewNotSizable)
if (mask === CPViewNotSizable)
return;
var frame = _superview._frame,
@@ -1593,10 +1632,8 @@ var CPViewHighDPIDrawingEnabled = YES;
// FIXME: Should we return to visibility? This breaks in FireFox, Opera, and IE.
// _DOMElement.style.visibility = (_isHidden = aFlag) ? "hidden" : "visible";
_isHidden = aFlag;
#if PLATFORM(DOM)
_DOMElement.style.display = _isHidden ? "none" : "block";
_DOMElement.style.display = aFlag ? "none" : "block";
#endif
if (aFlag)
@@ -1607,7 +1644,7 @@ var CPViewHighDPIDrawingEnabled = YES;
{
do
{
if (self == view)
if (self === view)
{
[_window makeFirstResponder:[self nextValidKeyView]];
break;
@@ -1616,33 +1653,89 @@ var CPViewHighDPIDrawingEnabled = YES;
while (view = [view superview]);
}
[self _notifyViewDidHide];
[self _postViewWillDisappearNotification];
[self _recursiveGainedHiddenAncestor];
}
else
{
[self setNeedsDisplay:YES];
[self _notifyViewDidUnhide];
[self _postViewWillAppearNotification];
[self _recursiveLostHiddenAncestor];
}
_isHidden = aFlag;
}
- (void)_notifyViewDidHide
- (void)_postViewWillAppearNotification
{
[self viewDidHide];
var count = [_subviews count];
while (count--)
[_subviews[count] _notifyViewDidHide];
[[CPNotificationCenter defaultCenter] postNotificationName:_CPViewWillAppearNotification object:self userInfo:nil];
}
- (void)_notifyViewDidUnhide
- (void)_postViewDidAppearNotification
{
[self viewDidUnhide];
[[CPNotificationCenter defaultCenter] postNotificationName:_CPViewDidAppearNotification object:self userInfo:nil];
}
var count = [_subviews count];
- (void)_postViewWillDisappearNotification
{
[[CPNotificationCenter defaultCenter] postNotificationName:_CPViewWillDisappearNotification object:self userInfo:nil];
}
while (count--)
[_subviews[count] _notifyViewDidUnhide];
- (void)_postViewDidDisappearNotification
{
[[CPNotificationCenter defaultCenter] postNotificationName:_CPViewDidDisappearNotification object:self userInfo:nil];
}
- (void)_setSuperview:(CPView)aSuperview
{
var hasOldSuperview = (_superview !== nil),
hasNewSuperview = (aSuperview !== nil),
oldSuperviewIsHidden = hasOldSuperview && [_superview isHiddenOrHasHiddenAncestor],
newSuperviewIsHidden = hasNewSuperview && [aSuperview isHiddenOrHasHiddenAncestor];
if (!newSuperviewIsHidden && oldSuperviewIsHidden)
[self _recursiveLostHiddenAncestor];
if (newSuperviewIsHidden && !oldSuperviewIsHidden)
[self _recursiveGainedHiddenAncestor];
_superview = aSuperview;
if (hasOldSuperview)
[self _postViewDidDisappearNotification];
if (hasNewSuperview)
[self _postViewDidAppearNotification];
}
- (void)_recursiveLostHiddenAncestor
{
if (_isHiddenOrHasHiddenAncestor)
{
_isHiddenOrHasHiddenAncestor = NO;
[self viewDidUnhide];
}
[_subviews enumerateObjectsUsingBlock:function(view, idx, stop)
{
[view _recursiveLostHiddenAncestor];
}];
}
- (void)_recursiveGainedHiddenAncestor
{
if (!_isHidden)
{
[self viewDidHide];
}
_isHiddenOrHasHiddenAncestor = YES;
[_subviews enumerateObjectsUsingBlock:function(view, idx, stop)
{
[view _recursiveGainedHiddenAncestor];
}];
}
/*!
@@ -1677,7 +1770,7 @@ var CPViewHighDPIDrawingEnabled = YES;
*/
- (void)setAlphaValue:(float)anAlphaValue
{
if (_opacity == anAlphaValue)
if (_opacity === anAlphaValue)
return;
_opacity = anAlphaValue;
@@ -1712,12 +1805,7 @@ var CPViewHighDPIDrawingEnabled = YES;
*/
- (BOOL)isHiddenOrHasHiddenAncestor
{
var view = self;
while (view && ![view isHidden])
view = [view superview];
return view !== nil;
return _isHiddenOrHasHiddenAncestor;
}
/*!
@@ -1881,24 +1969,34 @@ var CPViewHighDPIDrawingEnabled = YES;
*/
- (void)setBackgroundColor:(CPColor)aColor
{
if (_backgroundColor == aColor)
if (_backgroundColor === aColor)
return;
if (aColor == [CPNull null])
if (aColor === [CPNull null])
aColor = nil;
_backgroundColor = aColor;
#if PLATFORM(DOM)
if (_backgroundType === BackgroundCSSStyling)
[_backgroundColor restorePreviousCSSState:@ref(_cssStylePreviousState) forDOMElement:_DOMElement];
var patternImage = [_backgroundColor patternImage],
colorExists = _backgroundColor && ([_backgroundColor patternImage] || [_backgroundColor alphaComponent] > 0.0),
colorHasAlpha = colorExists && [_backgroundColor alphaComponent] < 1.0,
supportsRGBA = CPFeatureIsCompatible(CPCSSRGBAFeature),
colorNeedsDOMElement = colorHasAlpha && !supportsRGBA,
amount = 0,
slices;
slices,
// For CSS theming
isCSSBasedColor = [_backgroundColor isCSSBased];
if ([patternImage isThreePartImage])
if (isCSSBasedColor)
{
_backgroundType = BackgroundCSSStyling;
amount = -_DOMImageParts.length;
}
else if ([patternImage isThreePartImage])
{
_backgroundType = [patternImage isVertical] ? BackgroundVerticalThreePartImage : BackgroundHorizontalThreePartImage;
amount = 3;
@@ -1927,7 +2025,7 @@ var CPViewHighDPIDrawingEnabled = YES;
var image = slices[i],
size = [image size];
if (!size || (size.width == 0 && size.height == 0))
if (!size || (size.width === 0 && size.height === 0))
size = nil;
_DOMImageSizes[i] = size;
@@ -1961,7 +2059,14 @@ var CPViewHighDPIDrawingEnabled = YES;
_DOMElement.removeChild(_DOMImageParts.pop());
}
if (_backgroundType === BackgroundTrivialColor || _backgroundType === BackgroundTransparentColor)
if (_backgroundType === BackgroundCSSStyling)
{
_cssStyleNode = [_backgroundColor applyCSSColorForView:self
onDOMElement:_DOMElement
styleNode:_cssStyleNode
previousState:@ref(_cssStylePreviousState)];
}
else if (_backgroundType === BackgroundTrivialColor || _backgroundType === BackgroundTransparentColor)
{
var colorCSS = colorExists ? [_backgroundColor cssString] : "";
@@ -1982,10 +2087,12 @@ var CPViewHighDPIDrawingEnabled = YES;
CPDOMDisplayServerSetStyleSize(_DOMImageParts[0], size.width, size.height);
}
else
{
_DOMElement.style.background = colorCSS;
if (patternImage)
CPDOMDisplayServerSetStyleBackgroundSize(_DOMElement, [patternImage size].width + "px", [patternImage size].height + "px");
}
}
else
{
@@ -2019,7 +2126,7 @@ var CPViewHighDPIDrawingEnabled = YES;
partIndex++;
}
if (_backgroundType == BackgroundNinePartImage)
if (_backgroundType === BackgroundNinePartImage)
{
var left = _DOMImageSizes[0] ? _DOMImageSizes[0].width : 0,
right = _DOMImageSizes[2] ? _DOMImageSizes[2].width : 0,
@@ -2080,7 +2187,7 @@ var CPViewHighDPIDrawingEnabled = YES;
CPDOMDisplayServerSetStyleRightBottom(_DOMImageParts[partIndex], NULL, 0.0, 0.0);
}
}
else if (_backgroundType == BackgroundVerticalThreePartImage)
else if (_backgroundType === BackgroundVerticalThreePartImage)
{
var top = _DOMImageSizes[0] ? _DOMImageSizes[0].height : 0,
bottom = _DOMImageSizes[2] ? _DOMImageSizes[2].height : 0;
@@ -2112,7 +2219,7 @@ var CPViewHighDPIDrawingEnabled = YES;
CPDOMDisplayServerSetStyleSize(_DOMImageParts[partIndex], frameSize.width, bottom);
}
}
else if (_backgroundType == BackgroundHorizontalThreePartImage)
else if (_backgroundType === BackgroundHorizontalThreePartImage)
{
var left = _DOMImageSizes[0] ? _DOMImageSizes[0].width : 0,
right = _DOMImageSizes[2] ? _DOMImageSizes[2].width : 0;
@@ -2851,8 +2958,8 @@ setBoundsOrigin:
return YES;
}
/*
FIXME Not yet implemented
/*!
Scrolls the views CPClipView in the direction of a mouse event that occurs outside of it.
*/
- (BOOL)autoscroll:(CPEvent)anEvent
{
@@ -2917,7 +3024,7 @@ setBoundsOrigin:
*/
- (BOOL)inLiveResize
{
return _inLiveResize;
return [self window] && [[self window] _inLiveResize];
}
/*!
@@ -3074,7 +3181,7 @@ setBoundsOrigin:
*/
- (void)setLayer:(CALayer)aLayer
{
if (_layer == aLayer)
if (_layer === aLayer)
return;
if (_layer)
@@ -3368,6 +3475,17 @@ setBoundsOrigin:
@end
@implementation CPView (CSSTheming)
- (void)setDOMClassName:(CPString)aClassName
{
#if PLATFORM(DOM)
_DOMElement.className = aClassName;
#endif
}
@end
@implementation CPView (Appearance)
@@ -3459,16 +3577,16 @@ setBoundsOrigin:
// Consistency check
if (!trackingArea || [_trackingAreas containsObjectIdenticalTo:trackingArea])
return;
if ([trackingArea view])
[CPException raise:CPInternalInconsistencyException reason:"Tracking area has already been added to another view."];
[_trackingAreas addObject:trackingArea];
[trackingArea setView:self];
if (_window)
[_window _addTrackingArea:trackingArea];
[trackingArea _updateWindowRect];
}
@@ -3477,25 +3595,26 @@ setBoundsOrigin:
// Consistency check
if (!trackingArea)
return;
if (![_trackingAreas containsObjectIdenticalTo:trackingArea])
[CPException raise:CPInternalInconsistencyException reason:"Trying to remove unreferenced trackingArea"];
[self _removeTrackingArea:trackingArea];
}
/*!
/*!
Invoked automatically when the views geometry changes such that its tracking areas need to be recalculated.
You should override this method to remove out of date tracking areas and add recomputed tracking areas;
You should override this method to remove out of date tracking areas, add recomputed tracking areas and then call super;
Cocoa calls this on every view, whereas they have tracking area(s) or not.
Cappuccino behaves differently :
- updateTrackingAreas is called when placing a view in the view hierarchy (that is in a window)
- updateTrackingAreas is called during initWithFrame
- updateTrackingAreas is also called when placing a view in the view hierarchy (that is in a window)
- if you have only CPTrackingInVisibleRect tracking areas attached to a view, it will not be called again (until you move the view in the hierarchy)
- if you have at least one non-CPTrackingInVisibleRect tracking area attached, it will be called every time the view geometry could be modified
You don't have to touch to CPTrackingInVisibleRect tracking areas, they will be automatically updated
Please note that it is the owner of a tracking area who is called for updateTrackingAreas.
But, if a view without any tracking area is inserted in the view hierarchy (that is, in a window), the view is called for updateTrackingAreas.
This enables you to use updateTrackingArea to initially attach your tracking areas to the view.
@@ -3505,51 +3624,32 @@ setBoundsOrigin:
}
/*!
This utility method is intended for CPView subclasses overriding updateTrackingAreas
Typical use would be :
- (void)updateTrackingAreas
{
[self removeAllTrackingAreas];
... add your specific updated tracking areas ...
}
*/
- (void)removeAllTrackingAreas
{
while (_trackingAreas.length > 0)
[self _removeTrackingArea:_trackingAreas[0]];
}
// Internal methods
- (void)_removeTrackingArea:(CPTrackingArea)trackingArea
{
if (_window)
[_window _removeTrackingArea:trackingArea];
[trackingArea setView:nil];
[_trackingAreas removeObjectIdenticalTo:trackingArea];
}
- (void)_updateTrackingAreas
- (void)_updateTrackingAreasWithRecursion:(BOOL)shouldCallRecursively
{
_inhibitUpdateTrackingAreas = YES;
[self _recursivelyUpdateTrackingAreas];
_inhibitUpdateTrackingAreas = NO;
}
- (void)_recursivelyUpdateTrackingAreas
{
[self _updateTrackingAreasForOwners:[self _calcTrackingAreaOwners]];
for (var i = 0; i < _subviews.length; i++)
[_subviews[i] _recursivelyUpdateTrackingAreas];
if (shouldCallRecursively)
{
// Now, call _updateTrackingAreasWithRecursion on subviews
for (var i = 0; i < _subviews.length; i++)
[_subviews[i] _updateTrackingAreasWithRecursion:YES];
}
_inhibitUpdateTrackingAreas = NO;
}
- (CPArray)_calcTrackingAreaOwners
@@ -3557,25 +3657,25 @@ setBoundsOrigin:
// First search all owners that must be notified
// Remark: 99.99% of time, the only owner will be the view itself
// In the same time, update the rects of InVisibleRect tracking areas
var owners = [];
for (var i = 0; i < _trackingAreas.length; i++)
{
var trackingArea = _trackingAreas[i];
if ([trackingArea options] & CPTrackingInVisibleRect)
[trackingArea _updateWindowRect];
else
{
var owner = [trackingArea owner];
if (![owners containsObjectIdenticalTo:owner])
[owners addObject:owner];
}
}
return owners;
}
@@ -3606,7 +3706,7 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
CPViewScaleKey = @"CPViewScaleKey",
CPViewSizeScaleKey = @"CPViewSizeScaleKey",
CPViewIsScaledKey = @"CPViewIsScaledKey",
CPViewAppearanceKey = @"CPViewAppearanceKey";
CPViewAppearanceKey = @"CPViewAppearanceKey",
CPViewTrackingAreasKey = @"CPViewTrackingAreasKey";
@implementation CPView (CPCoding)
@@ -3636,17 +3736,16 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
if (self)
{
_trackingAreas = [aCoder decodeObjectForKey:CPViewTrackingAreasKey];
if (!_trackingAreas)
_trackingAreas = [];
// We have to manually check because it may be 0, so we can't use ||
_tag = [aCoder containsValueForKey:CPViewTagKey] ? [aCoder decodeIntForKey:CPViewTagKey] : -1;
_identifier = [aCoder decodeObjectForKey:CPReuseIdentifierKey];
_window = [aCoder decodeObjectForKey:CPViewWindowKey];
_superview = [aCoder decodeObjectForKey:CPViewSuperviewKey];
// We have to manually add the subviews so that they will receive
// viewWillMoveToSuperview: and viewDidMoveToSuperview:
_subviews = [];
@@ -3684,6 +3783,8 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
// DOM SETUP
#if PLATFORM(DOM)
_cssStylePreviousState = @[];
_DOMImageParts = [];
_DOMImageSizes = [];
@@ -3701,6 +3802,7 @@ var CPViewAutoresizingMaskKey = @"CPViewAutoresizingMask",
#endif
[self setHidden:[aCoder decodeBoolForKey:CPViewIsHiddenKey]];
_isHiddenOrHasHiddenAncestor = NO;
if ([aCoder containsValueForKey:CPViewOpacityKey])
[self setAlphaValue:[aCoder decodeIntForKey:CPViewOpacityKey]];
+174 -2
View File
@@ -149,9 +149,10 @@ var CPViewControllerCachedCibs;
If you use Interface Builder to create your views, and you initialize the
controller using the initWithCibName:bundle: methods, then you MUST NOT override
this method. The consequences risk shattering the space-time continuum.
this method.
Note: The cib loading system is currently synchronous.
@note When using this method, the cib loading system is synchronous.
See the loadViewWithCompletionHandler: method for an asynchronous loading.
*/
- (void)loadView
{
@@ -176,6 +177,67 @@ var CPViewControllerCachedCibs;
_view = [CPView new];
}
/*!
Asynchronously load the cib and create the view that the controller manages.
@param aHandler a function which will be passed the loaded view as the first
argument and a network error or nil as the second argument: function(view, error).
@note If the view has already been loaded, the completion handler is run immediatly
and the process is synchronous.
*/
- (void)loadViewWithCompletionHandler:(Function/*(view, error)*/)aHandler
{
if (_view)
return;
if (_cibName)
{
// check if a cib is already cached for the current _cibName
var cib = [CPViewControllerCachedCibs objectForKey:_cibName];
if (!cib)
{
var cibName = _cibName;
if (![cibName hasSuffix:@".cib"])
cibName = [cibName stringByAppendingString:@".cib"];
// If aBundle is nil, use mainBundle, but ONLY for searching for the nib, not for resources later.
var bundle = _cibBundle || [CPBundle mainBundle],
url = [bundle _cibPathForResource:cibName];
// if the cib isn't cached yet : fetch it and cache it
[CPURLConnection sendAsynchronousRequest:[CPURLRequest requestWithURL:url] queue:[CPOperationQueue mainQueue] completionHandler:function(aResponse, aData, anError)
{
if (anError == nil)
{
var data = [CPData dataWithRawString:aData],
aCib = [[CPCib alloc] _initWithData:data bundle:_cibBundle cibName:_cibName];
[CPViewControllerCachedCibs setObject:aCib forKey:_cibName];
[aCib instantiateCibWithExternalNameTable:_cibExternalNameTable];
[self _viewDidLoadWithCompletionHandler:aHandler];
}
else
{
aHandler(nil, anError);
}
}];
}
else
{
[cib instantiateCibWithExternalNameTable:_cibExternalNameTable];
[self _viewDidLoadWithCompletionHandler:aHandler];
}
}
else
{
_view = [CPView new];
[self _viewDidLoadWithCompletionHandler:aHandler];
}
}
/*!
Returns the view that the controller manages.
@@ -230,6 +292,16 @@ var CPViewControllerCachedCibs;
[self didChangeValueForKey:"isViewLoaded"];
}
- (void)_viewDidLoadWithCompletionHandler:(Function)aHandler
{
[self _registerOrUnregister:YES notificationsForView:_view];
[self willChangeValueForKey:"isViewLoaded"];
aHandler(_view, nil);
_isViewLoaded = YES;
[self didChangeValueForKey:"isViewLoaded"];
}
/*!
This method is called after the view controller has loaded its associated views into memory.
@@ -243,6 +315,79 @@ var CPViewControllerCachedCibs;
}
/*!
Called after the view controllers view has been loaded into memory is about to be added to the
view hierarchy in the window.
@discussion You can override this method to perform tasks prior to a view controllers view
getting added to view hierarchy, such as setting the views highlight color. This method is called when:
• The view is about to be added to the view hierarchy of the view controller
If you override this method, call this method on super at some point in your implementation in case
a superclass also overrides this method.
The default implementation of this method does nothing.
*/
- (void)viewWillAppear
{
}
/*!
Called when the view controllers view is fully transitioned onto the screen.
@discussion This method is called after the completion of any drawing and animations
involved in the initial appearance of the view. You can override this method to
perform tasks appropriate for that time, such as work that should not interfere
with the presentation animation, or starting an animation that you want to begin
after the view appears.
If you override this method, call this method on super at some point in your
implementation in case a superclass also overrides this method.
The default implementation of this method does nothing.
*/
- (void)viewDidAppear
{
}
/*!
Called when the view controllers view is about to be removed from the view hierarchy in the window.
@discussion You can override this method to perform tasks that are to precede the disappearance
of the view controllers view, such as stopping a continuous animation that you
started in response to the viewDidAppear method call. This method is called when:
• The view is about to be removed from the view hierarchy of the window
If you override this method, call this method on super at some point in your
implementation in case a superclass also overrides this method.
The default implementation of this method does nothing.
*/
- (void)viewWillDisappear
{
}
/*!
Called after the view controllers view is removed from the view hierarchy in a window.
@discussion You can override this method to perform tasks associated with removing the view
controllers view from the windows view hierarchy, such as releasing resources
not needed when the view is not visible or no longer part of the window.
If you override this method, call this method on super at some point in your
implementation in case a superclass also overrides this method.
The default implementation of this method does nothing.
*/
- (void)viewDidDisappear
{
}
/*!
Manually sets the view that the controller manages.
@@ -256,6 +401,9 @@ var CPViewControllerCachedCibs;
{
var willChangeIsViewLoaded = (_isViewLoaded == NO && aView != nil) || (_isViewLoaded == YES && aView == nil);
[self _registerOrUnregister:NO notificationsForView:_view];
[self _registerOrUnregister:YES notificationsForView:aView];
if (willChangeIsViewLoaded)
[self willChangeValueForKey:"isViewLoaded"];
@@ -271,6 +419,30 @@ var CPViewControllerCachedCibs;
return NO;
}
- (void)_registerOrUnregister:(BOOL)shouldRegister notificationsForView:(CPView)aView
{
if (aView === nil)
return;
var center = [CPNotificationCenter defaultCenter],
notifs_to_sel = @{_CPViewWillAppearNotification : @"viewWillAppear",
_CPViewDidAppearNotification : @"viewDidAppear",
_CPViewWillDisappearNotification : @"viewWillDisappear",
_CPViewDidDisappearNotification : @"viewDidDisappear"};
[notifs_to_sel enumerateKeysAndObjectsUsingBlock:function(notif, selString, stop)
{
var selector = CPSelectorFromString(selString);
if ([self implementsSelector:selector])
{
if (shouldRegister)
[center addObserver:self selector:selector name:notif object:aView];
else
[center removeObserver:self name:notif object:aView];
}
}];
}
@end
+315 -174
View File
@@ -54,6 +54,7 @@
@class CPToolbar
@class CPWindowController
@class _CPWindowFrameAnimation
@class _CPWindowFrameAnimationDelegate
@global CPApp
@global _CPPlatformWindowWillCloseNotification
@@ -178,7 +179,7 @@ var CPWindowActionMessageKeys = [
BOOL _isVisible;
BOOL _hasBeenOrderedIn @accessors;
BOOL _isMiniaturized;
BOOL _isAnimating;
BOOL _isAnimating @accessors(setter=_setAnimating:);
BOOL _hasShadow;
BOOL _isMovableByWindowBackground;
BOOL _isMovable;
@@ -198,8 +199,13 @@ var CPWindowActionMessageKeys = [
CPView _contentView;
CPView _toolbarView;
BOOL _handlingTrackingAreaEvent;
BOOL _restartHandlingTrackingAreaEvent;
CPArray _previousMouseEnteredStack;
CPArray _previousCursorUpdateStack;
CPArray _mouseEnteredStack;
CPArray _cursorUpdateStack;
CPArray _queuedEvents;
CPArray _trackingAreaViews;
id _activeCursorTrackingArea;
CPArray _queuedTrackingEvents;
@@ -256,6 +262,7 @@ var CPWindowActionMessageKeys = [
CPWindow _parentView;
BOOL _isSheet;
_CPWindowFrameAnimation _frameAnimation;
_CPWindowFrameAnimationDelegate _frameAnimationDelegate;
}
+ (Class)_binderClassForBinding:(CPString)aBinding
@@ -303,7 +310,7 @@ CPTexturedBackgroundWindowMask
[self setPlatformWindow:[CPPlatformWindow primaryPlatformWindow]];
else
{
// give zero sized borderless bridge windows a default size if we're not in the browser so they show up in NativeHost.
// give zero sized borderless bridge windows a default size.
if ((aStyleMask & CPBorderlessBridgeWindowMask) && aContentRect.size.width === 0 && aContentRect.size.height === 0)
{
var visibleFrame = [[[CPScreen alloc] init] visibleFrame];
@@ -331,6 +338,8 @@ CPTexturedBackgroundWindowMask
_isSheet = NO;
_sheetContext = nil;
_parentView = nil;
_frameAnimation = nil;
_frameAnimationDelegate = nil;
// Set up our window number.
_windowNumber = [CPApp._windows count];
@@ -340,9 +349,14 @@ CPTexturedBackgroundWindowMask
[self setLevel:CPNormalWindowLevel];
_handlingTrackingAreaEvent = NO;
_restartHandlingTrackingAreaEvent = NO;
_trackingAreaViews = [];
_previousMouseEnteredStack = [];
_previousCursorUpdateStack = [];
_mouseEnteredStack = [];
_cursorUpdateStack = [];
_queuedEvents = [];
_queuedTrackingEvents = [];
_activeCursorTrackingArea = nil;
@@ -645,7 +659,6 @@ CPTexturedBackgroundWindowMask
CPBorderlessWindowMask
CPTitledWindowMask
CPClosableWindowMask
CPMiniaturizableWindowMask (NOTE: only available in NativeHost)
CPResizableWindowMask
CPTexturedBackgroundWindowMask
CPBorderlessBridgeWindowMask
@@ -733,7 +746,7 @@ CPTexturedBackgroundWindowMask
{
[_frameAnimation stopAnimation];
_frameAnimation = [[_CPWindowFrameAnimation alloc] initWithWindow:self targetFrame:frame];
[_frameAnimation setDelegate:[self _frameAnimationDelegate]];
[_frameAnimation startAnimation];
}
else
@@ -793,6 +806,13 @@ CPTexturedBackgroundWindowMask
[_platformWindow setContentRect:aFrame];
}
- (id)_frameAnimationDelegate
{
if (_frameAnimationDelegate == nil)
_frameAnimationDelegate = [[_CPWindowFrameAnimationDelegate alloc] initWithWindow:self];
return _frameAnimationDelegate;
}
/*
Constrain a frame so that the window remains at least partially visible on screen,
moving or resizing the frame as necessary.
@@ -1831,16 +1851,12 @@ CPTexturedBackgroundWindowMask
// CPLeftMouseDown is needed for window moving and resizing to work.
// CPMouseMoved is needed for rollover effects on title bar buttons.
if (sheet)
if (sheet && _sheetContext["isAttached"])
{
switch (type)
{
case CPLeftMouseDown:
// This is needed when a doubleClick occurs when the sheet is closing or opening
if (!_parentWindow)
return;
[_windowView mouseDown:anEvent];
// -dw- if the window is clicked, the sheet should come to front, and become key,
@@ -1883,7 +1899,7 @@ CPTexturedBackgroundWindowMask
// Make sure the browser doesn't try to do its own tab handling.
// This is important or the browser might blur the shared text field or token field input field,
// even that we just moved it to a new first responder.
[[[anEvent window] platformWindow] _propagateCurrentDOMEvent:NO]
[[[anEvent window] platformWindow] _propagateCurrentDOMEvent:NO];
#endif
return;
}
@@ -1897,7 +1913,7 @@ CPTexturedBackgroundWindowMask
// Make sure the browser doesn't try to do its own tab handling.
// This is important or the browser might blur the shared text field or token field input field,
// even that we just moved it to a new first responder.
[[[anEvent window] platformWindow] _propagateCurrentDOMEvent:NO]
[[[anEvent window] platformWindow] _propagateCurrentDOMEvent:NO];
#endif
}
@@ -1980,7 +1996,7 @@ CPTexturedBackgroundWindowMask
// First, we search for any tracking area requesting CPTrackingEnabledDuringMouseDrag.
// At the same time, we update the entered stack.
[self _handleTrackingAreaEvent:anEvent];
// Normal mouseDragged workflow
if (!_leftMouseDownView)
return [[_windowView hitTest:point] mouseDragged:anEvent];
@@ -1989,13 +2005,13 @@ CPTexturedBackgroundWindowMask
if (type == CPRightMouseDragged)
{
selector = @selector(rightMouseDragged:)
selector = @selector(rightMouseDragged:);
if (![_leftMouseDownView respondsToSelector:selector])
selector = nil;
}
if (!selector)
selector = @selector(mouseDragged:)
selector = @selector(mouseDragged:);
return [_leftMouseDownView performSelector:selector withObject:anEvent];
@@ -2004,11 +2020,30 @@ CPTexturedBackgroundWindowMask
// Ignore mouse moves for parents of sheets
if (!_acceptsMouseMovedEvents || sheet)
return;
[self _handleTrackingAreaEvent:anEvent];
}
}
- (void)_startLiveResize
{
[[CPNotificationCenter defaultCenter]
postNotificationName:CPWindowWillStartLiveResizeNotification
object:self];
}
- (void)_endLiveResize
{
[[CPNotificationCenter defaultCenter]
postNotificationName:CPWindowDidEndLiveResizeNotification
object:self];
}
- (BOOL)_inLiveResize
{
return [_windowView _isTracking];
}
/*!
Returns the window's number in the desktop's screen list
*/
@@ -3759,13 +3794,6 @@ var interpolate = function(fromValue, toValue, progress)
return self;
}
- (void)startAnimation
{
[super startAnimation];
_window._isAnimating = YES;
}
- (void)setCurrentProgress:(float)aProgress
{
[super setCurrentProgress:aProgress];
@@ -3773,7 +3801,7 @@ var interpolate = function(fromValue, toValue, progress)
var value = [self currentValue];
if (value == 1.0)
_window._isAnimating = NO;
[_window _setAnimating:NO];
var newFrame = CGRectMake(
interpolate(CGRectGetMinX(_startFrame), CGRectGetMinX(_targetFrame), value),
@@ -3786,6 +3814,41 @@ var interpolate = function(fromValue, toValue, progress)
@end
@implementation _CPWindowFrameAnimationDelegate : CPObject
{
CPWindow _window;
}
- (id)initWithWindow:(CPWindow)aWindow
{
self = [super init];
_window = aWindow;
return self;
}
- (BOOL)animationShouldStart:(CPAnimation)animation
{
[_window _setAnimating:YES];
[_window _startLiveResize];
return YES;
}
- (void)animationDidStop:(CPAnimation)animation
{
[_window _setAnimating:NO];
[_window _endLiveResize];
}
- (void)animationDidEnd:(CPAnimation)animation
{
[_window _setAnimating:NO];
[_window _endLiveResize];
}
@end
@implementation CPWindow (CPDraggingAdditions)
@@ -3824,7 +3887,7 @@ var interpolate = function(fromValue, toValue, progress)
- (void)_addTrackingAreaView:(CPView)aView
{
var trackingAreas = [aView trackingAreas];
for (var i = 0; i < trackingAreas.length; i++)
[self _addTrackingArea:trackingAreas[i]];
}
@@ -3832,7 +3895,7 @@ var interpolate = function(fromValue, toValue, progress)
- (void)_removeTrackingAreaView:(CPView)aView
{
var trackingAreas = [aView trackingAreas];
for (var i = 0; i < trackingAreas.length; i++)
[self _removeTrackingArea:trackingAreas[i]];
}
@@ -3840,63 +3903,143 @@ var interpolate = function(fromValue, toValue, progress)
- (void)_addTrackingArea:(CPTrackingArea)trackingArea
{
var trackingAreaView = [trackingArea view];
if (![_trackingAreaViews containsObjectIdenticalTo:trackingAreaView])
[_trackingAreaViews addObject:trackingAreaView];
// If CPTrackingAssumeInside option is set, put the tracking area in the _mouseEnteredStack
if ([trackingArea options] & CPTrackingAssumeInside)
[_mouseEnteredStack addObject:trackingArea];
// If CPTrackingAssumeInside option is set, insert the tracking area in the events management system
// in order to have the first event sent only when mouse leaves the tracking area
[self _insertTrackingArea:trackingArea assumeInside:([trackingArea options] & CPTrackingAssumeInside)];
}
- (void)_removeTrackingArea:(CPTrackingArea)trackingArea
{
// If mouse is in the tracking area, we remove it from the stack to avoid to fire a future mouseExited event
[_mouseEnteredStack removeObjectIdenticalTo:trackingArea];
[self _purgeTrackingArea:trackingArea];
var trackingAreaView = [trackingArea view];
[_trackingAreaViews removeObjectIdenticalTo:trackingAreaView];
}
- (void)_insertTrackingArea:(CPTrackingArea)trackingArea assumeInside:(BOOL)assumeInside
{
if (_handlingTrackingAreaEvent)
_restartHandlingTrackingAreaEvent = YES;
if (assumeInside)
{
if (_handlingTrackingAreaEvent)
[_mouseEnteredStack addObject:trackingArea];
else
[_previousMouseEnteredStack addObject:trackingArea];
}
}
- (void)_purgeTrackingArea:(CPTrackingArea)trackingArea
{
if (_handlingTrackingAreaEvent)
{
[_mouseEnteredStack removeObjectIdenticalTo:trackingArea];
var i = _queuedEvents.length;
while (i--)
if ([_queuedEvents[i] trackingArea] === trackingArea)
[_queuedEvents removeObjectAtIndex:i];
_cursorUpdateStack = [];
_activeCursorTrackingArea = nil;
}
else
{
[_previousMouseEnteredStack removeObjectIdenticalTo:trackingArea];
[_previousCursorUpdateStack removeObjectIdenticalTo:trackingArea];
}
}
- (void)_handleTrackingAreaEvent:(CPEvent)anEvent
{
var mouseEnteredStack = [],
cursorUpdateStack = [],
point = [anEvent locationInWindow],
dragging = ([anEvent type] !== CPMouseMoved);
_handlingTrackingAreaEvent = YES;
// Handle mouse entering tracking areas (and calc mouseEnteredStack and cursorUpdateStack)
[self _handleMouseMovedAndEnteredEventsForEvent:anEvent atPoint:point dragging:dragging mouseEnteredStack:mouseEnteredStack cursorUpdateStack:cursorUpdateStack];
var point = [anEvent locationInWindow],
dragging = ([anEvent type] !== CPMouseMoved);
// Handle mouse exiting tracking areas
[self _handleMouseExitedEventsForEvent:anEvent atPoint:point dragging:dragging mouseEnteredStack:mouseEnteredStack];
// Cursor update
if (cursorUpdateStack.length > 0)
do
{
[self _handleCursorUpdateEventsForEvent:anEvent atPoint:point dragging:dragging cursorUpdateStack:cursorUpdateStack];
}
else if (!dragging)
{
// Here, we are outsite the window content view tracking area, so let _windowView set the cursor (resize cursor, ...)
// Initialize this run
_restartHandlingTrackingAreaEvent = NO;
[_windowView setCursorForLocation:point resizing:NO];
_activeCursorTrackingArea = nil;
}
_mouseEnteredStack = [];
_cursorUpdateStack = [];
// Prepare for next call
_mouseEnteredStack = mouseEnteredStack;
_cursorUpdateStack = cursorUpdateStack;
// Important remark: we must queue events to avoid running conditions when a view uses a mouse event to modify view hierarchy
_queuedEvents = [];
// Handle mouse entering tracking areas (and calc _mouseEnteredStack and _cursorUpdateStack)
[self _handleMouseMovedAndEnteredEventsForEvent:anEvent atPoint:point dragging:dragging];
// Handle mouse exiting tracking areas
[self _handleMouseExitedEventsForEvent:anEvent atPoint:point dragging:dragging];
// Cursor update
if (_cursorUpdateStack.length > 0)
{
[self _handleCursorUpdateEventsForEvent:anEvent atPoint:point dragging:dragging];
}
else if (!dragging)
{
// Here, we are outside the window content view tracking area, so let _windowView set the cursor (resize cursor, ...)
[_windowView setCursorForLocation:point resizing:NO];
_activeCursorTrackingArea = nil;
}
// Send all queued events
// Important remark : as an event can modify the view hierarchy, the events queue could be modified while processing it
while (_queuedEvents.length > 0)
{
var queuedEvent = _queuedEvents[0],
trackingArea = [queuedEvent trackingArea],
trackingOwner = [trackingArea owner];
switch ([queuedEvent type])
{
case CPMouseEntered:
[trackingOwner mouseEntered:queuedEvent];
break;
case CPMouseExited:
[trackingOwner mouseExited:queuedEvent];
break;
case CPCursorUpdate:
[trackingOwner cursorUpdate:queuedEvent];
break;
}
if (queuedEvent === _queuedEvents[0])
[_queuedEvents removeObjectAtIndex:0];
}
// Prepare for next call
_previousMouseEnteredStack = _mouseEnteredStack;
_previousCursorUpdateStack = _cursorUpdateStack;
}
while (_restartHandlingTrackingAreaEvent)
_handlingTrackingAreaEvent = NO;
}
- (void)_handleMouseMovedAndEnteredEventsForEvent:(CPEvent)anEvent atPoint:(CGPoint)point dragging:(BOOL)dragging mouseEnteredStack:(CPArray)mouseEnteredStack cursorUpdateStack:(CPArray)cursorUpdateStack
- (void)_handleMouseMovedAndEnteredEventsForEvent:(CPEvent)anEvent atPoint:(CGPoint)point dragging:(BOOL)dragging
{
var isKeyWindow = [self isKeyWindow];
@@ -3923,9 +4066,9 @@ var interpolate = function(fromValue, toValue, progress)
continue;
}
[mouseEnteredStack addObject:aTrackingArea];
[_mouseEnteredStack addObject:aTrackingArea];
if ([_mouseEnteredStack containsObjectIdenticalTo:aTrackingArea])
if ([_previousMouseEnteredStack containsObjectIdenticalTo:aTrackingArea])
{
// Mouse was already in this rect so it's a mouseMoved
@@ -3946,32 +4089,33 @@ var interpolate = function(fromValue, toValue, progress)
if (dragging && !(trackingOptions & CPTrackingEnabledDuringMouseDrag))
[self _queueTrackingEvent:mouseEnteredEvent];
else
[[aTrackingArea owner] mouseEntered:mouseEnteredEvent];
[_queuedEvents addObject:mouseEnteredEvent];
}
if ((trackingOptions & CPTrackingCursorUpdate) && (trackingImplementedMethods & CPTrackingOwnerImplementsCursorUpdate))
[cursorUpdateStack addObject:aTrackingArea];
[_cursorUpdateStack addObject:aTrackingArea];
}
}
}
- (void)_handleMouseExitedEventsForEvent:(CPEvent)anEvent atPoint:(CGPoint)point dragging:(BOOL)dragging mouseEnteredStack:(CPArray)mouseEnteredStack
- (void)_handleMouseExitedEventsForEvent:(CPEvent)anEvent atPoint:(CGPoint)point dragging:(BOOL)dragging
{
// Search for exited views (were in _mouseEnteredStack but no more in mouseEnteredStack)
// Search for exited views (were in _previousMouseEnteredStack but no more in _mouseEnteredStack)
for (var i = 0; i < _mouseEnteredStack.length; i++)
for (var i = 0; i < _previousMouseEnteredStack.length; i++)
{
var aTrackingArea = _mouseEnteredStack[i],
var aTrackingArea = _previousMouseEnteredStack[i],
trackingOptions = [aTrackingArea options];
if ([mouseEnteredStack containsObjectIdenticalTo:aTrackingArea])
if ([_mouseEnteredStack containsObjectIdenticalTo:aTrackingArea])
continue;
// Mouse is no more in this area so it's a mouseExited
if ((trackingOptions & CPTrackingMouseEnteredAndExited) && ([aTrackingArea implementedOwnerMethods] & CPTrackingOwnerImplementsMouseExited))
{
var mouseExitedEvent = [CPEvent enterExitEventWithType:CPMouseExited
var theView = [aTrackingArea owner],
mouseExitedEvent = [CPEvent enterExitEventWithType:CPMouseExited
location:point
modifierFlags:[anEvent modifierFlags]
timestamp:[anEvent timestamp]
@@ -3983,132 +4127,130 @@ var interpolate = function(fromValue, toValue, progress)
if (dragging && !(trackingOptions & CPTrackingEnabledDuringMouseDrag))
[self _queueTrackingEvent:mouseExitedEvent];
else
[[aTrackingArea owner] mouseExited:mouseExitedEvent];
[_queuedEvents addObject:mouseExitedEvent];
}
// If this is the active cursor area, we reset _cursorUpdateStack so a new active area will be computed
// If this is the active cursor area, we reset _previousCursorUpdateStack so a new active area will be computed
if (aTrackingArea === _activeCursorTrackingArea)
{
_cursorUpdateStack = [];
_previousCursorUpdateStack = [];
_activeCursorTrackingArea = nil;
}
}
}
- (void)_handleCursorUpdateEventsForEvent:(CPEvent)anEvent atPoint:(CGPoint)point dragging:(BOOL)dragging cursorUpdateStack:(CPArray)cursorUpdateStack
- (void)_handleCursorUpdateEventsForEvent:(CPEvent)anEvent atPoint:(CGPoint)point dragging:(BOOL)dragging
{
var overlappingTrackingAreas = [];
for (var i = 0; i < cursorUpdateStack.length; i++)
for (var i = 0; i < _cursorUpdateStack.length; i++)
{
var aTrackingArea = cursorUpdateStack[i];
var aTrackingArea = _cursorUpdateStack[i];
if ((![_cursorUpdateStack containsObjectIdenticalTo:aTrackingArea]) || (aTrackingArea === _activeCursorTrackingArea))
if ((![_previousCursorUpdateStack containsObjectIdenticalTo:aTrackingArea]) || (aTrackingArea === _activeCursorTrackingArea))
[overlappingTrackingAreas addObject:aTrackingArea];
}
var nbOverlappingTrackingAreas = overlappingTrackingAreas.length;
if (overlappingTrackingAreas.length === 0)
return;
if (nbOverlappingTrackingAreas > 0)
var frontmostTrackingArea = overlappingTrackingAreas[0],
frontmostView = [frontmostTrackingArea view];
for (var i = 1; i < overlappingTrackingAreas.length; i++)
{
var frontmostTrackingArea = overlappingTrackingAreas[0],
frontmostView = [frontmostTrackingArea view];
var aTrackingArea = overlappingTrackingAreas[i],
aView = [aTrackingArea view];
for (var i = 1; i < nbOverlappingTrackingAreas; i++)
// First, if aView is _windowView, skip to next overlapping tracking area
// as _windowView can't be the frontmost view if there's multiple overlapping tracking areas.
if (aView === _windowView)
continue;
// Then, if frontmostView is _windowView, aView must become frontmostView
if (frontmostView === _windowView)
{
var aTrackingArea = overlappingTrackingAreas[i],
aView = [aTrackingArea view];
frontmostTrackingArea = aTrackingArea;
frontmostView = aView;
// First, if aView is _windowView, skip to next overlapping tracking area
// as _windowView can't be the frontmost view if there's multiple overlapping tracking areas.
if (aView === _windowView)
continue;
// Then, if frontmostView is _windowView, aView must become frontmostView
if (frontmostView === _windowView)
{
frontmostTrackingArea = aTrackingArea;
frontmostView = aView;
continue;
}
// Next verify if aView is a subview of frontmostView
// If so, it's our new frontmost view
var searchingView = aView;
while ((searchingView !== _contentView) && ([searchingView superview] !== frontmostView))
searchingView = [searchingView superview];
if (searchingView !== _contentView)
{
frontmostTrackingArea = aTrackingArea;
frontmostView = aView;
continue;
}
// aView is not a subview of frontmostView
// Search in view hierarchy which one will be over the other
// (this is done by comparing their draw order)
var firstView = frontmostView,
firstSuperview = [firstView superview];
while (firstView !== _contentView)
{
var secondView = aView,
secondSuperview = [secondView superview];
while ((secondSuperview !== _contentView) && (firstSuperview !== secondSuperview))
{
secondView = secondSuperview;
secondSuperview = [secondView superview];
}
if (firstSuperview === secondSuperview)
break;
firstView = firstSuperview;
firstSuperview = [firstView superview];
}
if (firstSuperview !== secondSuperview)
[CPException raise:CPInternalInconsistencyException reason:"Problem with view hierarchy"];
var firstSuperviewSubviews = [firstSuperview subviews],
firstViewIndex = [firstSuperviewSubviews indexOfObject:firstView],
secondViewIndex = [firstSuperviewSubviews indexOfObject:secondView];
if (secondViewIndex > firstViewIndex)
{
frontmostTrackingArea = aTrackingArea;
frontmostView = aView;
}
continue;
}
if (frontmostTrackingArea !== _activeCursorTrackingArea)
// Next verify if aView is a subview of frontmostView
// If so, it's our new frontmost view
var searchingView = aView;
while ((searchingView !== _contentView) && ([searchingView superview] !== frontmostView))
searchingView = [searchingView superview];
if (searchingView !== _contentView)
{
var cursorUpdateEvent = [CPEvent enterExitEventWithType:CPCursorUpdate
location:point
modifierFlags:[anEvent modifierFlags]
timestamp:[anEvent timestamp]
windowNumber:_windowNumber
context:nil
eventNumber:-1
trackingArea:frontmostTrackingArea];
frontmostTrackingArea = aTrackingArea;
frontmostView = aView;
if (dragging)
[self _queueTrackingEvent:cursorUpdateEvent];
else
[[frontmostTrackingArea owner] cursorUpdate:cursorUpdateEvent];
_activeCursorTrackingArea = frontmostTrackingArea;
continue;
}
// aView is not a subview of frontmostView
// Search in view hierarchy which one will be over the other
// (this is done by comparing their draw order)
var firstView = frontmostView,
firstSuperview = [firstView superview];
while (firstView !== _contentView)
{
var secondView = aView,
secondSuperview = [secondView superview];
while ((secondSuperview !== _contentView) && (firstSuperview !== secondSuperview))
{
secondView = secondSuperview;
secondSuperview = [secondView superview];
}
if (firstSuperview === secondSuperview)
break;
firstView = firstSuperview;
firstSuperview = [firstView superview];
}
if (firstSuperview !== secondSuperview)
[CPException raise:CPInternalInconsistencyException reason:"Problem with view hierarchy"];
var firstSuperviewSubviews = [firstSuperview subviews],
firstViewIndex = [firstSuperviewSubviews indexOfObject:firstView],
secondViewIndex = [firstSuperviewSubviews indexOfObject:secondView];
if (secondViewIndex > firstViewIndex)
{
frontmostTrackingArea = aTrackingArea;
frontmostView = aView;
}
}
if (frontmostTrackingArea !== _activeCursorTrackingArea)
{
var cursorUpdateEvent = [CPEvent enterExitEventWithType:CPCursorUpdate
location:point
modifierFlags:[anEvent modifierFlags]
timestamp:[anEvent timestamp]
windowNumber:_windowNumber
context:nil
eventNumber:-1
trackingArea:frontmostTrackingArea];
if (dragging)
[self _queueTrackingEvent:cursorUpdateEvent];
else
[_queuedEvents addObject:cursorUpdateEvent];
_activeCursorTrackingArea = frontmostTrackingArea;
}
}
@@ -4116,12 +4258,11 @@ var interpolate = function(fromValue, toValue, progress)
{
// This will put a tracking event in the _queuedTrackingEvents queue.
//
// We optimize this queue with this policy :
// We optimize this queue with this policy:
// - if mouseEntered, search if queue contains a previous mouseExited for the same tracking area. If so, discard both.
// - if mouseExited, search if queue contains a previous mouseEntered for the same tracking area. If so, discard both.
//
// This is not Cocoa way of doing as it would send every event.
// But final result should be the same.
// This is not the Cocoa way of doing as it would send every event, but the final result should be the same.
var eventType = [anEvent type],
trackingArea = [anEvent trackingArea];
@@ -4181,7 +4322,7 @@ var interpolate = function(fromValue, toValue, progress)
case CPMouseExited:
[trackingOwner mouseExited:queuedEvent];
break;
case CPCursorUpdate:
[trackingOwner updateTrackingAreas];
+2
View File
@@ -176,6 +176,8 @@ CPWindowDidEndSheetNotification = @"CPWindowDidEndSheetNotificat
CPWindowDidMiniaturizeNotification = @"CPWindowDidMiniaturizeNotification";
CPWindowWillMiniaturizeNotification = @"CPWindowWillMiniaturizeNotification";
CPWindowDidDeminiaturizeNotification = @"CPWindowDidDeminiaturizeNotification";
CPWindowWillStartLiveResizeNotification = @"CPWindowWillStartLiveResizeNotification";
CPWindowDidEndLiveResizeNotification = @"CPWindowDidEndLiveResizeNotification";
_CPWindowDidChangeFirstResponderNotification = @"_CPWindowDidChangeFirstResponderNotification";
@@ -29,7 +29,7 @@
+ (CPString)defaultThemeClass
{
return @"bordeless-bridge-window-view";
return @"borderless-bridge-window-view";
}
+ (CPDictionary)themeAttributes
+1 -1
View File
@@ -183,7 +183,7 @@
if (_styleMask & CPClosableWindowMask)
{
[_closeButton setFrameOrigin:[self valueForThemeAttribute:@"close-image-origin"]];
[_closeButton setFrameSize:[self valueForThemeAttribute:@"close-image-size"]]
[_closeButton setFrameSize:[self valueForThemeAttribute:@"close-image-size"]];
[_closeButton setImage:[self valueForThemeAttribute:@"close-image"]];
[_closeButton setAlternateImage:[self valueForThemeAttribute:@"close-active-image"]];
}
+23 -6
View File
@@ -64,6 +64,8 @@ _CPWindowViewResizeSlop = 3;
CGRect _cachedScreenFrame;
CPView _sheetShadowView;
BOOL _isTracking @accessors(getter=_isTracking);
}
+ (CGRect)contentRectForFrameRect:(CGRect)aFrameRect
@@ -148,6 +150,7 @@ _CPWindowViewResizeSlop = 3;
_styleMask = aStyleMask;
_resizeIndicatorOffset = CGSizeMakeZero();
_toolbarOffset = CGSizeMakeZero();
_isTracking = NO;
}
return self;
@@ -458,6 +461,8 @@ _CPWindowViewResizeSlop = 3;
if (type === CPLeftMouseUp)
{
_cachedScreenFrame = nil;
_isTracking = NO;
[_window _endLiveResize];
return;
}
@@ -474,6 +479,12 @@ _CPWindowViewResizeSlop = 3;
}
else if (type === CPLeftMouseDragged)
{
if (!_isTracking)
{
_isTracking = YES;
[_window _startLiveResize];
}
var deltaX = globalLocation.x - _mouseDraggedPoint.x,
deltaY = globalLocation.y - _mouseDraggedPoint.y,
startX = CGRectGetMinX(_cachedFrame),
@@ -973,16 +984,22 @@ _CPWindowViewResizeSlop = 3;
@end
@implementation _CPWindowView (TrackingAreaAdditions)
{
CPTrackingArea _windowViewTrackingArea;
}
- (void)updateTrackingAreas
{
[self removeAllTrackingAreas];
if (_windowViewTrackingArea)
[self removeTrackingArea:_windowViewTrackingArea];
[self addTrackingArea:[[CPTrackingArea alloc] initWithRect:[self contentRectForFrameRect:[self frame]]
options:CPTrackingCursorUpdate | CPTrackingActiveInActiveApp
owner:self
userInfo:nil]];
_windowViewTrackingArea = [[CPTrackingArea alloc] initWithRect:[self contentRectForFrameRect:[self frame]]
options:CPTrackingCursorUpdate | CPTrackingActiveInActiveApp
owner:self
userInfo:nil];
[self addTrackingArea:_windowViewTrackingArea];
[super updateTrackingAreas];
}
@end
+1 -1
View File
@@ -364,7 +364,7 @@
{
[viewControllerView removeFromSuperview];
[viewControllerView setFrame:[contentView frame]];
[viewControllerView setAutoresizingMask:[contentView autoresizingMask]]
[viewControllerView setAutoresizingMask:[contentView autoresizingMask]];
[[self window] setContentView:viewControllerView];
}
else
+12
View File
@@ -55,6 +55,18 @@ var CPCibObjectDataKey = @"CPCibObjectDataKey";
id _loadDelegate;
}
- (id)_initWithData:(CPData)data bundle:(CPBundle)aBundle cibName:(CPString)aCibName
{
self = [super init];
_data = data;
_cibName = aCibName;
_bundle = aBundle;
_awakenCustomResources = YES;
return self;
}
- (id)initWithContentsOfURL:(CPURL)aURL
{
self = [super init];
+25
View File
@@ -222,3 +222,28 @@ var _CPCibCustomResourceClassNameKey = @"_CPCibCustomResourceClassNameKey",
}
@end
@implementation _CPCibCustomResource (CSSTheming)
- (BOOL)isCSSBased
{
return NO;
}
- (BOOL)hasCSSDictionary
{
return NO;
}
- (BOOL)hasCSSBeforeDictionary
{
return NO;
}
- (BOOL)hasCSSAfterDictionary
{
return NO;
}
@end
+1 -1
View File
@@ -230,7 +230,7 @@ var _CPCibObjectDataNamesKeysKey = @"_CPCibObjectDataNamesKeysKey
if ([object respondsToSelector:@selector(_cibInstantiate)])
{
var instantiatedObject = [object _cibInstantiate];
instantiatedObject = [object _cibInstantiate];
if (instantiatedObject !== object)
{
+10 -133
View File
@@ -30,8 +30,10 @@
*/
@implementation CAAnimation : CPObject
{
BOOL _isRemovedOnCompletion;
id _delegate;
BOOL _isRemovedOnCompletion;
id _delegate;
CAMediaTimingFunction _timingFunction @accessors(property=timingFunction);
double _duration @accessors(property=duration);
}
/*!
@@ -47,8 +49,10 @@
{
self = [super init];
if (self)
_isRemovedOnCompletion = YES;
_isRemovedOnCompletion = YES;
_timingFunction = nil;
_duration = 0.0;
_delegate = nil;
return self;
}
@@ -102,7 +106,7 @@
- (CAMediaTimingFunction)timingFunction
{
// Linear Pacing
return nil;
return _timingFunction;
}
/*!
@@ -127,131 +131,4 @@
[anObject addAnimation:self forKey:aKey];
}
@end
/*
*/
@implementation CAPropertyAnimation : CAAnimation
{
CPString _keyPath;
BOOL _isCumulative;
BOOL _isAdditive;
}
+ (id)animationWithKeyPath:(CPString)aKeyPath
{
var animation = [self animation];
[animation setKeyPath:aKeyPath];
return animation;
}
- (void)setKeyPath:(CPString)aKeyPath
{
_keyPath = aKeyPath;
}
- (CPString)keyPath
{
return _keyPath;
}
- (void)setCumulative:(BOOL)isCumulative
{
_isCumulative = isCumulative;
}
- (BOOL)cumulative
{
return _isCumulative;
}
- (BOOL)isCumulative
{
return _isCumulative;
}
- (void)setAdditive:(BOOL)isAdditive
{
_isAdditive = isAdditive;
}
- (BOOL)additive
{
return _isAdditive;
}
- (BOOL)isAdditive
{
return _isAdditive;
}
@end
/*!
A CABasicAnimation is a simple animation that moves a
CALayer from one point to another over a specified
period of time.
*/
@implementation CABasicAnimation : CAPropertyAnimation
{
id _fromValue;
id _toValue;
id _byValue;
}
/*!
Sets the starting position for the animation.
@param aValue the animation starting position
*/
- (void)setFromValue:(id)aValue
{
_fromValue = aValue;
}
/*!
Returns the animation's starting position.
*/
- (id)fromValue
{
return _fromValue;
}
/*!
Sets the ending position for the animation.
@param aValue the animation ending position
*/
- (void)setToValue:(id)aValue
{
_toValue = aValue;
}
/*!
Returns the animation's ending position.
*/
- (id)toValue
{
return _toValue;
}
/*!
Sets the optional byValue for animation interpolation.
@param aValue the byValue
*/
- (void)setByValue:(id)aValue
{
_byValue = aValue;
}
/*!
Returns the animation's byValue.
*/
- (id)byValue
{
return _byValue;
}
@end
@end
+84
View File
@@ -0,0 +1,84 @@
@import <Foundation/CPObject.j>
@import "CAPropertyAnimation.j"
/*!
A CABasicAnimation is a simple animation that moves a
CALayer from one point to another over a specified
period of time.
*/
/*!
A CABasicAnimation is a simple animation that moves a
CALayer from one point to another over a specified
period of time.
*/
@implementation CABasicAnimation : CAPropertyAnimation
{
id _fromValue;
id _toValue;
id _byValue;
}
- (id)init
{
self = [super init];
_fromValue = nil;
_toValue = nil;
_byValue = nil;
return self;
}
/*!
Sets the starting position for the animation.
@param aValue the animation starting position
*/
- (void)setFromValue:(id)aValue
{
_fromValue = aValue;
}
/*!
Returns the animation's starting position.
*/
- (id)fromValue
{
return _fromValue;
}
/*!
Sets the ending position for the animation.
@param aValue the animation ending position
*/
- (void)setToValue:(id)aValue
{
_toValue = aValue;
}
/*!
Returns the animation's ending position.
*/
- (id)toValue
{
return _toValue;
}
/*!
Sets the optional byValue for animation interpolation.
@param aValue the byValue
*/
- (void)setByValue:(id)aValue
{
_byValue = aValue;
}
/*!
Returns the animation's byValue.
*/
- (id)byValue
{
return _byValue;
}
@end
@@ -0,0 +1,23 @@
@import <Foundation/CPObject.j>
@import "CAPropertyAnimation.j"
@implementation CAKeyframeAnimation : CAPropertyAnimation
{
CPArray _values @accessors(property=values);
CPArray _keyTimes @accessors(property=keyTimes);
CPArray _timingFunctions @accessors(property=timingFunctions);
}
- (id)init
{
self = [super init];
_values = [CPArray array];
_keyTimes = [CPArray array];
_timingFunctions = [CPArray array];
return self;
}
@end
+1 -1
View File
@@ -522,7 +522,7 @@ var CALayerRegisteredRunLoopUpdates = nil;
if (USE_BUFFER)
{
if (_delegateRespondsToDisplayLayerSelector)
return [_delegate displayInLayer:self];
return [_delegate displayLayer:self];
if (CGRectGetWidth(_backingStoreFrame) == 0.0 || CGRectGetHeight(_backingStoreFrame) == 0.0)
return;
@@ -0,0 +1,74 @@
@import <Foundation/CPObject.j>
@import "CAAnimation.j"
@implementation CAPropertyAnimation : CAAnimation
{
CPString _keyPath;
BOOL _isCumulative;
BOOL _isAdditive;
}
- (id)init
{
self = [super init];
_keyPath = nil;
_isCumulative = NO;
_isAdditive = NO;
return self;
}
+ (id)animationWithKeyPath:(CPString)aKeyPath
{
var animation = [self animation];
[animation setKeyPath:aKeyPath];
return animation;
}
- (void)setKeyPath:(CPString)aKeyPath
{
_keyPath = aKeyPath;
}
- (CPString)keyPath
{
return _keyPath;
}
- (void)setCumulative:(BOOL)isCumulative
{
_isCumulative = isCumulative;
}
- (BOOL)cumulative
{
return _isCumulative;
}
- (BOOL)isCumulative
{
return _isCumulative;
}
- (void)setAdditive:(BOOL)isAdditive
{
_isAdditive = isAdditive;
}
- (BOOL)additive
{
return _isAdditive;
}
- (BOOL)isAdditive
{
return _isAdditive;
}
@end
+560
View File
@@ -0,0 +1,560 @@
@import "CABasicAnimation.j"
@import "CAKeyframeAnimation.j"
@import "CPView.j"
@import <Foundation/CPTimer.j>
@import <Foundation/CPRunLoop.j>
@typedef Map;
var _CPAnimationContextStack = nil,
_animationFlushingObserver = nil;
@implementation CPAnimationContext : CPObject
{
double _duration @accessors(property=duration);
CAMediaTimingFunction _timingFunction @accessors(property=timingFunction);
Function _completionHandlerAgent;
Map _animationsByObject;
}
+ (id)currentContext
{
var contextStack = [self contextStack],
context = [contextStack lastObject];
if (!context)
{
context = [[CPAnimationContext alloc] init];
[contextStack addObject:context];
[self _scheduleAnimationContextStackFlush];
}
return context;
}
+ (CPArray)contextStack
{
if (!_CPAnimationContextStack)
_CPAnimationContextStack = [CPArray array];
return _CPAnimationContextStack;
}
+ (void)runAnimationGroup:(Function/*(CPAnimationContext context)*/)animationsBlock completionHandler:(Function)aCompletionHandler
{
[CPAnimationContext beginGrouping];
var context = [CPAnimationContext currentContext];
[context setCompletionHandler:aCompletionHandler];
animationsBlock(context);
[CPAnimationContext endGrouping];
}
- (id)init
{
self = [super init];
_duration = 0.0;
_timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
_completionHandlerAgent = nil;
_animationsByObject = new Map();
return self;
}
+ (void)_scheduleAnimationContextStackFlush
{
if (!_animationFlushingObserver)
{
#if (DEBUG)
CPLog.debug("create new observer");
#endif
_animationFlushingObserver = CFRunLoopObserverCreate(2, true, 0, _animationFlushingObserverCallback, 0);
CFRunLoopAddObserver([CPRunLoop mainRunLoop], _animationFlushingObserver);
}
}
+ (void)beginGrouping
{
var newContext = [[CPAnimationContext alloc] init];
if ([_CPAnimationContextStack count])
{
var currentContext = [_CPAnimationContextStack lastObject];
[newContext setDuration:[currentContext duration]];
[newContext setTimingFunction:[currentContext timingFunction]];
}
[_CPAnimationContextStack addObject:newContext];
}
+ (BOOL)endGrouping
{
if (![_CPAnimationContextStack count])
return NO;
var context = [_CPAnimationContextStack lastObject];
[context _flushAnimations];
[_CPAnimationContextStack removeLastObject];
#if (DEBUG)
CPLog.debug(_cmd + "context stack =" + _CPAnimationContextStack);
#endif
return YES;
}
- (void)_enqueueActionForObject:(id)anObject keyPath:(id)aKeyPath targetValue:(id)aTargetValue animationCompletion:(id)animationCompletion
{
var resolvedAction = [self _actionForObject:anObject keyPath:aKeyPath targetValue:aTargetValue animationCompletion:animationCompletion];
if (!resolvedAction)
return;
var animByKeyPath = _animationsByObject.get(anObject);
if (!animByKeyPath)
{
var newAnimByKeyPath = @{aKeyPath:resolvedAction};
_animationsByObject.set(anObject, newAnimByKeyPath);
}
else
[animByKeyPath setObject:resolvedAction forKey:aKeyPath];
}
- (Object)_actionForObject:(id)anObject keyPath:(CPString)aKeyPath targetValue:(id)aTargetValue animationCompletion:(Function)animationCompletion
{
var animation,
duration,
animatedKeyPath,
values,
keyTimes,
timingFunctions,
needsPeriodicFrameUpdates,
objectId = [anObject UID];
if (!aKeyPath || !anObject || !(animation = [anObject animationForKey:aKeyPath]) || ![animation isKindOfClass:[CAAnimation class]])
return nil;
duration = [animation duration] || [self duration];
needsPeriodicFrameUpdates = [[anObject animator] needsPeriodicFrameUpdatesForKeyPath:aKeyPath];
var animatorClass = [[anObject class] animatorClass];
var completionFunction = function()
{
if (needsPeriodicFrameUpdates)
[animatorClass stopUpdaterWithIdentifier:objectId];
if (animationCompletion)
animationCompletion();
if (needsPeriodicFrameUpdates || animationCompletion)
[[CPRunLoop currentRunLoop] performSelectors];
if (_completionHandlerAgent)
_completionHandlerAgent.decrement();
};
if (![animation isKindOfClass:[CAPropertyAnimation class]] || !(animatedKeyPath = [animation keyPath]))
animatedKeyPath = aKeyPath;
if ([animation isKindOfClass:[CAKeyframeAnimation class]])
{
values = [animation values];
keyTimes = [animation keyTimes];
timingFunctions = [animation timingFunctionsControlPoints];
}
else
{
var isBasicAnimation = [animation isKindOfClass:[CABasicAnimation class]],
fromValue,
toValue;
if (!isBasicAnimation || (fromValue = [animation fromValue]) == nil)
fromValue = [anObject valueForKey:animatedKeyPath];
if (!isBasicAnimation || (toValue = [animation toValue]) == nil)
toValue = aTargetValue;
values = [fromValue, toValue];
keyTimes = [0, 1];
timingFunctions = isBasicAnimation ? [animation timingFunctionControlPoints] : [_timingFunction controlPoints];
}
return {
object:anObject,
root:anObject,
keypath:animatedKeyPath,
values:values,
keytimes:keyTimes,
duration:duration,
timingfunctions:timingFunctions,
completion:completionFunction
};
}
- (void)_flushAnimations
{
if (![_CPAnimationContextStack count])
return;
if (_animationsByObject.size == 0)
{
if (_completionHandlerAgent)
{
#if (DEBUG)
CPLog.debug("No animations are scheduled. Firing completion handler");
#endif
_completionHandlerAgent.fire();
}
}
else
[self _startAnimations];
}
- (void)_startAnimations
{
var cssAnimations = [],
timers = [];
_animationsByObject.forEach(function(animByKeyPath, targetView)
{
[animByKeyPath enumerateKeysAndObjectsUsingBlock:function(aKey, anAction, stop)
{
[self getAnimations:cssAnimations getTimers:timers usingAction:anAction cssAnimate:YES];
}];
});
_animationsByObject.clear();
var k = timers.length,
n = cssAnimations.length;
if (_completionHandlerAgent)
{
if (n == 0)
{
#if (DEBUG)
CPLog.debug("Animations are not needed. Firing completion handler");
#endif
_completionHandlerAgent.fire();
}
else
_completionHandlerAgent.increment(n);
}
// start timers
while(k--)
{
#if (DEBUG)
CPLog.debug("START TIMER " + timers[k].description());
#endif
timers[k].start();
}
// start css animations
while(n--)
{
#if (DEBUG)
CPLog.debug("START ANIMATION " + cssAnimations[n].description());
#endif
cssAnimations[n].start();
}
}
- (void)getAnimations:(CPArray)cssAnimations getTimers:(CPArray)timers usingAction:(Object)anAction cssAnimate:(BOOL)needsCSSAnimation
{
var values = anAction.values;
if (values.length == 2)
{
var start = values[0],
end = values[1];
if (anAction.keypath == @"frame" && CGRectEqualToRect(start, end)
|| anAction.keypath == @"frameSize" && CGSizeEqualToSize(start, end)
|| anAction.keypath == @"frameOrigin" && CGPointEqualToPoint(start, end))
return;
}
var targetView = anAction.object,
keyPath = anAction.keypath,
isFrameKeyPath = (keyPath == @"frame" || keyPath == @"frameSize"),
customLayout = [targetView hasCustomLayoutSubviews],
customDrawing = [targetView hasCustomDrawRect],
declarative_subviews_layout = (!customLayout || [targetView implementsSelector:@selector(frameRectOfView:inSuperviewSize:)]),
needsPeriodicFrameUpdates = [[targetView animator] needsPeriodicFrameUpdatesForKeyPath:keyPath],
timer = nil,
animatorClass = [[targetView class] animatorClass];
if (needsCSSAnimation)
{
[animatorClass addAnimations:cssAnimations forAction:anAction];
}
if (needsPeriodicFrameUpdates)
{
[animatorClass addFrameUpdaters:timers forAction:anAction];
}
var subviews = [targetView subviews],
count = [subviews count];
if (count && isFrameKeyPath)
{
[subviews enumerateObjectsUsingBlock:function(aSubview, idx, stop)
{
if (!declarative_subviews_layout && [aSubview autoresizingMask] == 0)
return;
var action = [self actionFromAction:anAction forAnimatedSubview:aSubview],
targetFrame = [action.values lastObject];
if (CGRectEqualToRect([aSubview frame], targetFrame))
return;
if ([aSubview hasCustomDrawRect])
{
action.completion = function()
{
[aSubview setFrame:targetFrame];
#if (DEBUG)
CPLog.debug(aSubview + " setFrame: " + CPStringFromRect(targetFrame));
#endif
if (idx == count - 1)
[animatorClass stopUpdaterWithIdentifier:[anAction.root UID]];
};
}
var animate = !needsPeriodicFrameUpdates;
[self getAnimations:cssAnimations getTimers:timers usingAction:action cssAnimate:animate];
}];
}
}
- (Object)actionFromAction:(Object)anAction forAnimatedSubview:(CPView)aView
{
var targetValue = [anAction.values lastObject],
startFrame = [aView frame],
endFrame,
values;
if (anAction.keypath == "frame")
targetValue = targetValue.size;
endFrame = [[aView superview] frameRectOfView:aView inSuperviewSize:targetValue];
values = [startFrame, endFrame];
return {
object:aView,
root:anAction.root,
keypath:"frame",
values:values,
keytimes:[0, 1],
duration:anAction.duration,
timingfunctions:anAction.timingfunctions
};
}
- (void)setCompletionHandler:(Function)aCompletionHandler
{
if (_completionHandlerAgent)
{
if (aCompletionHandler === _completionHandlerAgent._completionHandler)
return;
_completionHandlerAgent.invalidate();
}
if (aCompletionHandler)
{
_completionHandlerAgent = new CompletionHandlerAgent(aCompletionHandler);
#if (DEBUG)
CPLog.debug("created a new completion Agent with id " + _completionHandlerAgent.id);
#endif
}
else
{
_completionHandlerAgent = nil;
}
}
- (void)completionHandler
{
if (!_completionHandlerAgent)
return nil;
return _completionHandlerAgent.completionHandler();
}
@end
@implementation CPView (CPAnimationContext)
- (CGRect)frameRectOfView:(CPView)aView inSuperviewSize:(CGSize)aSize
{
return [aView frameWithNewSuperviewSize:aSize];
}
- (CGRect)frameWithNewSuperviewSize:(CGSize)newSize
{
var mask = [self autoresizingMask];
if (mask == CPViewNotSizable)
return _frame;
var oldSize = _superview._frame.size,
newFrame = CGRectMakeCopy(_frame),
dX = newSize.width - oldSize.width,
dY = newSize.height - oldSize.height,
evenFractionX = 1.0 / ((mask & CPViewMinXMargin ? 1 : 0) + (mask & CPViewWidthSizable ? 1 : 0) + (mask & CPViewMaxXMargin ? 1 : 0)),
evenFractionY = 1.0 / ((mask & CPViewMinYMargin ? 1 : 0) + (mask & CPViewHeightSizable ? 1 : 0) + (mask & CPViewMaxYMargin ? 1 : 0)),
baseX = (mask & CPViewMinXMargin ? _frame.origin.x : 0) +
(mask & CPViewWidthSizable ? _frame.size.width : 0) +
(mask & CPViewMaxXMargin ? oldSize.width - _frame.size.width - _frame.origin.x : 0),
baseY = (mask & CPViewMinYMargin ? _frame.origin.y : 0) +
(mask & CPViewHeightSizable ? _frame.size.height : 0) +
(mask & CPViewMaxYMargin ? oldSize.height - _frame.size.height - _frame.origin.y : 0);
if (mask & CPViewMinXMargin)
newFrame.origin.x += dX * (baseX > 0 ? _frame.origin.x / baseX : evenFractionX);
if (mask & CPViewWidthSizable)
newFrame.size.width += dX * (baseX > 0 ? _frame.size.width / baseX : evenFractionX);
if (mask & CPViewMinYMargin)
newFrame.origin.y += dY * (baseY > 0 ? _frame.origin.y / baseY : evenFractionY);
if (mask & CPViewHeightSizable)
newFrame.size.height += dY * (baseY > 0 ? _frame.size.height / baseY : evenFractionY);
return newFrame;
}
- (BOOL)hasCustomDrawRect
{
return self._viewClassFlags & 1;
}
- (BOOL)hasCustomLayoutSubviews
{
return self._viewClassFlags & 2;
}
@end
@implementation CAMediaTimingFunction (Additions)
- (CPArray)controlPoints
{
return [_c1x, _c1y, _c2x, _c2y];
}
@end
@implementation CAAnimation (Additions)
- (CPArray)timingFunctionControlPoints
{
if (_timingFunction)
return [_timingFunction controlPoints];
return [0, 0, 1, 1];
}
@end
@implementation CAKeyframeAnimation (Additions)
- (CPArray)timingFunctionsControlPoints
{
var result = [CPArray array];
[_timingFunctions enumerateObjectsUsingBlock:function(timingFunction, idx)
{
[result addObject:[timingFunction controlPoints]];
}];
return result;
}
@end
var COMPLETION_AGENT_ID = 0;
var CompletionHandlerAgent = function(aCompletionHandler)
{
this._completionHandler = aCompletionHandler;
this.total = 0;
this.valid = true;
this.id = COMPLETION_AGENT_ID++;
};
CompletionHandlerAgent.prototype.completionHandler = function()
{
return this._completionHandler;
};
CompletionHandlerAgent.prototype.fire = function()
{
if (this.valid)
{
this._completionHandler();
this.valid = false;
this.total = 0;
}
};
CompletionHandlerAgent.prototype.increment = function(inc)
{
this.total += inc;
};
CompletionHandlerAgent.prototype.decrement = function()
{
if (this.total <= 0)
return;
this.total--;
if (this.valid && this.total == 0)
{
this.fire();
}
};
CompletionHandlerAgent.prototype.invalidate = function()
{
this.valid = false;
this.total = 0;
this._completionHandler = null;
};
var _animationFlushingObserverCallback = function()
{
#if (DEBUG)
CPLog.debug("_animationFlushingObserverCallback");
#endif
if ([_CPAnimationContextStack count] == 1)
{
var context = [_CPAnimationContextStack lastObject];
[context _flushAnimations];
[_CPAnimationContextStack removeLastObject];
}
#if (DEBUG)
CPLog.debug("_animationFlushingObserver "+_animationFlushingObserver+" stack:" + [_CPAnimationContextStack count]);
#endif
if (_animationFlushingObserver && ![_CPAnimationContextStack count])
{
#if (DEBUG)
CPLog.debug("removeObserver");
#endif
CFRunLoopObserverInvalidate([CPRunLoop mainRunLoop], _animationFlushingObserver);
_animationFlushingObserver = nil;
}
};
+440
View File
@@ -0,0 +1,440 @@
@import "_CPObjectAnimator.j"
@import "CPView.j"
@import "CPCompatibility.j"
@import "CSSAnimation.j"
var DEFAULT_CSS_PROPERTIES = nil,
FRAME_UPDATERS = {};
@implementation CPViewAnimator : _CPObjectAnimator
{
BOOL _wantsPeriodicFrameUpdates @accessors(property=wantsPeriodicFrameUpdates);
}
- (id)initWithTarget:(id)aTarget
{
self = [super initWithTarget:aTarget];
_wantsPeriodicFrameUpdates = NO;
return self;
}
- (void)removeFromSuperview
{
[self _setTargetValue:nil withKeyPath:@"CPAnimationTriggerOrderOut" setter:_cmd];
}
- (void)setHidden:(BOOL)shouldHide
{
if ([_target isHidden] == shouldHide)
return;
if (shouldHide == NO)
return [_target setHidden:NO];
[self _setTargetValue:YES withKeyPath:@"CPAnimationTriggerOrderOut" setter:_cmd];
}
- (void)setAlphaValue:(CGPoint)alphaValue
{
[self _setTargetValue:alphaValue withKeyPath:@"alphaValue" setter:_cmd];
}
- (void)setBackgroundColor:(CPColor)aColor
{
[self _setTargetValue:aColor withKeyPath:@"backgroundColor" setter:_cmd];
}
- (void)setFrameOrigin:(CGPoint)aFrameOrigin
{
[self _setTargetValue:aFrameOrigin withKeyPath:@"frameOrigin" setter:_cmd];
}
- (void)setFrame:(CGRect)aFrame
{
[self _setTargetValue:aFrame withKeyPath:@"frame" setter:_cmd];
}
- (void)setFrameSize:(CGSize)aFrameSize
{
[self _setTargetValue:aFrameSize withKeyPath:@"frameSize" setter:_cmd];
}
// Convenience method for the common case where the setter has zero or one argument
- (void)_setTargetValue:(id)aTargetValue withKeyPath:(CPString)aKeyPath setter:(SEL)aSelector
{
var handler = function()
{
[_target _setForceUpdates:YES];
[_target performSelector:aSelector withObject:aTargetValue];
[_target _setForceUpdates:NO];
};
[self _setTargetValue:aTargetValue withKeyPath:aKeyPath fallback:handler completion:handler];
}
- (void)_setTargetValue:(id)aTargetValue withKeyPath:(CPString)aKeyPath fallback:(Function)fallback completion:(Function)completion
{
var animation = [_target animationForKey:aKeyPath],
context = [CPAnimationContext currentContext];
if (!animation || ![animation isKindOfClass:[CAAnimation class]] || (![context duration] && ![animation duration]) || !CPFeatureIsCompatible(CPCSSAnimationFeature))
{
if (fallback)
fallback();
}
else
{
[context _enqueueActionForObject:_target keyPath:aKeyPath targetValue:aTargetValue animationCompletion:completion];
}
}
+ (CPDictionary)_defaultCSSProperties
{
if (DEFAULT_CSS_PROPERTIES == nil)
{
var transformProperty = "transform";
DEFAULT_CSS_PROPERTIES = @{
"backgroundColor" : [@{"property":"background", "value":function(sv, val){return [val cssString];}}],
"alphaValue" : [@{"property":"opacity"}],
"frame" : [@{"property":transformProperty, "value":frameToCSSTranslationTransformMatrix},
@{"property":"width", "value":transformFrameToWidth},
@{"property":"height", "value":transformFrameToHeight}],
"frameOrigin" : [@{"property":transformProperty, "value":frameOriginToCSSTransformMatrix}],
"frameSize" : [@{"property":"width", "value":transformSizeToWidth},
@{"property":"height", "value":transformSizeToHeight}]
};
}
return DEFAULT_CSS_PROPERTIES;
}
+ (void)addAnimations:(CPArray)animations forAction:(id)anAction
{
var target = anAction.object;
return [self _addAnimations:animations forAction:anAction domElement:[target _DOMElement] identifier:[target UID]];
}
+ (void)_addAnimations:(CPArray)animations forAction:(id)anAction domElement:(Object)aDomElement identifier:(CPString)anIdentifier
{
var animation = [animations objectPassingTest:function(anim, idx, stop)
{
return anim.identifier == anIdentifier;
}];
if (animation == nil)
{
animation = new CSSAnimation(aDomElement, anIdentifier, [anAction.object debug_description]);
[animations addObject:animation];
}
var css_mapping = [self _cssPropertiesForKeyPath:anAction.keypath];
[css_mapping enumerateObjectsUsingBlock:function(aDict, anIndex, stop)
{
var completionFunction = (anIndex == 0) ? anAction.completion : null,
property = [aDict objectForKey:@"property"],
getter = [aDict objectForKey:@"value"];
animation.addPropertyAnimation(property, getter, anAction.duration, anAction.keytimes, anAction.values, anAction.timingfunctions, completionFunction);
}];
}
+ (CPArray)_cssPropertiesForKeyPath:(CPString)aKeyPath
{
return [[self _defaultCSSProperties] objectForKey:aKeyPath];
}
+ (void)addFrameUpdaters:(CPArray)frameUpdaters forAction:(id)anAction
{
var rootIdentifier = [anAction.root UID];
var frameUpdater = [frameUpdaters objectPassingTest:function(updater, idx, stop)
{
// There is one timer, linked to the top view, that updates the whole hierarchy.
return updater.identifier() == rootIdentifier;
}];
if (frameUpdater == nil)
{
frameUpdater = new FrameUpdater(rootIdentifier);
[frameUpdaters addObject:frameUpdater];
FRAME_UPDATERS[rootIdentifier] = frameUpdater;
}
frameUpdater.addTarget(anAction.object, anAction.keypath, anAction.duration);
}
+ (void)stopUpdaterWithIdentifier:(CPString)anIdentifier
{
var frameUpdater = FRAME_UPDATERS[anIdentifier];
if (frameUpdater)
{
frameUpdater.stop();
delete FRAME_UPDATERS[anIdentifier];
}
else
CPLog.warn("Could not find FrameUpdater with identifier " + anIdentifier);
}
- (BOOL)needsPeriodicFrameUpdatesForKeyPath:(CPString)aKeyPath
{
return ((aKeyPath == @"frame" || aKeyPath == @"frameSize") &&
(([_target hasCustomLayoutSubviews] && ![_target implementsSelector:@selector(frameRectOfView:inSuperviewSize:)])
|| [_target hasCustomDrawRect]))
|| [self wantsPeriodicFrameUpdates];
}
@end
var transformFrameToWidth = function(start, current)
{
return current.size.width + "px";
};
var transformFrameToHeight = function(start, current)
{
return current.size.height + "px";
};
var transformSizeToWidth = function(start, current)
{
return current.width + "px";
};
var transformSizeToHeight = function(start, current)
{
return current.height + "px";
};
var CSSStringFromCGAffineTransform = function(anAffineTransform)
{
return [CPString stringWithFormat:@"matrix(%d,%d,%d,%d,%d,%d)", anAffineTransform.a, anAffineTransform.b, anAffineTransform.c, anAffineTransform.d, anAffineTransform.tx, anAffineTransform.ty];
};
var frameOriginToCSSTransformMatrix = function(start, current)
{
var affine = CGAffineTransformMakeTranslation(current.x - start.x, current.y - start.y);
return CSSStringFromCGAffineTransform(affine);
};
var frameToCSSTranslationTransformMatrix = function(start, current)
{
var affine = CGAffineTransformMakeTranslation(current.origin.x - start.origin.x, current.origin.y - start.origin.y);
return CSSStringFromCGAffineTransform(affine);
};
@implementation CPView (CPAnimatablePropertyContainer)
+ (Class)animatorClass
{
var anim_class = CPClassFromString(CPStringFromClass(self) + "Animator");
if (anim_class)
return anim_class;
return [[self superclass] animatorClass];
}
- (id)animator
{
if (!_animator)
_animator = [[[[self class] animatorClass] alloc] initWithTarget:self];
return _animator;
}
+ (CAAnimation)defaultAnimationForKey:(CPString)aKey
{
// TODO: remove when supported.
if (aKey == @"CPAnimationTriggerOrderIn")
{
CPLog.warn("CPView animated key path CPAnimationTriggerOrderIn is not supported yet.");
return nil;
}
if ([[self animatorClass] _cssPropertiesForKeyPath:aKey] !== nil)
return [CAAnimation animation];
return nil;
}
- (CAAnimation)animationForKey:(CPString)aKey
{
var animations = [self animations],
animation = nil;
if (!animations || !(animation = [animations objectForKey:aKey]))
{
animation = [[self class] defaultAnimationForKey:aKey];
}
return animation;
}
- (CPDictionary)animations
{
return _animationsDictionary;
}
- (void)setAnimations:(CPDictionary)animationsDict
{
_animationsDictionary = [animationsDict copy];
}
- (Object)_DOMElement
{
return _DOMElement;
}
- (CPString)debug_description
{
return [self identifier] || [self className];
}
@end
@implementation CPArray (Additions)
- (CPArray)objectPassingTest:(Function)aFunction
{
var idx = [self indexOfObjectPassingTest:aFunction];
if (idx !== CPNotFound)
return [self objectAtIndex:idx];
return nil;
}
@end
var FrameUpdater = function(anIdentifier)
{
this._identifier = anIdentifier;
this._requestId = null;
this._duration = 0;
this._stop = false;
this._targets = [];
this._callbacks = [];
var frameUpdater = this;
this._updateFunction = function(timestamp)
{
if (frameUpdater._startDate == null)
frameUpdater._startDate = timestamp;
if (frameUpdater._stop)
return;
for (var i = 0; i < frameUpdater._callbacks.length; i++)
frameUpdater._callbacks[i]();
if (timestamp - frameUpdater._startDate < frameUpdater._duration * 1000)
window.requestAnimationFrame(frameUpdater._updateFunction);
};
};
FrameUpdater.prototype.start = function()
{
this._requestId = window.requestAnimationFrame(this._updateFunction);
};
FrameUpdater.prototype.stop = function()
{
CPLog.warn("STOP FrameUpdater" + this._identifier);
// window.cancelAnimationFrame support is Chrome 24, Firefox 23, IE 10, Opera 15, Safari 6.1
if (window.cancelAnimationFrame)
window.cancelAnimationFrame(this._requestId);
this._stop = true;
};
FrameUpdater.prototype.updateFunction = function()
{
return this._updateFunction;
};
FrameUpdater.prototype.identifier = function()
{
return this._identifier;
};
FrameUpdater.prototype.description = function()
{
return "<timer " + this._identifier + " " + this._targets.map(function(t){return [t debug_description];}) + ">";
};
FrameUpdater.prototype.addTarget = function(target, keyPath, duration)
{
var callback = createUpdateFrame(target, keyPath);
if (callback)
{
this._duration = MAX(this._duration, duration);
this._targets.push(target);
this._callbacks.push(callback);
}
};
var createUpdateFrame = function(aView, aKeyPath)
{
if (aKeyPath !== "frame" && aKeyPath !== "frameSize" && aKeyPath !== "frameOrigin")
return nil;
var style = getComputedStyle([aView _DOMElement]),
getCSSPropertyValue = function(prop) {
return ROUND(parseFloat(style.getPropertyValue(prop)));
},
initialOrigin = CGPointMakeCopy([aView frameOrigin]),
transformProperty = CPBrowserStyleProperty("transform"),
updateFrame = function(timestamp)
{
if (aKeyPath === "frameSize")
{
var width = getCSSPropertyValue("width"),
height = getCSSPropertyValue("height");
[aView setFrameSize:CGSizeMake(width, height)];
}
else
{
[aView _setInhibitDOMUpdates:YES];
var matrix_value = style[transformProperty];
if (matrix_value && matrix_value !== 'none')
{
var matrix_array = matrix_value.split('(')[1].split(')')[0].split(','),
x = ROUND(initialOrigin.x + parseFloat(matrix_array[4])),
y = ROUND(initialOrigin.y + parseFloat(matrix_array[5]));
if (aKeyPath === "frame")
{
var width = getCSSPropertyValue("width"),
height = getCSSPropertyValue("height");
[aView setFrame:CGRectMake(x, y, width, height)];
}
else
{
[aView setFrameOrigin:CGPointMake(x, y)];
}
}
[aView _setInhibitDOMUpdates:NO];
}
[[CPRunLoop currentRunLoop] performSelectors];
// CPLog.debug("update " + [aView debug_description]);
};
return updateFrame;
};
+308
View File
@@ -0,0 +1,308 @@
var ANIMATIONS_GLOBAL_ID = 0,
CURRENT_ANIMATIONS = {},
ANIMATION_END_EVENT_NAME,
ANIMATION_PROPERTY,
ANIMATION_NAME_PROPERTY,
ANIMATION_DURATION_PROPERTY,
ANIMATION_TIMING_FUNCTION_PROPERTY,
ANIMATION_FILL_MODE_PROPERTY,
ANIMATION_KEYFRAMES_RULE;
var defineCSSProperties = function()
{
if (this.done)
return;
ANIMATION_END_EVENT_NAME = CPBrowserStyleProperty("animationend");
ANIMATION_PROPERTY = CPBrowserCSSProperty("animation");
ANIMATION_NAME_PROPERTY = CPBrowserCSSProperty("animation-name");
ANIMATION_DURATION_PROPERTY = CPBrowserCSSProperty("animation-duration");
ANIMATION_TIMING_FUNCTION_PROPERTY = CPBrowserCSSProperty("animation-timing-function");
ANIMATION_FILL_MODE_PROPERTY = CPBrowserCSSProperty("animation-fill-mode");
ANIMATION_KEYFRAMES_RULE = "@" + ANIMATION_PROPERTY.substring(0, ANIMATION_PROPERTY.indexOf("animation")) + "keyframes";
this.done = true;
};
var removeFromParent = function(aNode)
{
var parentNode = aNode.parentNode;
if (parentNode)
parentNode.removeChild(aNode);
};
CSSAnimation = function(aTarget/* DOM Element */, anIdentifier, aTargetName)
{
defineCSSProperties();
if (!anIdentifier)
anIdentifier = ANIMATIONS_GLOBAL_ID++;
var animationName = "anim_" + anIdentifier,
animation = CURRENT_ANIMATIONS[anIdentifier];
if (animation)
{
console.warn("Animation " + anIdentifier + " is already in use. Ignoring.");
}
else
{
this.target = aTarget;
this.identifier = anIdentifier;
this.targetName = aTargetName;
this.animationName = animationName;
this.listener = null;
this.styleElement = null;
this.propertyanimations = [];
this.animationsnames = [];
this.animationstimingfunctions = [];
this.animationsdurations = [];
this.islive = false;
this.didBuildDOMElements = false;
animation = this;
CURRENT_ANIMATIONS[anIdentifier] = animation;
}
return animation;
};
CSSAnimation.prototype.description = function()
{
return "<animation " + this.identifier + " target=" + this.targetName + " properties=" + this.propertyanimations.map(function(anim){return anim.property;}).join(",") + " >";
}
CSSAnimation.prototype.addPropertyAnimation = function(propertyName/* String */, valueFunction/* Function */, aDuration/* float */, aKeyTimes/* (d, [d]) */, aValues/* Array */, aTimingFunctions/* [d,d,d,d], [[d,d,d,d]] */, aCompletionfunction/* Function */)
{
if (this.islive)
return false;
// TODO: If a property already exist, replace its values & valueFunctions.
var fullAnimationName = this.animationName + "_" + propertyName;
var animation = {
name: fullAnimationName,
property: propertyName,
valuefunction: valueFunction,
keytimes: aKeyTimes,
values: aValues,
duration: aDuration,
completionfunction: aCompletionfunction };
var animationTimingFunction;
if (aTimingFunctions && (aTimingFunctions[0] instanceof Array))
{
animation.keyframestimingFunctions = aTimingFunctions;
// dummy timing function overriden by keyframes timings functions
animationTimingFunction = "linear";
}
else
{
animationTimingFunction = "cubic-bezier(" + aTimingFunctions + ")";
}
this.animationstimingfunctions.push(animationTimingFunction);
this.propertyanimations.push(animation);
this.animationsnames.push(fullAnimationName);
this.animationsdurations.push(aDuration + "s");
return true;
};
CSSAnimation.prototype.keyFrames = function()
{
var keyframesRules = [];
var count = this.propertyanimations.length;
for (var i = 0; i < count; i++)
{
var animation = this.propertyanimations[i],
property = animation.property,
valuefunction = animation.valuefunction,
keytimes = animation.keytimes,
values = animation.values,
timingFunctions = animation.keyframestimingFunctions;
var keyframes = [],
keytimescount = keytimes.length,
start_value = values[0];
for (var j = 0; j < keytimescount; j++)
{
var keytime = keytimes[j],
value = values[j],
timingFunction;
if (valuefunction !== null)
value = valuefunction(start_value, value);
var keyframeContent = property + ": " + value + ";";
if (timingFunctions && timingFunctions.length && (timingFunction = timingFunctions[j]))
{
keyframeContent += ANIMATION_TIMING_FUNCTION_PROPERTY + ":cubic-bezier(" + timingFunction + ");";
}
var keyframe = "\t" + Math.round(keytime * 100) + "% {\n\t\t" + keyframeContent + "\n\t}\n";
keyframes.push(keyframe);
}
// TODO ! Add keyframe rule to CPCompatibility
var rule = ANIMATION_KEYFRAMES_RULE + " " + animation.name + " {\n" + keyframes.join(" ") + "}\n";
keyframesRules.push(rule);
}
return keyframesRules.join("\n");
};
CSSAnimation.prototype.appendKeyFramesRule = function()
{
var styleElement = this.createKeyFramesStyleElement(),
keyframesText = this.keyFrames(),
nodeText = document.createTextNode(keyframesText);
styleElement.appendChild(nodeText);
document.head.appendChild(styleElement);
};
CSSAnimation.prototype.createKeyFramesStyleElement = function()
{
if (!this.styleElement)
{
var styleElement = document.createElement("style");
styleElement.setAttribute("type", "text/css");
this.styleElement = styleElement;
}
return this.styleElement;
};
CSSAnimation.prototype.endEventListener = function()
{
var animation = this,
animationsNames = this.animationsnames,
inFlightAnimationsNames = animationsNames.slice();
if (!animation.listener)
{
var AnimationEndListener = function(event)
{
var idx = inFlightAnimationsNames.indexOf(event.animationName);
if (idx !== -1)
inFlightAnimationsNames.splice(idx, 1);
if (inFlightAnimationsNames.length > 0)
return;
for (var i = 0; i < animationsNames.length; i++)
{
var completion = animation.completionFunctionForAnimationName(animationsNames[i]);
if (completion)
completion();
}
var eventTarget = event.target,
style = eventTarget.style;
try
{
style.removeProperty(ANIMATION_NAME_PROPERTY);
style.removeProperty(ANIMATION_DURATION_PROPERTY);
style.removeProperty(ANIMATION_FILL_MODE_PROPERTY);
style.removeProperty("-webkit-backface-visibility");
if (animation.animationstimingfunctions.length)
style.removeProperty(ANIMATION_TIMING_FUNCTION_PROPERTY);
removeFromParent(animation.styleElement);
eventTarget.removeEventListener(ANIMATION_END_EVENT_NAME, AnimationEndListener);
animation.listener = null;
delete (CURRENT_ANIMATIONS[animation.identifier]);
}
catch (err)
{
console.warn("CSSAnimation.j - " + err);
}
};
this.listener = AnimationEndListener;
}
return this.listener;
};
CSSAnimation.prototype.completionFunctionForAnimationName = function(aName)
{
var propanims = this.propertyanimations,
count = propanims.length;
while (count--)
{
var anim = propanims[count];
if (anim.name === aName)
return anim.completionfunction;
}
return null;
};
CSSAnimation.prototype.addAnimationEndEventListener = function()
{
var listener = this.endEventListener();
this.target.addEventListener(ANIMATION_END_EVENT_NAME, listener, false);
};
CSSAnimation.prototype.setTargetStyleProperties = function()
{
var style = this.target.style;
if (this.animationstimingfunctions.length)
style.setProperty(ANIMATION_TIMING_FUNCTION_PROPERTY, this.animationstimingfunctions.join(","));
style.setProperty(ANIMATION_DURATION_PROPERTY, this.animationsdurations.join(","));
style.setProperty(ANIMATION_FILL_MODE_PROPERTY, "forwards");
// http://webdesign.tutsplus.com/tutorials/htmlcss-tutorials/css3-animations-the-hiccups-and-bugs-youll-want-to-avoid/
style.setProperty("-webkit-backface-visibility", "hidden");
};
CSSAnimation.prototype.buildDOMElements = function()
{
this.appendKeyFramesRule();
this.addAnimationEndEventListener();
this.setTargetStyleProperties();
this.didBuildDOMElements = true;
};
CSSAnimation.prototype.start = function()
{
if (this.propertyanimations.length === 0 || this.islive)
return false;
if (!this.didBuildDOMElements)
this.buildDOMElements();
this.target.style.setProperty(ANIMATION_NAME_PROPERTY, this.animationsnames.join(","));
this.islive = true;
return true;
};
+92
View File
@@ -0,0 +1,92 @@
@import <Foundation/CPProxy.j>
@import "CPAnimationContext.j"
var _supportsCSSAnimations = null;
@protocol CPAnimatablePropertyContainer <CPObject>
+ (id)defaultAnimationForKey:(CPString)key;
- (id)animationForKey:(CPString)key;
- (id)animator;
- (CPDictionary)animations;
- (void)setAnimations:(CPDictionary)animations;
@end
@implementation _CPObjectAnimator : CPProxy
{
id <CPAnimatablePropertyContainer> _target;
}
+ (void)initialize
{
if ([self class] !== [_CPObjectAnimator class])
return;
var compat = (CPBrowserCSSProperty("animation") !== nil);
CPSetPlatformFeature(CPCSSAnimationFeature, compat);
}
- (id)initWithTarget:(id)aTarget
{
_target = aTarget;
return self;
}
- (id)animator
{
return self;
}
- (BOOL)isEqual:(id)anObject
{
return [_target isEqual:anObject];
}
- (id)forwardingTargetForSelector:(SEL)aSelector
{
return _target;
}
- (CPMethodSignature)methodSignatureForSelector:(SEL)aSelector
{
return [_target methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(CPInvocation)anInvocation
{
var target = [self forwardingTargetForSelector:[anInvocation selector]];
[anInvocation invokeWithTarget:target];
return;
}
- (void)doesNotRecognizeSelector:(SEL)aSelector
{
[CPException raise:CPInvalidArgumentException reason:@"Animator does not recognize selector " + CPStringFromSelector(aSelector)];
}
- (CPString)description
{
return [CPString stringWithFormat:@"%@ Animator Proxy for %@", [self class], _target];
}
- (void)setValue:(id)aTargetValue forKey:(id)aKeyPath
{
var animation = [_target animationForKey:aKeyPath],
context = [CPAnimationContext currentContext];
if (!animation || ![animation isKindOfClass:[CAAnimation class]] || (![context duration] && ![animation duration]) || !CPFeatureIsCompatible(CPCSSAnimationFeature))
[_target setValue:aTargetValue forKey:aKeyPath];
else
{
[context _enqueueActionForObject:_target keyPath:aKeyPath targetValue:aTargetValue animationCompletion:function()
{
[_target setValue:aTargetValue forKey:aKeyPath];
}];
}
}
@end
+1
View File
@@ -24,6 +24,7 @@
@import "CPCompatibility.j"
@import "CGGeometry.j"
@import "CGPath.j"
@import "CGContextText.j"
@typedef CGContext
+2 -2
View File
@@ -557,14 +557,14 @@ CGContextConcatCTM = function(aContext, anAffineTransform)
b = VT.b;
c = VT.c;
d = VT.d;
scale_rotate(a, b, c, d)
scale_rotate(a, b, c, d);
S.a *= sx;
S.d *= sy;
a = U.a;
b = U.b;
c = U.c;
d = U.d;
rotate_scale(a, b, c, d)
rotate_scale(a, b, c, d);
sx = S.a * sx;
sy = S.d * sy;
}
+86
View File
@@ -0,0 +1,86 @@
/*
* 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);
}
+1 -1
View File
@@ -242,7 +242,7 @@ function CGContextDrawPath(aContext, aMode)
vml.push("\">");
if (gState.gradient)
vml.push(gState.gradient)
vml.push(gState.gradient);
else if (fill)
{
+1 -4
View File
@@ -132,9 +132,6 @@ function CGPathAddArc(aPath, aTransform, x, y, aRadius, aStartAngle, anEndAngle,
}
else
{
var arcStartX = x + aRadius * COS(aStartAngle),
arcStartY = y + aRadius * SIN(aStartAngle);
aPath.start = CGPointMake(arcStartX, arcStartY);
}
@@ -274,7 +271,7 @@ function CGPathAddQuadCurveToPoint(aPath, aTransform, cpx, cpy, x, y)
end = CGPointApplyAffineTransform(end, aTransform);
}
aPath.elements[aPath.count++] = { type:kCGPathElementAddQuadCurveToPoint, cpx:cp.x, cpy:cp.y, x:end.x, y:end.y }
aPath.elements[aPath.count++] = { type:kCGPathElementAddQuadCurveToPoint, cpx:cp.x, cpy:cp.y, x:end.x, y:end.y };
aPath.current = end;
}
+1 -1
View File
@@ -37,7 +37,7 @@ appKitTask = framework ("AppKit", function(appKitTask)
appKitTask.setCompilerFlags("-O2 " + INCLUDES);
}
else
appKitTask.setCompilerFlags("-DDEBUG -g " + INCLUDES);
appKitTask.setCompilerFlags("-DDEBUG -g -S --inline-msg-send " + INCLUDES);
});
$BUILD_CJS_CAPPUCCINO_APPKIT = FILE.join($BUILD_CJS_CAPPUCCINO_FRAMEWORKS, "AppKit");
+1 -23
View File
@@ -60,6 +60,7 @@ var PrimaryPlatformWindow = NULL;
BOOL _mouseIsDown;
BOOL _mouseDownIsRightClick;
int _firstMouseDownButton;
CGPoint _lastMouseEventLocation;
CPWindow _mouseDownWindow;
CPTimeInterval _lastMouseUp;
@@ -223,18 +224,10 @@ var PrimaryPlatformWindow = NULL;
- (void)deminiaturize:(id)sender
{
#if PLATFORM(DOM)
if (_DOMWindow && typeof _DOMWindow["cpDeminiaturize"] === "function")
_DOMWindow.cpDeminiaturize();
#endif
}
- (void)miniaturize:(id)sender
{
#if PLATFORM(DOM)
if (_DOMWindow && typeof _DOMWindow["cpMiniaturize"] === "function")
_DOMWindow.cpMiniaturize();
#endif
}
- (void)moveWindow:(CPWindow)aWindow fromLevel:(int)fromLevel toLevel:(int)toLevel
@@ -254,31 +247,16 @@ var PrimaryPlatformWindow = NULL;
- (void)setLevel:(CPInteger)aLevel
{
_level = aLevel;
#if PLATFORM(DOM)
if (_DOMWindow && _DOMWindow.cpSetLevel)
_DOMWindow.cpSetLevel(aLevel);
#endif
}
- (void)setHasShadow:(BOOL)shouldHaveShadow
{
_hasShadow = shouldHaveShadow;
#if PLATFORM(DOM)
if (_DOMWindow && _DOMWindow.cpSetHasShadow)
_DOMWindow.cpSetHasShadow(shouldHaveShadow);
#endif
}
- (void)setShadowStyle:(int)aStyle
{
_shadowStyle = aStyle;
#if PLATFORM(DOM)
if (_DOMWindow && _DOMWindow.cpSetShadowStyle)
_shadowStyle.cpSetShadowStyle(aStyle);
#endif
}
- (BOOL)supportsFullPlatformWindows
+8 -6
View File
@@ -384,9 +384,10 @@ Return true if the event may be a copy and paste event, but the target is not an
if ([value length])
{
var pasteboard = [CPPasteboard generalPasteboard];
var pasteboard = [CPPasteboard generalPasteboard],
cappString = [pasteboard stringForType:CPStringPboardType];
if ([pasteboard _stateUID] != value)
if (cappString != value)
{
[pasteboard declareTypes:[CPStringPboardType] owner:self];
[pasteboard setString:value forType:CPStringPboardType];
@@ -450,9 +451,10 @@ Return true if the event may be a copy and paste event, but the target is not an
if ([value length])
{
var pasteboard = [CPPasteboard generalPasteboard];
var pasteboard = [CPPasteboard generalPasteboard],
cappString = [pasteboard stringForType:CPStringPboardType];
if ([pasteboard _stateUID] != value)
if (cappString != value)
{
[pasteboard declareTypes:[CPStringPboardType] owner:self];
[pasteboard setString:value forType:CPStringPboardType];
@@ -467,7 +469,7 @@ Return true if the event may be a copy and paste event, but the target is not an
// By default we'll stop the native handling of the event since we're handling it ourselves. However, we need to
// stop it before we send the event so that the event can overrule our choice. CPTextField for instance wants the
// default handling when focused (which is to insert into the field).
[platformWindow _propagateCurrentDOMEvent:NO]
[platformWindow _propagateCurrentDOMEvent:NO];
[CPApp sendEvent:anEvent];
@@ -490,7 +492,7 @@ Return true if the event may be a copy and paste event, but the target is not an
SUPPRESS_CAPPUCCINO_CUT_FOR_EVENT(anEvent);
[platformWindow _propagateCurrentDOMEvent:NO]
[platformWindow _propagateCurrentDOMEvent:NO];
// Let the app react through copy: and cut: actions.
[CPApp sendEvent:anEvent];
+3 -1
View File
@@ -171,7 +171,9 @@ var DOMFixedWidthSpanElement = nil,
span.style.width = ROUND(aWidth) + "px";
}
span.style.font = [(aFont || DefaultFont) cssString];
var effectiveFontCSSString = [(aFont || DefaultFont) cssString];
if (span.style.font !== effectiveFontCSSString)
span.style.font = effectiveFontCSSString;
if (CPFeatureIsCompatible(CPJavaScriptInnerTextFeature))
span.innerText = aString;
+74 -48
View File
@@ -205,6 +205,9 @@ var resizeTimer = nil;
var PreventScroll = true;
var blurTimer = nil;
var touchStartingPointX,
touchStartingPointY;
_CPPlatformWindowWillCloseNotification = @"_CPPlatformWindowWillCloseNotification";
@@ -244,9 +247,6 @@ _CPPlatformWindowWillCloseNotification = @"_CPPlatformWindowWillCloseNotificatio
if (!_DOMWindow)
return [self contentRect];
if (_DOMWindow.cpFrame)
return _DOMWindow.cpFrame();
var contentRect = CGRectMakeZero();
if (window.screenTop)
@@ -275,9 +275,6 @@ _CPPlatformWindowWillCloseNotification = @"_CPPlatformWindowWillCloseNotificatio
if (!_DOMWindow)
return;
if (typeof _DOMWindow["cpSetFrame"] === "function")
return _DOMWindow.cpSetFrame([self contentRect]);
var origin = [self contentRect].origin,
nativeOrigin = [self nativeContentRect].origin;
@@ -573,22 +570,12 @@ _CPPlatformWindowWillCloseNotification = @"_CPPlatformWindowWillCloseNotificatio
[PlatformWindows addObject:self];
// FIXME: cpSetFrame?
_DOMWindow.document.write('<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"></head><body style="background-color:transparent; overflow:hidden"></body></html>');
_DOMWindow.document.close();
if (self != [CPPlatformWindow primaryPlatformWindow])
_DOMWindow.document.title = _title;
if (![CPPlatform isBrowser])
{
_DOMWindow.cpWindowNumber = [self._only windowNumber];
_DOMWindow.cpSetFrame(_contentRect);
_DOMWindow.cpSetLevel(_level);
_DOMWindow.cpSetHasShadow(_hasShadow);
_DOMWindow.cpSetShadowStyle(_shadowStyle);
}
[self registerDOMWindow];
_DOMBodyElement.style.cursor = [[CPCursor currentCursor] _cssString];
@@ -666,7 +653,8 @@ _CPPlatformWindowWillCloseNotification = @"_CPPlatformWindowWillCloseNotificatio
}
else if (type === "dragend")
{
var dropEffect = aDOMEvent.dataTransfer.dropEffect;
var dropEffect = aDOMEvent.dataTransfer.dropEffect,
dragOperation;
if (dropEffect === "move")
dragOperation = CPDragOperationMove;
@@ -944,16 +932,15 @@ _CPPlatformWindowWillCloseNotification = @"_CPPlatformWindowWillCloseNotificatio
if (!theWindow)
return;
var windowNumber = [theWindow windowNumber];
windowNumber = [theWindow windowNumber];
location = [theWindow convertBridgeToBase:location];
var event = [CPEvent mouseEventWithType:CPScrollWheel location:location modifierFlags:modifierFlags
timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:-1 clickCount:1 pressure:0];
event._DOMEvent = aDOMEvent;
// We lag 1 event behind without this timeout.
setTimeout(function()
// We lag 1 event behind without this approach
window.requestAnimationFrame(function()
{
if (aDOMEvent.deltaMode !== undefined && aDOMEvent.deltaMode !== 0)
{
@@ -992,10 +979,10 @@ _CPPlatformWindowWillCloseNotification = @"_CPPlatformWindowWillCloseNotificatio
_DOMScrollingElement.scrollLeft = 150;
_DOMScrollingElement.scrollTop = 150;
// Is this needed?
//[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
// this is needed to prevent flickering during scrolling
[[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
}, 0);
});
// We hide the dom element after a little bit
// so that other DOM elements such as inputs
@@ -1152,10 +1139,26 @@ _CPPlatformWindowWillCloseNotification = @"_CPPlatformWindowWillCloseNotificatio
- (void)touchEvent:(DOMEvent)aDOMEvent
{
var newEvent = {},
touch = aDOMEvent.touches.length ? aDOMEvent.touches[0] : aDOMEvent.changedTouches[0];
newEvent.timestamp = [CPEvent currentTimestamp];
newEvent.target = aDOMEvent.target;
newEvent.shiftKey = newEvent.ctrlKey = newEvent.altKey = newEvent.metaKey = false;
newEvent.clientX = touch.clientX;
/*
Normally the document can't scroll in Cappuccino: our body element has top:0 and bottom:0 with absolute positioning. So it should always be exactly the height of the viewport. The below handles a special case. iOS scrolls the document when the virtual keyboard is present and it needs to move a text input upwards visually to avoid covering the input with the keyboard. For most purposes we can ignore this, except here. In theory I think we could always apply this (scrollTop should always be 0 on every other device and situation) but let's be defensive and only apply it for touch events to minimise the risk of surprises.
*/
newEvent.clientY = _DOMWindow.document.body.scrollTop + touch.clientY;
newEvent.preventDefault = function() { if (aDOMEvent.preventDefault) aDOMEvent.preventDefault() };
newEvent.stopPropagation = function() { if (aDOMEvent.stopPropagation) aDOMEvent.stopPropagation() };
// single finger event-> simulate a simple mouse-click
if (aDOMEvent.touches && (aDOMEvent.touches.length == 1 || (aDOMEvent.touches.length == 0 && aDOMEvent.changedTouches.length == 1)))
{
var newEvent = {};
switch (aDOMEvent.type)
{
case CPDOMEventTouchStart: newEvent.type = CPDOMEventMouseDown;
@@ -1168,32 +1171,42 @@ _CPPlatformWindowWillCloseNotification = @"_CPPlatformWindowWillCloseNotificatio
break;
}
var touch = aDOMEvent.touches.length ? aDOMEvent.touches[0] : aDOMEvent.changedTouches[0];
newEvent.clientX = touch.clientX;
newEvent.clientY = touch.clientY;
newEvent.timestamp = [CPEvent currentTimestamp];
newEvent.target = aDOMEvent.target;
newEvent.shiftKey = newEvent.ctrlKey = newEvent.altKey = newEvent.metaKey = false;
newEvent.preventDefault = function() { if (aDOMEvent.preventDefault) aDOMEvent.preventDefault() };
newEvent.stopPropagation = function() { if (aDOMEvent.stopPropagation) aDOMEvent.stopPropagation() };
[self mouseEvent:newEvent];
return;
}
else
{
// two fingers->simulate scrolling events
if (aDOMEvent.touches && aDOMEvent.touches.length == 2)
{
switch (aDOMEvent.type)
{
case CPDOMEventTouchStart:
touchStartingPointX = touch.pageX;
touchStartingPointY = touch.pageY;
break;
case CPDOMEventTouchMove:
newEvent._hasPreciseScrollingDeltas = YES;
newEvent.deltaX = touchStartingPointX - touch.pageX;
newEvent.deltaY = touchStartingPointY - touch.pageY;
newEvent.type = CPDOMEventScrollWheel;
[self scrollEvent:newEvent];
touchStartingPointX = touch.pageX;
touchStartingPointY = touch.pageY;
return;
}
}
// handle other touch cases specifically
if (aDOMEvent.preventDefault)
aDOMEvent.preventDefault();
if (aDOMEvent.stopPropagation)
aDOMEvent.stopPropagation();
}
// handle touch cases specifically
}
- (void)mouseEvent:(DOMEvent)aDOMEvent
@@ -1245,12 +1258,16 @@ _CPPlatformWindowWillCloseNotification = @"_CPPlatformWindowWillCloseNotificatio
{
if (_mouseIsDown)
{
if (aDOMEvent.button !== _firstMouseDownButton)
return;
event = _CPEventFromNativeMouseEvent(aDOMEvent, _mouseDownIsRightClick ? CPRightMouseUp : CPLeftMouseUp, location, modifierFlags, timestamp, windowNumber, nil, -1, CPDOMEventGetClickCount(_lastMouseUp, timestamp, location), 0, nil);
_mouseIsDown = NO;
_lastMouseUp = event;
_mouseDownWindow = nil;
_mouseDownIsRightClick = NO;
_firstMouseDownButton = -1;
}
if (_DOMEventMode)
@@ -1270,6 +1287,16 @@ _CPPlatformWindowWillCloseNotification = @"_CPPlatformWindowWillCloseNotificatio
_mouseDownIsRightClick = button == 2 || (CPBrowserIsOperatingSystem(CPMacOperatingSystem) && button == 0 && modifierFlags & CPControlKeyMask);
// If mouse is already down, that means that a second mouse button is pushed. This could interfere in mouse events treatment. Just ignore it.
// BUT we have to track which button will be first released.
if (_mouseIsDown)
{
_mouseDownIsRightClick = !_mouseDownIsRightClick;
return;
}
_firstMouseDownButton = button;
if ((sourceElement.tagName === "INPUT" || sourceElement.tagName === "TEXTAREA") && sourceElement != _DOMFocusElement)
{
if ([CPPlatform supportsDragAndDrop])
@@ -1404,7 +1431,7 @@ _CPPlatformWindowWillCloseNotification = @"_CPPlatformWindowWillCloseNotificatio
var insertionIndex = 0;
if (middle !== undefined)
insertionIndex = _windowLevels[middle] > aLevel ? middle : middle + 1
insertionIndex = _windowLevels[middle] > aLevel ? middle : middle + 1;
[_windowLevels insertObject:aLevel atIndex:insertionIndex];
layer._DOMElement.style.zIndex = aLevel + 1; // adding one avoids negative zIndices. These have been causing issues in Chrome
@@ -1803,7 +1830,7 @@ var _CPEventFromNativeMouseEvent = function(aNativeEvent, anEventType, aPoint, m
var CLICK_SPACE_DELTA = 5.0,
CLICK_TIME_DELTA = (typeof document != "undefined" && document.addEventListener) ? 0.55 : 1.0;
var CPDOMEventGetClickCount = function(aComparisonEvent, aTimestamp, aLocation)
CPDOMEventGetClickCount = function(aComparisonEvent, aTimestamp, aLocation)
{
if (!aComparisonEvent)
return 1;
@@ -1857,11 +1884,10 @@ function CPWindowObjectList()
function CPWindowList()
{
var windowObjectList = CPWindowObjectList(),
windowList = [];
var windowObjectList = CPWindowObjectList();
for (var i = 0, count = [windowObjectList count]; i < count; i++)
windowList.push([windowObjectList[i] windowNumber]);
return windowList;
return [windowObjectList arrayByApplyingBlock:function(windowObject)
{
return [windowObject windowNumber];
}];
}
+5 -2
View File
@@ -389,8 +389,11 @@ var themedButtonValues = nil,
var color = [CPColor blackColor],
themedColorValues =
[
[@"alternate-selected-control-color", [[CPColor alloc] _initWithRGBA:[0.22, 0.46, 0.84, 1.0]]],
[@"secondary-selected-control-color", [[CPColor alloc] _initWithRGBA:[0.83, 0.83, 0.83, 1.0]]]
[@"alternate-selected-control-color", [[CPColor alloc] _initWithRGBA:[0.22, 0.46, 0.84, 1.0]]],
[@"secondary-selected-control-color", [[CPColor alloc] _initWithRGBA:[0.83, 0.83, 0.83, 1.0]]],
[@"selected-text-background-color", [CPColor colorWithHexString:"99CCFF"]],
[@"selected-text-inactive-background-color", [CPColor colorWithHexString:"CCCCCC"]]
];
[self registerThemeValues:themedColorValues forObject:color];
Binary file not shown.

Before

Width:  |  Height:  |  Size: 317 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 422 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 409 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 333 B

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